[
  {
    "path": ".gitignore",
    "content": "*html/*\n*xcuserdata*\n*xccheckout*\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2017 John Holdsworth\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Refactorator II, The App\n\nDue to chnages in the index databaase format in Xcode 10, this program no longer works properly.\n\nThis is the source for the App version of the [Refactorator plugin](https://github.com/johnno1962/Refactorator)\nfor refactoring Swift (well, renaming actually.)\n\nOne of the features of app is it can convert a project into a standalone website of navigable code for\nexample [this project](http://johnholdsworth.com/refactorator).\n\nTo build, clone this *and the code for the Refactorator plugin* next to each other the build this project.\nHelp is available [here](http://johnholdsworth.com/refactorator.html) where you can download a [pre-built\nbinary](http://johnholdsworth.com/Refactorator.app.zip).\n\n![Icon](http://johnholdsworth.com/refactorator2.gif)\n\nThe project now draws interactive dependecncy graphs between sources in a project if you have Graphviz installed.\n\n![Icon](http://johnholdsworth.com/depends.png)\n\nRefactorator now takes into account membership of protocols and overrides in the main target\nif you augment the index db by using the \"File/Index Protocols\" menu item.\n\nThis project is an experiment in \"Beerware\" there is a \"donate\" button on the Help Menu ;)\n\n## MIT Licensed\n\nCopyright (C) 2016 John Holdsworth refactorator@johnholdsworth.com [@Injection4Xcode](https://twitter.com/@Injection4Xcode)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \ndocumentation files (the \"Software\"), to deal in the Software without restriction, including without limitation \nthe rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, \nand to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial \nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE \nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nThis release includes the canviz, path amd prototype JavaScript libraries which are distributed under the terms of their respective licenses.\n\n"
  },
  {
    "path": "Refactorator/AppController.swift",
    "content": "//\n//  AppState.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 13/12/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\nimport Foundation\nimport WebKit\n\nclass AppController: NSObject, AppGui, WebUIDelegate, WebFrameLoadDelegate, WebPolicyDelegate {\n\n    @IBOutlet weak var window: NSWindow!\n\n    @IBOutlet weak var sourceView: WebView!\n    @IBOutlet weak var changesView: WebView!\n    weak var printWebView: WebView!\n\n    let canvizEntity = Entity(file: \"[Dependencies]\")\n    var canvizView: WebView!\n\n    @IBOutlet weak var replacement: NSTextField!\n    @IBOutlet weak var findText: NSTextField!\n\n    @IBOutlet var backItem: NSMenuItem!\n    @IBOutlet var forwardItem: NSMenuItem!\n    @IBOutlet var reloadItem: NSMenuItem!\n    @IBOutlet var dependsItem: NSMenuItem!\n    @IBOutlet var searchItem: NSMenuItem!\n\n    var history = [Entity]()\n    var future = [Entity]()\n    var project: Project?\n\n    var html = \"\", oldValue = \"\", changes = \"\"\n    var wasSearch = false\n\n    var entitiesByFile = [[Entity]]()\n    var originals = [String:NSData]()\n    var modified = [String:NSData]()\n    var linecounts = [String:Int]()\n\n    var formatter = Formatter()\n\n    func log( _ msg: String ) {\n        appendSource(title: \"\", text: \"<div class=log>\\(msg)</div>\")\n        Swift.print( msg )\n    }\n\n    func error( _ msg: String ) {\n        window.title = msg\n        log( \"<div class=error>\\(msg)</div>\" )\n    }\n\n    func open( url: String ) {\n        NSWorkspace.shared().open(url.url)\n    }\n    \n    func sourceHTML() -> String {\n        let path = Bundle.main.path(forResource: \"Source\", ofType: \"html\")!\n        return try! String(contentsOfFile: path, encoding:.utf8)\n    }\n\n    func defaultEntity() -> Entity {\n        if let recentSource = NSDocumentController.shared().recentDocumentURLs.first {\n            let entity = Entity(file: recentSource.path)\n            project = Project(target: entity)\n            return entity\n        }\n        return Entity(file: Bundle.main.path(forResource: \"Intro\", ofType: \"html\")!)\n    }\n\n    @discardableResult\n    func setupChanges() -> String {\n        let code = sourceHTML()\n        if changesView.uiDelegate == nil {\n            changesView.uiDelegate = self\n            changesView.frameLoadDelegate = self\n            changesView.mainFrame.loadHTMLString(code+\"<div>Click on a symbol to locate references to rename</div>\", baseURL: nil)\n            changesView.policyDelegate = self\n            RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.1))\n            changesView.windowScriptObject.setValue(self, forKey:\"appController2\")\n        }\n        return code\n    }\n\n    func setup( target: Entity? = nil, cascade: Bool = true ) {\n        let code = setupChanges()\n\n        NSApp.activate(ignoringOtherApps: true)\n        window.makeKeyAndOrderFront(nil)\n\n        if target != canvizEntity {\n            project = Project(target: target)\n            canvizView?.removeFromSuperview()\n        }\n        else {\n            if canvizView == nil {\n                canvizView = WebView(frame: sourceView.frame)\n                canvizView.autoresizingMask = sourceView.autoresizingMask\n                canvizView.frameLoadDelegate = self\n                canvizView.uiDelegate = self\n                let path = Bundle.main.path(forResource: \"canviz\", ofType: \"html\")!\n                canvizView.mainFrame.load( URLRequest( url: path.url ) )\n            }\n            else {\n                canvizView.frame = sourceView.frame\n            }\n            sourceView.superview?.addSubview(canvizView)\n            history.append( canvizEntity )\n            return\n        }\n\n        let target = target ?? project?.entity ?? defaultEntity()\n\n        if printWebView == nil {\n            printWebView = sourceView\n        }\n        setLocation(entity: target)\n        future.removeAll()\n\n        if let sourceData = NSData(contentsOfFile: target.file) {\n            if target.sourceName == \"Intro.html\" {\n                html = String(data:sourceData as Data, encoding:.utf8)!\n            }\n            else {\n                let entities = project?.indexDB?.entitiesFor(filePath: target.file)\n                let coverage = project != nil ? Coverage(file: target.file, project: project!)?.covered : nil\n                html = formatter.htmlFor(path: target.file, data: sourceData, entities: entities,\n                                         selecting: target, cascade: cascade, cleanPath: relative(target.file),\n                                         coverage: coverage).joined()\n            }\n\n            if sourceView.uiDelegate == nil {\n                sourceView.uiDelegate = self\n                sourceView.frameLoadDelegate = self\n                sourceView.mainFrame.loadHTMLString(code, baseURL: nil)\n            }\n            else {\n                sourceView.windowScriptObject.callWebScriptMethod(\"setSource\", withArguments: [html])\n            }\n        }\n        else {\n            xcode.error(\"Could not open \\(target.file)\")\n        }\n    }\n\n    func setLocation( entity: Entity ) {\n        if entity != history.last || entity.offset != history.last?.offset {\n            history.append( entity )\n        }\n        if entity.sourceName == \"Intro.html\" {\n            return\n        }\n\n        let sourceURL = entity.file.url\n        NSDocumentController.shared().noteNewRecentDocumentURL(sourceURL)\n        let sourceDir = sourceURL.deletingLastPathComponent().path\n        if var workspace = project?.workspaceName {\n            if !IndexDB.projectIncludes(file: entity.file) {\n                workspace = \"Incorrect frontmost open workspace \\(workspace)\"\n            }\n            window.title = \"\\(sourceURL.lastPathComponent) – \\(sourceDir.replacingOccurrences(of: HOME, with: \"~\")) – \\(workspace)\"\n        }\n    }\n    \n    @objc func webView( _ webView: WebView, addMessageToConsole message: NSDictionary ) {\n        Swift.print(\"\\(message)\")\n    }\n\n    @objc func webView(_ sender: WebView!, runJavaScriptAlertPanelWithMessage message: String!, initiatedBy frame: WebFrame!) {\n        print(\"\\(message)\")\n    }\n\n    @objc func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {\n        guard let win = sender.windowScriptObject else { return }\n        if sender == sourceView {\n            sourceView.policyDelegate = self\n            win.setValue(self, forKey:\"appController\")\n            win.callWebScriptMethod(\"setSource\", withArguments: [html])\n        }\n        else if sender == changesView {\n            win.setValue(self, forKey:\"appController2\")\n        }\n        else if sender == canvizView {\n            win.setValue(self, forKey:\"appController\")\n        }\n    }\n\n    @objc func webView(_ webView: WebView!, decidePolicyForNavigationAction actionInformation: [AnyHashable : Any]!,\n                       request: URLRequest!, frame: WebFrame!, decisionListener listener: WebPolicyDecisionListener!) {\n        if request.url!.scheme != \"about\" {\n            NSWorkspace.shared().open(request.url!)\n            listener.ignore()\n        }\n        else {\n            listener.use()\n        }\n    }\n\n    @objc func webView(_ sender: WebView!, contextMenuItemsForElement element: [AnyHashable : Any]!, defaultMenuItems: [Any]!) -> [Any]! {\n        return [backItem, forwardItem, reloadItem, dependsItem, searchItem]\n    }\n    \n    func setChangesSource( header: String? = nil, target: Entity? = nil, isApply: Bool = false ) {\n        window.makeKeyAndOrderFront(nil)\n        if changesView.uiDelegate == nil {\n            setupChanges()\n            RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.1))\n        }\n\n        if !isApply, let last = history.last, last != canvizEntity {\n            project = Project(target: target ?? last)\n        }\n\n        let args = [header != nil ? \"<div class=changesHeader>\\(header!)</div>\" : \"\"]\n        changesView.windowScriptObject.setValue(self, forKey:\"appController2\")\n        changesView.windowScriptObject.callWebScriptMethod(\"setSource\", withArguments: args)\n        if project?.indexDB == nil {\n            xcode.error(\"No index DB found for project: \\(project?.workspacePath ?? \"unavailable\")\")\n        }\n    }\n\n    func appendSource( title: String, text: String ) {\n        changesView.windowScriptObject.callWebScriptMethod(\"appendSource\", withArguments: [title, text])\n    }\n\n    func relative( _ path: String ) -> String {\n        return project != nil ? path\n            .replacingOccurrences(of: project!.projectRoot+\"/\", with: \"\")\n            .replacingOccurrences(of: HOME+\"/\", with: \"\") : path\n    }\n\n    @objc override class func isSelectorExcluded( fromWebScript aSelector: Selector ) -> Bool {\n        return\n            aSelector != #selector(selected(text:title:line:col:offset:metaKey:)) &&\n            aSelector != #selector(changeSelected(text:title:line:col:offset:metaKey:)) &&\n            aSelector != #selector(depends(path:)) &&\n            aSelector != #selector(graphvizExport) &&\n            aSelector != #selector(goto(file:line:))\n    }\n\n    @objc func goto(file: String, line: Int) {\n        setup(target: Entity(file: file))\n        sourceView.windowScriptObject.callWebScriptMethod(\"gotoLine\", withArguments: [\"\\(line)\"])\n    }\n\n    @objc public func selected( text: String, title: String, line: Int, col: Int, offset: Int, metaKey: Bool ) {\n        let entity = Entity(file: history.last?.file ?? title.components(separatedBy: \"#\")[0],\n                            line: line, col: col, offset: offset)\n\n        setChangesSource(target: entity)\n        replacement.stringValue = text\n        printWebView = sourceView\n        entitiesByFile.removeAll()\n        oldValue = text\n\n        if project?.indexDB == nil {\n            xcode.error(\"Unable to open index db. Best guess at path was:\\n\\(project!.indexPath)\")\n            return\n        }\n\n        let sourcePath = entity.file\n        if !IndexDB.projectIncludes(file: sourcePath) {\n            xcode.error(\"File does not seem to be in the project. Is the wrong project open in the frontmost window of Xcode?\\n\\n\")\n        }\n\n        if let indexDB = project?.indexDB {\n            if let usrIDs = indexDB.usrIDsFor(filePath: sourcePath, line: line, col: col) {\n\n                if metaKey, let entity = indexDB.declarationFor(filePath: sourcePath, line: line, col: col) {\n                    setup(target: entity, cascade: false)\n                    return\n                }\n\n                setLocation(entity: entity)\n\n                let usrs = usrIDs.map { IndexDB.resolutions[$0] ?? \"??\\($0)\" }\n                let usrText = usrs.sorted { demangle( $0 )! < demangle( $1 )! }\n                    .map { \"USR: <span title=\\\"\\($0)\\\">\\(htmlEscape( demangle( $0 ) ))</span>\\n\" }.joined()\n                appendSource(title: project!.indexPath, text: \"<div class=usr>\\(usrText)</div>\" )\n\n                var system = false\n                var pathSeen = [String:Int]()\n                _ = indexDB.entitiesFor(usrIDs: usrIDs) {\n                    (entities) in\n\n                    let path = entities[0].file\n                    if let seen = pathSeen[path] {\n                        xcode.log(\"Already seen \\(path) \\(seen) times\")\n                        pathSeen[path] = seen + 1\n                    }\n                    else {\n                        pathSeen[path] = 1\n                    }\n\n                    if path.contains(\"/Developer/Platforms/\") ||\n                        path.contains(\"/Developer/Toolchains/\" ) {\n                        system = true\n//                        return\n                    }\n\n                    entitiesByFile.append( entities )\n                }\n\n                processEntities(type: \"references\")\n                if system {\n                    appendSource(title: \"\", text: \"\\nToolchain symbol\")\n                }\n            }\n            else {\n                xcode.log(\"<span title=\\\"\\(project?.indexPath ?? \"\")\\\">No USR associated with \\(entity.sourceName)#\\(line):\\(col) in project: \\(project!.workspaceName). Is indexing complete?</span>\")\n                Process.run(path: \"/usr/bin/touch\", args: [entity.file])\n            }\n        }\n        else {\n            xcode.error(\"Could load load index db for project \\(project?.workspacePath ?? \"unknown\")\")\n        }\n    }\n\n    @objc public func changeSelected( text: String, title: String, line: Int, col: Int, offset: Int, metaKey: Bool ) {\n        let sourcePath = title.components(separatedBy: \"#\")[0]\n        printWebView = changesView\n        if  !metaKey {\n            setup(target: Entity(file: sourcePath, line: line, col: col, offset: offset), cascade: false)\n        }\n        else if let indexDB = project?.indexDB,\n            let entity = indexDB.declarationFor(filePath: sourcePath, line: line, col: col) {\n            setup(target: entity, cascade: false)\n        }\n    }\n\n    func filtered( _ lines: [String], _ entities: [Entity] ) -> String {\n        var path = entities[0].file, filename = relative( path )\n        filename = filename.substring(from: filename.range(of: \"SDKs\")?.lowerBound ?? filename.startIndex)\n        let linenos = Set( entities.map { $0.line } ).sorted(), body = linenos.map { lines[$0-1] }.joined()\n        return \"<a class=sourceLink href=\\\"file:\\(path)\\\">\\(filename)</a>\\n<div class='changesEntry'>\\(body)</div>\"\n    }\n\n    func processEntities(type: String) {\n        var changes = 0, files = 0\n\n        for entities in entitiesByFile.sorted( by: { $0[0].file < $1[0].file } ) {\n            let path = entities[0].file\n            if let sourceData = NSData(contentsOfFile: path) {\n                let lines = formatter.htmlFor(path: path, data: sourceData, entities: entities)\n                appendSource(title: path, text: filtered(lines, entities))\n                linecounts[path] = lines.count\n\n                changes += entities.count\n                files += 1\n            }\n            else {\n                xcode.log(\"Could not read \\(path)\")\n            }\n        }\n\n        appendSource(title: \"\", text: \"\\(changes) \\(type) in \\(files) file\"+(files==1 ? \"\" : \"s\"))\n    }\n\n    @objc func depends( path: String ) {\n        setChangesSource(header: \"Dependencies on \\(relative(path))\")\n        if let indexDB = project?.indexDB {\n            entitiesByFile = indexDB.dependsOn(path: path)\n        }\n        processEntities(type: \"dependencies\")\n    }\n\n    @objc func graphvizExport() {\n        open(url: formatter.gvfile)\n    }\n\n    func applySubstitution(oldValue: String, newValue: String) {\n        let newData = newValue.data(using: .utf8)!\n        let skew = newData.count - oldValue.utf8.count\n        setChangesSource(header: \"Applying replacement of '\\(oldValue)' with '\\(newValue)'\", isApply: true)\n\n        var modifications = 0\n        for entities in entitiesByFile.sorted( by: { $0[0].file < $1[0].file } ) {\n            let path = entities[0].file\n            if let contents = modified[path] ?? NSData(contentsOfFile: path) {\n                if originals[path] == nil {\n                    originals[path] = contents\n                }\n\n                let out = NSMutableData()\n                var pos = 0, mods = 0\n                for entity in entities {\n                    if let matches = entity.regex(text: oldValue).match(input: contents), Int(matches[2].rm_so) >= pos {\n                        let startOffset = Int(matches[2].rm_so)\n                        out.append( contents.subdata( with: NSMakeRange(pos, startOffset-pos) ) )\n\n                        if let entity = history.last, path == entity.file && startOffset == entity.offset {\n                            entity.offset = out.length\n                        }\n                        entity.offset = out.length\n\n                        out.append( newData )\n                        pos = Int(matches[2].rm_eo)\n                        modifications += 1\n                        mods += 1\n                    }\n                    else if wasSearch {\n                        entity.notMatch = true\n                    }\n                    else {\n                        xcode.log(\"Could not match \\(newValue) at \\(path)#\\(entity.line):\\(entity.col)\")\n                    }\n                }\n\n                out.append( contents.subdata( with: NSMakeRange(pos, contents.length-pos) ) )\n                modified[path] = out\n\n                let lines = formatter.htmlFor(path: path, data: out, entities: entities, skew: skew)\n                appendSource(title: path, text: filtered(lines, entities))\n                if lines.count != linecounts[path] {\n                    xcode.log(\"Mismatched linecount \\(lines.count) != \\(linecounts[path]) for \\(path)\")\n                }\n            }\n        }\n\n        changes += \"<div id=applying>Changing <span class=oldValue>'\\(oldValue)'</span> to <span class=newValue>'\\(newValue)'</span>...<div>\"\n        appendSource(title: \"\", text: \"\\(modifications) modifications proposed\")\n    }\n\n    func writeChanges( dict: [String:NSData], header: String ) {\n        setChangesSource(header: header, isApply: true)\n        for (path, data) in dict {\n            let wrote = data.write(toFile: path, atomically: true)\n            appendSource(title: path, text: \"\\(wrote ? \"Wrote\" : \"Could not write to\") \\(path)\\n\")\n        }\n\n        let indexUpdateTime = 5.0\n        appendSource(title: \"\", text: \"\\nRefreshing in \\(indexUpdateTime) seconds\\n\")\n        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + indexUpdateTime) {\n            self.setup(target: self.history.last ?? self.defaultEntity())\n        }\n\n        formatter = Formatter()\n        modified.removeAll()\n        changes = \"\"\n    }\n\n    func searchProject(sender: AnyObject) {\n        let pattern = sender is NSMenuItem ? replacement.stringValue : findText.stringValue\n        setChangesSource(header: \"USR search for pattern: \\(pattern)\")\n        guard let indexDB = project?.indexDB else {\n            xcode.error(\"Could load load index db \\(project!.indexPath)\")\n            return\n        }\n\n        replacement.stringValue = pattern\n        oldValue = pattern\n        wasSearch = true\n\n        entitiesByFile = indexDB.entitiesFor(pattern: pattern)\n    }\n\n}\n"
  },
  {
    "path": "Refactorator/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 19/11/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n//  http://johnholdsworth.com/refactorator.html\n//\n\nimport Cocoa\n\n@NSApplicationMain\nclass AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {\n\n    class PathMenuItem: NSMenuItem {\n\n        let path: String\n\n        init(path: String, title: String, action: Selector) {\n            self.path = path\n            super.init(title: title, action: action, keyEquivalent: \"\")\n        }\n\n        required init(coder decoder: NSCoder) {\n            fatalError(\"init(coder:) has not been implemented\")\n        }\n\n    }\n\n    class EntityMenuItem: NSMenuItem {\n\n        let entity: Entity\n\n        init(entity: Entity, title: String, action: Selector, keyEquivalent: String) {\n            self.entity = entity\n            super.init(title: title, action: action, keyEquivalent: keyEquivalent)\n        }\n        \n        required init(coder decoder: NSCoder) {\n            fatalError(\"init(coder:) has not been implemented\")\n        }\n        \n    }\n    \n    @IBOutlet weak var window: NSWindow!\n\n    @IBOutlet var findPanel: NSPanel!\n    @IBOutlet weak var findText: NSTextField!\n\n    @IBOutlet weak var applyButton: NSButton!\n    @IBOutlet weak var saveButton: NSButton!\n    @IBOutlet weak var revertButton: NSButton!\n\n    @IBOutlet var state: AppController!\n\n    var saved = false\n\n    var licensed: Bool {\n        return UserDefaults.standard.string(forKey: colorKey) == myColor\n    }\n\n    @objc func applicationDidFinishLaunching(_ aNotification: Notification) {\n        // Insert code here to initialize your application\n        NSApp.servicesProvider = self\n        NSUpdateDynamicServices()\n\n        state.history = NSDocumentController.shared().recentDocumentURLs.reversed().map { Entity( file: $0.path ) }\n        xcode = state\n\n        let defaults = UserDefaults.standard, countKey = \"n\"\n        let count = max(0,defaults.integer(forKey: countKey))+1\n        defaults.set(count, forKey: countKey)\n\n//        window.contentView?.wantsLayer = true\n//        window.appearance = NSAppearance(named: NSAppearanceNameVibrantDark)\n\n        _ = Integration(appDelegate: self, count: count)\n    }\n\n    @objc func application(_ theApplication: NSApplication, openFile filename: String ) -> Bool {\n        state.setup(target: Entity(file: filename))\n        return true\n    }\n\n    @objc func refactorator(_ pboard: NSPasteboard, userData: String, error: NSErrorPointer) {\n        _ = pboard.string(forType: NSPasteboardTypeString)\n        NSApp.activate(ignoringOtherApps: true)\n        window.makeKeyAndOrderFront(nil)\n        state.setup()\n    }\n\n    @objc func refactorFile(_ pboard: NSPasteboard, userData: String, error: NSErrorPointer) {\n        let options = [NSPasteboardURLReadingFileURLsOnlyKey:true]\n        if let fileURLs = pboard.readObjects(forClasses: [NSURL.self], options: options),\n            let file = (fileURLs.first as? NSURL)?.path {\n            state.setup(target: Entity(file: file))\n        }\n    }\n\n    @objc func windowWillClose(_ notification: Notification) {\n//        NSApp.hide(nil)\n    }\n\n    @objc func applicationDidUnhide(_ notification: Notification) {\n//        window.makeKeyAndOrderFront(nil)\n    }\n\n    @objc func applicationWillBecomeActive(_ notification: Notification) {\n//        window.makeKeyAndOrderFront(nil)\n//        state.setup()\n    }\n\n    @IBAction func syncToXcode(sender: NSMenuItem) {\n        state.setup()\n    }\n\n    @IBAction func open(sender: NSMenuItem) {\n        let panel = NSOpenPanel()\n        panel.allowsMultipleSelection = false\n        panel.canChooseDirectories = false\n        panel.canCreateDirectories = false\n        panel.canChooseFiles = true\n        panel.begin { (result) -> Void in\n            if result == NSFileHandlingPanelOKButton,\n                let url = panel.url {\n                self.state.setup(target: Entity(file: url.path))\n            }\n        }\n    }\n\n    @IBAction func openInXcode(sender: NSMenuItem) {\n        if let current = state.history.last {\n            state.open(url: current.file)\n        }\n    }\n\n    @IBAction func openWorkspace(sender: NSMenuItem) {\n        if let workspace = state.project?.workspacePath {\n            state.open(url: workspace)\n        }\n    }\n\n    @IBAction func back(sender: NSMenuItem) {\n        if !state.history.isEmpty {\n            state.future.append( state.history.removeLast() )\n            let save = state.future\n            if !state.history.isEmpty {\n                let previous = state.history.removeLast()\n                state.setup(target: previous, cascade: false)\n            }\n            else {\n                let recentSources = NSDocumentController.shared().recentDocumentURLs\n                if recentSources.count > 1 {\n                    state.setup(target: Entity(file: recentSources[1].path))\n                }\n            }\n            state.future = save\n        }\n    }\n\n    @IBAction func forward(sender: NSMenuItem) {\n        if !state.future.isEmpty {\n            state.setup(target: state.future.removeLast())\n        }\n    }\n\n    @IBAction func reload(sender: NSMenuItem) {\n        if let current = state.history.last {\n            state.setup(target: Entity(file: current.file))\n        }\n    }\n    \n    @IBAction func printSource(sender: NSMenuItem) {\n        let pi = NSPrintInfo.shared()\n        pi.topMargin = 50\n        pi.leftMargin = 25\n        pi.rightMargin = 25\n        pi.bottomMargin = 50\n        pi.isHorizontallyCentered = false\n        NSPrintOperation(view: state.printWebView.mainFrame.frameView.documentView, printInfo: pi).run()\n    }\n\n    @IBAction func zapDerivedData(sender: NSMenuItem) {\n        let dir = HOME + \"/Library/Developer/Xcode/DerivedData\"\n        let alert = NSAlert()\n        alert.messageText = \"Refactorator\"\n        alert.informativeText = \"This will \\\"rm -rf\\\" the contents of Xcode's DerivedData directory: \\(dir). There are rare times when this can be a good idea.\"\n        alert.addButton(withTitle: \"Cancel\")\n        alert.addButton(withTitle: \"I know what I'm doing\")\n        if alert.runModal() == NSAlertSecondButtonReturn {\n            Process.run(path: \"/bin/rm\", args: [\"-rf\", dir])\n        }\n    }\n\n    @IBAction func undoChanges(sender: AnyObject) {\n        state.modified.removeAll()\n        state.changes = \"\"\n    }\n\n    @objc override func validateMenuItem(_ aMenuItem: NSMenuItem) -> Bool {\n        if let action = aMenuItem.action {\n            switch action {\n            case #selector(back(sender:)):\n                return !state.history.isEmpty\n            case #selector(forward(sender:)):\n                return !state.future.isEmpty\n            case #selector(openWorkspace(sender:)):\n                return state.project?.workspacePath != Project.unknown\n            case #selector(undoChanges(sender:)):\n                fallthrough\n            case #selector(saveChanges(sender:)):\n                return !state.modified.isEmpty\n            case #selector(revertSession(sender:)):\n                return !state.originals.isEmpty && saved\n            case #selector(buildProject(sender:)):\n                return state.project?.workspaceDoc != nil\n            case #selector(indexRebuild(sender:)):\n                return state.project?.projectRoot != Project.unknown\n            case #selector(buildSite(sender:)):\n                return state.project?.indexDB != nil\n            case #selector(navigateDirectories(sender:)):\n                if let navigateMenu = aMenuItem.submenu {\n                    while navigateMenu.items.count != 0 {\n                        navigateMenu.removeItem(at: 0)\n                    }\n                    if let indexDB = state.project?.indexDB {\n                        var projectDirs = [String]()\n                        for dirID in indexDB.projectDirIDs.keys {\n                            if let wholePath = indexDB.directories[dirID] {\n                                if wholePath.contains(\".\") {\n                                    continue\n                                }\n                                projectDirs.append( wholePath )\n                            }\n                        }\n                        for wholePath in projectDirs.sorted() {\n                            var dirPath = wholePath.url\n                            var title = dirPath.lastPathComponent\n                            while title == \"Classes\" || title == \"Source\" || title == \"Pod\" {\n                                dirPath.deleteLastPathComponent()\n                                title = dirPath.lastPathComponent\n                            }\n                            let item = PathMenuItem(path: wholePath, title: title,\n                                                    action: #selector(navigateFiles(sender:)))\n                            item.target = self\n                            item.submenu = NSMenu()\n    //                        item.toolTip = wholePath\n                            navigateMenu.addItem(item)\n                        }\n                    }\n                }\n            case #selector(navigateFiles(sender:)):\n                if let item = aMenuItem as? PathMenuItem,\n                    let menu = item.submenu,\n                    let indexDB = state.project?.indexDB {\n                    for file in indexDB.files(inDirectory: item.path).sorted() {\n                        let item = PathMenuItem(path: item.path+\"/\"+file, title: file,\n                                                action: #selector(navigateOpen(sender:)))\n                        item.toolTip = item.path+\"/\"+file\n                        item.target = self\n                        menu.addItem(item)\n                    }\n                }\n            case #selector(backEntities(sender:)):\n                if let backMenu = aMenuItem.submenu {\n                    while backMenu.items.count != 0 {\n                        backMenu.removeItem(at: 0)\n                    }\n                    var number = 0\n                    for entity in state.history.reversed() {\n                        if number > 0 {\n                            let item = EntityMenuItem(entity: entity, title: entity.file.url.lastPathComponent,\n                                                      action: #selector(backOpen(sender:)),\n                                                      keyEquivalent: number == 1 ? \"[\" : \"\")\n                            item.target = self\n                            backMenu.addItem(item)\n                        }\n                        number += 1\n                    }\n                }\n            default:\n                break\n            }\n        }\n        return true\n    }\n\n    @IBAction func applySubstitution(sender: NSButton) {\n\n        let newValue = state.replacement.stringValue\n        if newValue == myColor && !licensed {\n            state.setChangesSource(header: \"<div class=licensed>You are now licensed. Thanks!</div><br><img src='data:image/png;base64,\\(fireworks)'>\", isApply: true)\n            UserDefaults.standard.set(newValue, forKey: colorKey)\n            UserDefaults.standard.synchronize()\n            return\n        }\n\n        if state.oldValue == \"\" {\n            state.setChangesSource(header: \"Please select an entity before applying replacement\", isApply: true)\n            return\n        }\n\n        state.applySubstitution(oldValue: state.oldValue, newValue: newValue)\n        state.oldValue = newValue\n\n        revertButton.isEnabled = !state.originals.isEmpty\n        saveButton.isEnabled = !state.modified.isEmpty\n    }\n\n    @IBAction func openFind(sender: NSMenuItem) {\n        if findText.stringValue == \"\" {\n            findText.stringValue = state.replacement.stringValue\n        }\n        findPanel.makeKeyAndOrderFront(nil)\n    }\n\n    @IBAction func findInSource(sender: AnyObject) {\n        let string = findText.stringValue\n        switch sender.tag {\n        case 1:\n            fallthrough\n        case 2:\n            state.sourceView.search( for: string, direction:true, caseSensitive:false, wrap:true)\n        case 3:\n            state.sourceView.search( for: string, direction:false, caseSensitive:false, wrap:true)\n        default:\n            break\n        }\n    }\n\n    @IBAction func searchProject(sender: AnyObject) {\n        state.searchProject(sender: sender)\n        state.processEntities(type: sender is AppDelegate ? \"errors\" : \"references\")\n    }\n    \n    @IBAction func findOrphans(sender: NSMenuItem) {\n        state.setChangesSource(header: \"Symbols declared but not referred to...\")\n        guard let indexDB = state.project?.indexDB else {\n            xcode.error(\"Could load load index db \\(state.project!.indexPath)\")\n            return\n        }\n\n        state.entitiesByFile = indexDB.orphans()\n        state.processEntities(type: \"unused symbols\")\n    }\n    \n    @IBAction func saveChanges(sender: AnyObject) {\n        state.writeChanges(dict: state.modified, header: state.changes)\n        saved = true\n    }\n\n    @IBAction func buildProject(sender: AnyObject) {\n        _ = state.project?.workspaceDoc?.build()\n    }\n\n    @IBAction func revertSession(sender: AnyObject) {\n        state.writeChanges(dict: state.originals, header: \"Reverting changes...\\n\")\n        undoChanges(sender: self)\n    }\n\n    @IBAction func indexCheck(sender: NSMenuItem) {\n        findText.stringValue = \"ERROR TYPE\"\n        searchProject(sender: self)\n    }\n\n    @IBAction func searchSelection(sender: NSMenuItem) {\n        findText.stringValue = state.oldValue\n        searchProject(sender: self)\n    }\n\n    @IBAction func indexRebuild(sender: NSMenuItem) {\n        Process.run(path: \"/usr/bin/find\", args: [state.project!.projectRoot,\n                                                  \"-name\", \"*.swift\", \"-exec\", \"touch\", \"{}\", \";\"])\n    }\n\n    @IBAction func exportHTML(sender: NSMenuItem) {\n        let out = state.sourceView.windowScriptObject.evaluateWebScript(\"document.head.outerHTML + document.body.outerHTML\") as! String\n        let panel = NSSavePanel()\n        panel.nameFieldStringValue = state.history.last!.file.url.deletingPathExtension().lastPathComponent+\".html\"\n        panel.begin { (result) -> Void in\n            if result == NSFileHandlingPanelOKButton,\n                let url = panel.url {\n                try? out.write(to: url, atomically: false, encoding: .utf8)\n            }\n        }\n    }\n\n    @IBAction func navigateDirectories(sender: AnyObject) {\n    }\n    \n    @IBAction func navigateFiles(sender: AnyObject) {\n    }\n    \n    @IBAction func navigateOpen(sender: PathMenuItem) {\n        state.setup(target: Entity(file: sender.path))\n    }\n\n    @IBAction func backEntities(sender: AnyObject) {\n    }\n\n    @IBAction func backOpen(sender: EntityMenuItem) {\n        state.history.last.flatMap { state.future.append($0) }\n        let save = state.future\n        state.setup(target: sender.entity)\n        state.future = save\n    }\n\n    @IBAction func buildSite(sender: AnyObject) {\n        guard let projectRoot = state.project?.projectRoot else { return }\n        state.formatter.buildSite( for: state.project!, into: projectRoot+\"/html/\", state: state)\n    }\n\n    @IBAction func findDependencies(sender: AnyObject) {\n        if sender as? NSMenuItem == state.dependsItem,\n            let path = state.history.last?.file {\n            state.depends(path: path)\n        }\n        else {\n            if !FileManager.default.fileExists(atPath: state.formatter.DOT_PATH) {\n                let alert = NSAlert()\n                alert.messageText = \"Refactorator\"\n                alert.informativeText = \"Dependencies in your application \" +\n                \"can be displayed if you install \\\"dot\\\" from http://www.graphviz.org/.\"\n                alert.runModal()\n                state.open(url: \"http://www.graphviz.org/Download_macos.php\")\n                return\n            }\n            \n            state.project = Project(target: state.history.last )\n            state.formatter.runDepends(state: state, standalone: false)\n\n            state.canvizView = nil\n            state.setup(target: state.canvizEntity)\n        }\n    }\n\n    @IBAction func findAssociated(sender: AnyObject) {\n        state.formatter.indexAssociations(filePath: state.history.last!.file, state: state)\n    }\n\n}\n\nlet myIndex = {\n    () -> Int in\n    var index = 0\n    if var chars = getenv(\"USER\") {\n        while chars.pointee != 0 {\n            index += Int(chars.pointee)\n            chars += 1\n        }\n    }\n    return index\n}()\n\nprivate let myColor = {\n    () -> String in\n    return colors[myIndex % colors.count]\n}()\n\nprivate let colorKey = \"Color\"\n\nprivate var fireworks = \"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\"\n"
  },
  {
    "path": "Refactorator/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Refactorator/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=\"11762\" systemVersion=\"15G1212\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11762\"/>\n        <plugIn identifier=\"com.apple.WebKitIBPlugin\" version=\"11762\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\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=\"Injection\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"applyButton\" destination=\"Izx-PW-zhY\" id=\"iBw-bi-MwO\"/>\n                <outlet property=\"findPanel\" destination=\"A2I-eS-piB\" id=\"f2N-7f-Gh0\"/>\n                <outlet property=\"findText\" destination=\"cpj-R8-vCt\" id=\"rCd-e6-2rU\"/>\n                <outlet property=\"revertButton\" destination=\"IcZ-6U-OZY\" id=\"pfI-XV-kvK\"/>\n                <outlet property=\"saveButton\" destination=\"atp-pA-4jR\" id=\"0qy-Ju-HXL\"/>\n                <outlet property=\"state\" destination=\"nF1-TD-e5Y\" id=\"dAj-Je-v3j\"/>\n                <outlet property=\"window\" destination=\"QvC-M9-y7g\" id=\"jIt-wF-TW8\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"Refactorator\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Refactorator\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About Refactorator\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"orderFrontStandardAboutPanel:\" target=\"-1\" id=\"Exp-CZ-Vem\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" hidden=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" hidden=\"YES\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide Refactorator\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit Refactorator\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                        <items>\n                            <menuItem title=\"New\" hidden=\"YES\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                <connections>\n                                    <action selector=\"newDocument:\" target=\"-1\" id=\"4Si-XN-c54\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Back\" keyEquivalent=\"[\" toolTip=\"Navigate to previous file\" id=\"SvX-iU-EQT\">\n                                <connections>\n                                    <action selector=\"backWithSender:\" target=\"Voe-Tx-rLC\" id=\"lfQ-jG-uDH\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Forward\" keyEquivalent=\"]\" toolTip=\"Navigate to previous file\" id=\"SgJ-iz-IgR\">\n                                <connections>\n                                    <action selector=\"forwardWithSender:\" target=\"Voe-Tx-rLC\" id=\"6eK-ju-wUY\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Navigate\" id=\"Ks8-6s-W0O\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Navigate\" id=\"QcH-1k-rC4\"/>\n                                <connections>\n                                    <action selector=\"navigateDirectoriesWithSender:\" target=\"Voe-Tx-rLC\" id=\"eeo-9U-3py\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                            <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"ss4-gS-ptz\">\n                                <connections>\n                                    <action selector=\"openWithSender:\" target=\"Voe-Tx-rLC\" id=\"Ecz-sM-83p\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                    <items>\n                                        <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"clearRecentDocuments:\" target=\"-1\" id=\"Daa-9d-B3U\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Open in Xcode\" keyEquivalent=\"O\" toolTip=\"Open Source file in default editor\" id=\"ABn-uE-BS1\">\n                                <connections>\n                                    <action selector=\"openInXcodeWithSender:\" target=\"Voe-Tx-rLC\" id=\"Zgk-9P-ugI\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open Project\" keyEquivalent=\"o\" toolTip=\"Open associated Xcode project\" id=\"alq-4I-Ur0\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"openWorkspaceWithSender:\" target=\"Voe-Tx-rLC\" id=\"gAo-vk-GDx\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Sync to Xcode\" keyEquivalent=\"y\" id=\"IAo-SY-fd9\">\n                                <connections>\n                                    <action selector=\"syncToXcodeWithSender:\" target=\"Voe-Tx-rLC\" id=\"pZd-Bk-QaN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Undo Apply\" keyEquivalent=\"u\" toolTip=\"Undo any changes applied in memory\" id=\"pxx-59-PXV\">\n                                <connections>\n                                    <action selector=\"undoChangesWithSender:\" target=\"Voe-Tx-rLC\" id=\"Hvl-b3-J5l\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save To Disk…\" keyEquivalent=\"s\" toolTip=\"Save all modifications to disk\" id=\"GfA-ng-gpe\">\n                                <connections>\n                                    <action selector=\"saveChangesWithSender:\" target=\"Voe-Tx-rLC\" id=\"7Eg-1X-K8S\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Perform Build…\" keyEquivalent=\"b\" toolTip=\"Perform a test build of the project\" id=\"Bw7-FT-i3A\">\n                                <connections>\n                                    <action selector=\"buildProjectWithSender:\" target=\"Voe-Tx-rLC\" id=\"MW0-0S-R9p\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Revert Changes\" keyEquivalent=\"r\" toolTip=\"Revert all changes made since Refactorator launched\" id=\"KaW-ft-85H\">\n                                <connections>\n                                    <action selector=\"revertSessionWithSender:\" target=\"Voe-Tx-rLC\" id=\"RHO-L8-b6g\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                            <menuItem title=\"Zap DervivedData\" hidden=\"YES\" toolTip=\"Completely remove Xcode's DrivedDat directory to force index rebuild.\" id=\"tVJ-u1-yHX\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"zapDerivedDataWithSender:\" target=\"Voe-Tx-rLC\" id=\"D0J-Iu-pjm\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Check Index DB\" toolTip=\"Check index database for obvious errors\" id=\"DA7-dj-Vke\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"indexCheckWithSender:\" target=\"Voe-Tx-rLC\" id=\"R3f-9d-yWp\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Force Re-Index\" toolTip=\"Touch all swift files to force index re-build\" id=\"0pR-Gj-uH2\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"indexRebuildWithSender:\" target=\"Voe-Tx-rLC\" id=\"wZt-mp-h0F\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Index Protocols\" toolTip=\"Re-index project to find associateion bwteen USRs e.g. implements protocol\" id=\"duR-AO-ekK\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"findAssociatedWithSender:\" target=\"Voe-Tx-rLC\" id=\"qu1-vh-8Y2\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Dependencies\" toolTip=\"Find dependencies bewteen source files (requires Graphviz)\" id=\"AK8-sM-fgc\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"findDependenciesWithSender:\" target=\"Voe-Tx-rLC\" id=\"nQo-Tc-GRe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Export HTML\" toolTip=\"Extract olourised HTML for source\" id=\"xV4-lN-mus\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"exportHTMLWithSender:\" target=\"Voe-Tx-rLC\" id=\"QJo-IQ-Zb6\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Build Site\" toolTip=\"Build cros linked HTML site for your project\" id=\"x9U-ND-vGe\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"buildSiteWithSender:\" target=\"Voe-Tx-rLC\" id=\"bHd-fG-xE2\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Close\" keyEquivalent=\"w\" toolTip=\"Close window and exit\" id=\"DVo-aG-piG\">\n                                <connections>\n                                    <action selector=\"performClose:\" target=\"-1\" id=\"ehy-yF-tr1\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"RZQ-bj-ZDO\"/>\n                            <menuItem title=\"Page Setup…\" hidden=\"YES\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"runPageLayout:\" target=\"-1\" id=\"Din-rz-gC5\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                <connections>\n                                    <action selector=\"printSourceWithSender:\" target=\"Voe-Tx-rLC\" id=\"J2e-tC-nGG\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" hidden=\"YES\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" hidden=\"YES\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" hidden=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste and Match Style\" hidden=\"YES\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"pasteAsPlainText:\" target=\"-1\" id=\"cEh-KX-wJQ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" hidden=\"YES\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" hidden=\"YES\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Spelling and Grammar\" hidden=\"YES\" id=\"Dv1-io-Yv7\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"vFj-Ks-hy3\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"fz7-VC-reM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"7w6-Qz-0kB\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"muD-Qn-j4w\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"2lM-Qi-WAP\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" hidden=\"YES\" id=\"9ic-FL-obx\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"oku-mr-iSq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"3IJ-Se-DZD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"ptq-xd-QOA\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"oCt-pO-9gS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"Gip-E3-Fov\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"R1I-Nq-Kbl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"DvP-Fe-Py6\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" hidden=\"YES\" id=\"2oI-Rn-ZJC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"sPh-Tk-edu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"iUZ-b5-hil\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"26H-TL-nsh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" hidden=\"YES\" id=\"xrE-MZ-jX0\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"654-Ng-kyl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"dX8-6p-jy9\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                        <items>\n                            <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" toolTip=\"Search in source of project\" id=\"Xz5-n4-O0W\">\n                                <connections>\n                                    <action selector=\"openFindWithSender:\" target=\"Voe-Tx-rLC\" id=\"9hX-CZ-m98\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Find and Replace…\" tag=\"12\" hidden=\"YES\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" toolTip=\"Find next\" id=\"q09-fT-Sye\">\n                                <connections>\n                                    <action selector=\"findInSourceWithSender:\" target=\"Voe-Tx-rLC\" id=\"2ac-Pf-Dnc\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" toolTip=\"Find previous\" id=\"OwM-mh-QMV\">\n                                <connections>\n                                    <action selector=\"findInSourceWithSender:\" target=\"Voe-Tx-rLC\" id=\"nG6-aF-4cY\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Use Selection for Find\" tag=\"7\" hidden=\"YES\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                <connections>\n                                    <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Project Search\" keyEquivalent=\"g\" toolTip=\"grep through project Symbols using a regex\" id=\"gbP-jh-pGT\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"openFindWithSender:\" target=\"Voe-Tx-rLC\" id=\"k7k-IT-vf2\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Find Unused\" toolTip=\"Search for symbols declared but not referred to in code\" id=\"jEQ-l8-b1a\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"findOrphansWithSender:\" target=\"Voe-Tx-rLC\" id=\"WaZ-nh-8RO\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Jump to Selection\" hidden=\"YES\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                <connections>\n                                    <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Format\" hidden=\"YES\" id=\"jxT-CU-nIS\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                        <items>\n                            <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                    <items>\n                                        <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                            <connections>\n                                                <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                            <connections>\n                                                <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                            <connections>\n                                                <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                            <connections>\n                                                <action selector=\"underline:\" target=\"-1\" id=\"FYS-2b-JAY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                        <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                            <connections>\n                                                <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                            <connections>\n                                                <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                        <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useStandardKerning:\" target=\"-1\" id=\"6dk-9l-Ckg\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"turnOffKerning:\" target=\"-1\" id=\"U8a-gz-Maa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"tightenKerning:\" target=\"-1\" id=\"hr7-Nz-8ro\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"loosenKerning:\" target=\"-1\" id=\"8i4-f9-FKE\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useStandardLigatures:\" target=\"-1\" id=\"7uR-wd-Dx6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"turnOffLigatures:\" target=\"-1\" id=\"iX2-gA-Ilz\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useAllLigatures:\" target=\"-1\" id=\"KcB-kA-TuK\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"unscript:\" target=\"-1\" id=\"0vZ-95-Ywn\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"superscript:\" target=\"-1\" id=\"3qV-fo-wpU\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"subscript:\" target=\"-1\" id=\"Q6W-4W-IGz\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"raiseBaseline:\" target=\"-1\" id=\"4sk-31-7Q9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowerBaseline:\" target=\"-1\" id=\"OF1-bc-KW4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                        <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                            <connections>\n                                                <action selector=\"orderFrontColorPanel:\" target=\"-1\" id=\"mSX-Xz-DV3\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                        <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"copyFont:\" target=\"-1\" id=\"GJO-xA-L4q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteFont:\" target=\"-1\" id=\"JfD-CL-leO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                    <items>\n                                        <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                            <connections>\n                                                <action selector=\"alignLeft:\" target=\"-1\" id=\"zUv-R1-uAa\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                            <connections>\n                                                <action selector=\"alignCenter:\" target=\"-1\" id=\"spX-mk-kcS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"alignJustified:\" target=\"-1\" id=\"ljL-7U-jND\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                            <connections>\n                                                <action selector=\"alignRight:\" target=\"-1\" id=\"r48-bG-YeY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                        <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                <items>\n                                                    <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                    </menuItem>\n                                                    <menuItem id=\"YGs-j5-SAR\">\n                                                        <string key=\"title\">\tDefault</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionNatural:\" target=\"-1\" id=\"qtV-5e-UBP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"Lbh-J2-qVU\">\n                                                        <string key=\"title\">\tLeft to Right</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"-1\" id=\"S0X-9S-QSf\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"jFq-tB-4Kx\">\n                                                        <string key=\"title\">\tRight to Left</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"-1\" id=\"5fk-qB-AqJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                    <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                    </menuItem>\n                                                    <menuItem id=\"Nop-cj-93Q\">\n                                                        <string key=\"title\">\tDefault</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionNatural:\" target=\"-1\" id=\"lPI-Se-ZHp\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"BgM-ve-c93\">\n                                                        <string key=\"title\">\tLeft to Right</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"-1\" id=\"caW-Bv-w94\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"RB4-Sm-HuC\">\n                                                        <string key=\"title\">\tRight to Left</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"-1\" id=\"EXD-6r-ZUu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                        <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleRuler:\" target=\"-1\" id=\"FOx-HJ-KwY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"copyRuler:\" target=\"-1\" id=\"71i-fW-3W2\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteRuler:\" target=\"-1\" id=\"cSh-wd-qM2\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"View\" hidden=\"YES\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                        <items>\n                            <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleToolbarShown:\" target=\"-1\" id=\"BXY-wc-z0C\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"runToolbarCustomizationPalette:\" target=\"-1\" id=\"pQI-g3-MTW\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                            <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleSourceList:\" target=\"-1\" id=\"iwa-gc-5KM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"dU3-MA-1Rq\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                        <items>\n                            <menuItem title=\"General Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                <connections>\n                                    <action selector=\"helpWithSender:\" target=\"Voe-Tx-rLC\" id=\"sYW-Kc-obu\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Shout John a Beer\" keyEquivalent=\"🍺\" id=\"yLP-Wv-ElC\">\n                                <connections>\n                                    <action selector=\"donateWithSender:\" target=\"Voe-Tx-rLC\" id=\"eGG-0t-KC3\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n            </items>\n        </menu>\n        <window title=\"Welcome to Refactorator\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"Refactorator\" animationBehavior=\"default\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"335\" y=\"390\" width=\"718\" height=\"713\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1177\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" misplaced=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"718\" height=\"713\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <splitView misplaced=\"YES\" arrangesAllSubviews=\"NO\" dividerStyle=\"paneSplitter\" id=\"R7d-nT-bCd\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"718\" height=\"713\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <customView id=\"D5a-sP-aUT\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"718\" height=\"484\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <webView misplaced=\"YES\" id=\"hoP-PD-VYj\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"38\" width=\"718\" height=\"446\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                        <webPreferences key=\"preferences\" defaultFontSize=\"12\" defaultFixedFontSize=\"12\" plugInsEnabled=\"NO\" javaEnabled=\"NO\" javaScriptCanOpenWindowsAutomatically=\"NO\" allowsAnimatedImages=\"NO\" allowsAnimatedImageLooping=\"NO\">\n                                            <nil key=\"identifier\"/>\n                                        </webPreferences>\n                                    </webView>\n                                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"5nb-3q-Dw7\">\n                                        <rect key=\"frame\" x=\"9\" y=\"11\" width=\"73\" height=\"17\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Rename to:\" id=\"cs8-CC-T22\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <textField toolTip=\"New value for idedntifier name\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"hvb-Q7-aD4\">\n                                        <rect key=\"frame\" x=\"85\" y=\"8\" width=\"287\" height=\"22\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"Pgk-cL-dwp\">\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                                        <connections>\n                                            <action selector=\"performClick:\" target=\"Izx-PW-zhY\" id=\"TuX-VO-6R9\"/>\n                                        </connections>\n                                    </textField>\n                                    <button toolTip=\"Apply change in memory\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"Izx-PW-zhY\">\n                                        <rect key=\"frame\" x=\"374\" y=\"2\" width=\"83\" height=\"32\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <buttonCell key=\"cell\" type=\"push\" title=\"Apply\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"nsv-rB-oCY\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"applySubstitutionWithSender:\" target=\"Voe-Tx-rLC\" id=\"iyT-6H-3yF\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"Save changes to disk\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"atp-pA-4jR\">\n                                        <rect key=\"frame\" x=\"452\" y=\"2\" width=\"81\" height=\"32\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" enabled=\"NO\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"sqZ-NX-jMo\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"saveChangesWithSender:\" target=\"Voe-Tx-rLC\" id=\"8Tc-ZS-Y6D\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"Check that project still builds\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"BoD-Ix-wka\">\n                                        <rect key=\"frame\" x=\"527\" y=\"2\" width=\"113\" height=\"32\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <buttonCell key=\"cell\" type=\"push\" title=\"Check Build\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"10p-49-7Ni\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"buildProjectWithSender:\" target=\"Voe-Tx-rLC\" id=\"Bp1-Kr-bfO\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"Revert all changes since the beginning of the session\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"IcZ-6U-OZY\">\n                                        <rect key=\"frame\" x=\"633\" y=\"2\" width=\"80\" height=\"32\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <buttonCell key=\"cell\" type=\"push\" title=\"Revert\" bezelStyle=\"rounded\" alignment=\"center\" enabled=\"NO\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"F0V-iV-ebh\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"revertSessionWithSender:\" target=\"Voe-Tx-rLC\" id=\"kV2-z5-yUJ\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                            </customView>\n                            <customView id=\"a6X-bH-sPj\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"494\" width=\"718\" height=\"219\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <webView misplaced=\"YES\" maintainsBackForwardList=\"NO\" id=\"Kfe-Ht-0tr\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"718\" height=\"219\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                        <webPreferences key=\"preferences\" defaultFontSize=\"12\" defaultFixedFontSize=\"12\" plugInsEnabled=\"NO\" javaEnabled=\"NO\" javaScriptCanOpenWindowsAutomatically=\"NO\" allowsAnimatedImages=\"NO\" allowsAnimatedImageLooping=\"NO\">\n                                            <nil key=\"identifier\"/>\n                                        </webPreferences>\n                                    </webView>\n                                </subviews>\n                            </customView>\n                        </subviews>\n                        <holdingPriorities>\n                            <real value=\"250\"/>\n                            <real value=\"250\"/>\n                        </holdingPriorities>\n                    </splitView>\n                </subviews>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"Kiw-DV-A2f\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-230\" y=\"-291.5\"/>\n        </window>\n        <menuItem title=\"Reload\" id=\"zJ0-Jr-CmZ\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <connections>\n                <action selector=\"reloadWithSender:\" target=\"Voe-Tx-rLC\" id=\"lwD-b1-IGA\"/>\n            </connections>\n        </menuItem>\n        <window title=\"Find\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" hidesOnDeactivate=\"YES\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"A2I-eS-piB\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" utility=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"132\" width=\"304\" height=\"42\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1177\"/>\n            <view key=\"contentView\" misplaced=\"YES\" id=\"VUZ-zJ-xWR\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"304\" height=\"42\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"cpj-R8-vCt\">\n                        <rect key=\"frame\" x=\"46\" y=\"10\" width=\"96\" height=\"22\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"2V0-ke-led\">\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                        <connections>\n                            <action selector=\"performClick:\" target=\"qz6-LG-DWp\" id=\"M27-D9-nWM\"/>\n                        </connections>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"Thy-91-Pbc\">\n                        <rect key=\"frame\" x=\"8\" y=\"13\" width=\"34\" height=\"17\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Find:\" id=\"iVO-hr-Fxk\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button toolTip=\"Find next\" verticalHuggingPriority=\"750\" misplaced=\"YES\" tag=\"2\" id=\"qz6-LG-DWp\">\n                        <rect key=\"frame\" x=\"143\" y=\"4\" width=\"83\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"In File..\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"VTy-fC-trt\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"findInSourceWithSender:\" target=\"Voe-Tx-rLC\" id=\"UYi-Sb-cld\"/>\n                        </connections>\n                    </button>\n                    <button toolTip=\"grep through project Symbols using a regex\" verticalHuggingPriority=\"750\" misplaced=\"YES\" id=\"fa0-Zh-DT5\">\n                        <rect key=\"frame\" x=\"219\" y=\"4\" width=\"83\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Project\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"rp5-Z9-4T0\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"searchProjectWithSender:\" target=\"Voe-Tx-rLC\" id=\"oz2-BR-lIG\"/>\n                        </connections>\n                    </button>\n                </subviews>\n            </view>\n            <point key=\"canvasLocation\" x=\"-142\" y=\"246\"/>\n        </window>\n        <menuItem title=\"Forward\" keyEquivalent=\"]\" id=\"rZ9-vB-ZMx\">\n            <connections>\n                <action selector=\"forwardWithSender:\" target=\"Voe-Tx-rLC\" id=\"DUY-3P-KZX\"/>\n            </connections>\n        </menuItem>\n        <menuItem title=\"Search USRs\" toolTip=\"Search project for USRs matching selection\" id=\"kWr-TP-7Pz\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <connections>\n                <action selector=\"searchSelectionWithSender:\" target=\"Voe-Tx-rLC\" id=\"ZFB-Uh-Dt1\"/>\n            </connections>\n        </menuItem>\n        <menuItem title=\"Search USRs\" toolTip=\"Search project for USRs matching selection\" id=\"iD6-4l-Ufq\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <connections>\n                <action selector=\"searchSelectionWithSender:\" target=\"Voe-Tx-rLC\" id=\"gqS-Mf-gXB\"/>\n            </connections>\n        </menuItem>\n        <menuItem title=\"Dependencies\" toolTip=\"Search project for USRs matching selection\" id=\"T6k-0J-mIM\" userLabel=\"Dependencies\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <connections>\n                <action selector=\"findDependenciesWithSender:\" target=\"Voe-Tx-rLC\" id=\"bxb-5V-J0Q\"/>\n            </connections>\n        </menuItem>\n        <customObject id=\"nF1-TD-e5Y\" customClass=\"AppController\" customModule=\"Injection\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"backItem\" destination=\"tq0-Xd-Lwk\" id=\"bGs-XU-SEQ\"/>\n                <outlet property=\"changesView\" destination=\"Kfe-Ht-0tr\" id=\"Pci-C5-kAq\"/>\n                <outlet property=\"dependsItem\" destination=\"T6k-0J-mIM\" id=\"paB-69-x0Y\"/>\n                <outlet property=\"findText\" destination=\"cpj-R8-vCt\" id=\"aFk-nw-QAW\"/>\n                <outlet property=\"forwardItem\" destination=\"rZ9-vB-ZMx\" id=\"HsK-1X-VsG\"/>\n                <outlet property=\"reloadItem\" destination=\"zJ0-Jr-CmZ\" id=\"8Gs-yO-6CK\"/>\n                <outlet property=\"replacement\" destination=\"hvb-Q7-aD4\" id=\"2cv-HW-epU\"/>\n                <outlet property=\"searchItem\" destination=\"kWr-TP-7Pz\" id=\"4c1-Zd-Slh\"/>\n                <outlet property=\"sourceView\" destination=\"hoP-PD-VYj\" id=\"aCi-kN-Hfe\"/>\n                <outlet property=\"window\" destination=\"QvC-M9-y7g\" id=\"lsx-29-EL8\"/>\n            </connections>\n        </customObject>\n        <menuItem title=\"Back\" id=\"tq0-Xd-Lwk\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <menu key=\"submenu\" title=\"Back\" id=\"14n-z9-aqj\"/>\n            <connections>\n                <action selector=\"backEntitiesWithSender:\" target=\"Voe-Tx-rLC\" id=\"ntF-lD-c1N\"/>\n            </connections>\n        </menuItem>\n    </objects>\n</document>\n"
  },
  {
    "path": "Refactorator/Common.swift",
    "content": "//\n//  Common.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 18/12/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\nimport Foundation\n\nvar xcode: AppLogging!\n\nprotocol AppLogging {\n    func log( _ msg: String )\n    func error( _ msg: String )\n}\n\nfunc htmlEscape( _ str: String? ) -> String {\n    if let str = str {\n        return str.contains(\"<\") || str.contains(\"&\") ?\n            str.replacingOccurrences(of: \"&\", with: \"&amp;\")\n                .replacingOccurrences(of: \"<\", with: \"&lt;\") : str\n    }\n    return \"nil\"\n}\n\nextension Process {\n\n    @discardableResult\n    class func run(path: String, args: [String]) -> Int32 {\n        let task = Process()\n        task.launchPath = path\n        task.arguments = args\n        task.launch()\n        task.waitUntilExit()\n        return task.terminationStatus\n    }\n\n}\n\nextension DispatchGroup {\n\n    class func inParallel<T>( work: [T], workers: Int = 4,\n                          processor: @escaping (T, @escaping (() -> Void) -> Void) -> Void ) {\n        let threadPool = DispatchGroup()\n        let lock = NSLock()\n        func locked<L>( block: () -> L ) -> L {\n            lock.lock()\n            let ret = block()\n            lock.unlock()\n            return ret\n        }\n\n        var work = work\n        for _ in 0..<workers {\n            threadPool.enter()\n            DispatchQueue.global().async {\n                while let next = locked( block: {\n                    () -> T? in\n                    return !work.isEmpty ? work.removeFirst() : nil\n                } ) {\n                    processor( next, locked )\n                }\n\n                threadPool.leave()\n            }\n        }\n\n        threadPool.wait()\n    }\n\n}\n"
  },
  {
    "path": "Refactorator/Coverage.swift",
    "content": "//\n//  Coverage.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 03/03/2017.\n//  Copyright © 2017 John Holdsworth. All rights reserved.\n//\n\nimport Foundation\n\nclass Coverage {\n\n    let covered: Set<Int>\n\n    init?( file: String, project: Project ) {\n        let coverageFile = project.derivedData.url\n            .appendingPathComponent(\"Build/Intermediates/CodeCoverage/Coverage.profdata\").path\n        if !FileManager.default.fileExists(atPath: coverageFile) {\n            return nil\n        }\n\n        let task = Process()\n        task.launchPath = Bundle.main.path(forResource: \"coverage\", ofType: \".rb\")\n        task.arguments = [coverageFile, file]\n\n        let output = Pipe()\n        task.standardOutput = output.fileHandleForWriting\n        task.launch()\n        output.fileHandleForWriting.closeFile()\n\n        let data = output.fileHandleForReading.readDataToEndOfFile()\n        task.waitUntilExit()\n\n        if let coverage = String(data: data, encoding: .utf8) {\n            covered = Set<Int>( coverage.components(separatedBy: \"\\n\").map { Int($0, radix:10) ?? -1 } )\n        }\n        else {\n            return nil\n        }\n    }\n\n}\n"
  },
  {
    "path": "Refactorator/Credits.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;\\f1\\fnil\\fcharset0 LucidaGrande;\\f2\\fnil\\fcharset0 Menlo-Regular;\n\\f3\\fnil\\fcharset0 HelveticaNeue;\\f4\\fmodern\\fcharset0 Courier;}\n{\\colortbl;\\red255\\green255\\blue255;\\red83\\green98\\blue108;}\n\\paperw11900\\paperh16840\\vieww9600\\viewh8400\\viewkind0\n\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\partightenfactor0\n\n\\f0\\fs24 \\cf0 Refactorator is a user interface to an Xcode project's SQLite index database that allows you to rename identifiers that have a \"Unified Symbol Reference\" i.e. types, variables, ivars, functions & enum cases. For local variables use \"Edit All in Scope\". \\\n\\\nWhenever you launch Refactorator it communicates with Xcode through it's Apple Script API (see Xcode.h in the app bundle) to determine the current source file, topmost workspace and selection. It also uses this to locate the index database in \"DerivedData\".\\\n\\\nTo rename the selected symbol, enter a new name into the text field in the middle of the display and click the \"\n\\b Apply\n\\b0 \" button or press enter. If the changes look OK, use the \"\n\\b Save\n\\b0 \" button to save them to disk then click the the \"\n\\b Check Build\n\\b0 \" button to make sure your project still builds.\\\n\\\nIf the project no longer builds use the \"\n\\b Revert\n\\b0 \" button to undo all changes in the current session.\\\n\\\nRefactorator is designed to be used as a macOS service which is installed when you first run the application. To enable it go to \"\n\\b Keyboard/Shortcuts/Services\n\\b0 \" in the System Preferences app and enable the \"Refactorator\" and \"Refactor File\" services. After this you should be able to refactor from Xcode by selecting an identifier and typing \n\\f1 \\uc0\\u8984 \n\\f0 -~ (cmd-tilde) or by using the right-click context menu under \"Services\" or direct from Finder.\\\n\\\nIt can also be used as a source browser. Clicking on a symbol in top half of the screen will list the places it is used in the application while clicking on a symbol in the bottom half of the screen will load that source into the source viewer. \n\\f1 \\uc0\\u8984  \n\\f0 clicking should take you to the definition. There are a couple of other features where you can search a project for specific text in a symbol USR or locate all symbols declared but not referenced in the code. \\\n\\\nRefactorator's ability to correctly find all occurrences of a symbol in a program is dependent on the quality of the index db which could be described as \"generally complete\" but it does sometimes get out of sync and you may have to manually fix errors at times. If you're having trouble, rebuild the project, test the project and then use the menu item \"File/Force Re-index\" to touch all Swift files in your project to force a complete re-index.\\\n\\\nIf you're not keen how Refactorator looks, change the CSS styling in the file \"Source.html\" in the the app bundle. Feel free to send me an update!\\\n\\\nFor further help go to {\\field{\\*\\fldinst{HYPERLINK \"http://johnholdsworth.com/refactorator.html\"}}{\\fldrslt http://johnholdsworth.com/refactorator.html}}\\\n\\\n\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\pardirnatural\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Copyright (C) 2016 John Holdsworth {\\field{\\*\\fldinst{HYPERLINK \"mailto:refactorator@johnholdsworth.com\"}}{\\fldrslt refactorator@johnholdsworth.com}} {\\field{\\*\\fldinst{HYPERLINK \"https://twitter.com/Injection4Xcode\"}}{\\fldrslt \n\\f3\\fs24 \\cf2 \\expnd0\\expndtw0\\kerning0\n@Injection4Xcode}}\\\n\\\n\\pard\\pardeftab720\\partightenfactor0\n\n\\f4\\fs24 \\cf0 \\expnd0\\expndtw0\\kerning0\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \\\ndocumentation files (the \"Software\"), to deal in the Software without restriction, including without limitation \\\nthe rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, \\\nand to permit persons to whom the Software is furnished to do so, subject to the following conditions:\\\n\\\nThe above copyright notice and this permission notice shall be included in all copies or substantial \\\nportions of the Software.\\\n\\\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \\\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \\\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \\\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE \\\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\\\n\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\pardirnatural\\partightenfactor0\n\n\\f2\\fs22 \\cf0 \\kerning1\\expnd0\\expndtw0 .\\\n}"
  },
  {
    "path": "Refactorator/Formatter.swift",
    "content": "//\n//  Formatter.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 13/12/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\nimport Foundation\nimport WebKit\n\nprotocol AppGui: AppLogging {\n\n    var project: Project? { get }\n    func sourceHTML() -> String\n    func setChangesSource( header: String?, target: Entity?, isApply: Bool )\n    func appendSource( title: String, text: String )\n    func relative( _ path: String ) -> String\n    func open( url: String )\n\n}\n\nclass Formatter {\n\n    static let sourceKit = SourceKit()\n\n    var maps = [String:(mtime: TimeInterval, resp: sourcekitd_response_t)]()\n    let newline = CChar(\"\\n\".utf16.last!)\n\n    func htmlFor( path: String, data: NSData, entities: [Entity]? = nil, skew: Int = 0, selecting: Entity? = nil, cascade: Bool = true, shortform: Bool = false, cleanPath: String? = nil, coverage: Set<Int>? = nil,\n                  linker: @escaping (_ text: String, _ entity: Entity?) -> String = {\n        (_ text: String, _ entity: Entity?) -> String in\n        return text\n        } ) -> [String] {\n\n        var ptr = 0, skewtotal = 0, line = 1, col = 1, entityNumber = 0, html = \"\"\n        let sourceBytes = data.bytes.assumingMemoryBound(to: CChar.self)\n\n        func skipTo( offset: Int ) -> (text: String, entity: Entity?) {\n            if offset <= ptr {\n                return (\"\", nil)\n            }\n\n            let selectedByOffset = ptr == selecting?.offset\n            var offset = offset + skewtotal\n            var currentEntity: Entity?\n\n            if let entities = entities, entityNumber < entities.count {\n                var entity = entities[entityNumber]\n                while (entity.line < line || entity.line == line && entity.col < col) && entityNumber + 1 < entities.count {\n                    //                    xcode.log(\"Missed entity \\(entity.line):\\(entity.col) < \\(line):\\(col) \\(entity.usr) - \\(path)\")\n                    entityNumber += 1\n                    entity = entities[entityNumber]\n                }\n                if entity.line == line && entity.col == col || entity.offset == ptr+skewtotal {\n                    //                    xcode.log(\"entity \\(entity.line):\\(entity.col) == \\(line):\\(col) \\(entity.usr) - \\(path)\")\n                    currentEntity = entity\n                    entityNumber += 1\n                    if !entity.notMatch {\n                        offset += skew\n                    }\n                }\n            }\n\n            let out = NSString( bytes: sourceBytes+ptr+skewtotal,\n                                length: offset-(ptr+skewtotal),\n                                encoding: String.Encoding.utf8.rawValue ) ??\n                NSString( bytes: sourceBytes+ptr+skewtotal,\n                          length: offset-(ptr+skewtotal),\n                          encoding: String.Encoding.isoLatin1.rawValue ) ??\n                \"?\\(ptr+skewtotal)?\\(offset-(ptr+skewtotal))?\" as NSString\n\n            while ptr+skewtotal < offset {\n                if sourceBytes[ptr+skewtotal] == newline {\n                    line += 1\n                    col = 1\n                }\n                else {\n                    col += 1\n                }\n                ptr += 1\n            }\n\n            if currentEntity?.notMatch == false {\n                skewtotal += skew\n                ptr -= skew\n            }\n            //            ptr = offset-skews\n\n            var escaped = htmlEscape( out as String )\n            if currentEntity?.decl == true {\n                escaped = \"<span class=declaration>\\(escaped)</span>\"\n            }\n            if selectedByOffset || currentEntity != nil && (currentEntity == selecting || selecting == nil) {\n                escaped = \"<span class=highlighted id=selected cascade=\\(cascade ? 1 : 0)>\\(escaped)</span>\"\n            }\n\n            return (escaped, currentEntity)\n        }\n\n        isTTY = false\n\n        let sourceKit = Formatter.sourceKit\n        let cleanPath = cleanPath ?? path\n        let modified = mtime( path )\n        let resp = (modified == maps[path]?.mtime ? maps[path]?.resp : nil) ?? sourceKit.syntaxMap(filePath: path)\n        maps[path] = (modified,resp)\n\n        var extensions = [String:String]()\n\n        let dict = SKApi.sourcekitd_response_get_value( resp )\n        let map = SKApi.sourcekitd_variant_dictionary_get_value( dict, sourceKit.syntaxID )\n        _ = SKApi.sourcekitd_variant_array_apply( map ) { (_,dict) in\n            let kind = dict.getUUIDString( key: sourceKit.kindID )\n            let offset = dict.getInt( key: sourceKit.offsetID )\n            let length = dict.getInt( key: sourceKit.lengthID )\n            let kindSuffix = extensions[kind] ?? kind.url.pathExtension\n            if extensions[kind] == nil {\n                extensions[kind] = kindSuffix\n            }\n\n            html += skipTo( offset: offset ).text\n\n            var span = \"<span\"\n            if !shortform {\n                span += \" line=\\(line) col=\\(col) offset=\\(ptr) title=\\\"\\(cleanPath)#\\(line):\\(col)\"\n            }\n\n            var (text, entity) = skipTo( offset: offset+length )\n            let type = entity != nil ? \"Xc\\(entity!.kindSuffix) \" : \"\"\n            let usr = entity?.usr != nil ? htmlEscape( demangle( entity!.usr! ) ) : \"\"\n\n            if !shortform {\n                span += \" \\(usr) \\(entity?.kind ?? \"\") \\(entity?.role ?? -1)\\\"\"\n            }\n\n            span += \" class='\\(type)\\(kindSuffix)' entity=\\(entity != nil || entities == nil ? 1 : 0)>\"\n\n            if kindSuffix == \"url\" {\n                text = \"<a href=\\\"\\(text)\\\">\\(text)</a>\"\n            }\n            html += \"\\(span)\\(linker(text, entity))</span>\"\n\n            return true\n        }\n\n        html += skipTo( offset: data.length-skewtotal ).0\n\n        var lineno = 0\n        let lines = html.components(separatedBy: \"\\n\").map {\n            (line) -> String in\n            lineno += 1\n            var classes = \"linenumber\"\n            if coverage?.contains(lineno) == true {\n                classes += \" covered\"\n            }\n            return String(format:\"<span class='\\(classes)' id=L\\(lineno)>%04d&nbsp;</span>\", lineno)+line+\"\\n\"\n        }\n        \n        return lines\n    }\n\n    func htmlFile(_ state: AppGui, _ path: String ) -> String {\n        return state.relative( path ).replacingOccurrences(of: \"/\", with: \"_\") + \".html\"\n    }\n\n    func buildSite( for project: Project, into htmlDir: String, state: AppGui ) {\n        state.setChangesSource(header: \"Building source site into \\(htmlDir)\", target: nil, isApply: false)\n\n        try? FileManager.default.createDirectory(atPath: htmlDir, withIntermediateDirectories: false, attributes: nil)\n        if var entiesForFiles = project.indexDB?.projectEntities() {\n            var referencesByUSR = [Int:[Entity]]()\n            var declarationsByUSR = [Int:Entity]()\n\n            var dataByFile = [String:NSData]()\n            var linesByFile = [String:[String]]()\n\n            for entities in entiesForFiles {\n                for entity in entities {\n                    if let usrID = entity.usrID {\n                        if referencesByUSR[usrID] == nil {\n                            referencesByUSR[usrID] = [Entity]()\n                        }\n                        referencesByUSR[usrID]!.append(entity)\n                        if entity.decl {\n                            declarationsByUSR[usrID] = entity\n                        }\n                    }\n                }\n            }\n\n            DispatchGroup.inParallel(work: entiesForFiles) {\n                (entities, locked) in\n                let path = entities[0].file\n                let data = NSData(contentsOfFile: path) ?? NSData()\n                let html = self.htmlFor(path: path, data: data, entities: entities, shortform: true)\n                locked {\n                    dataByFile[path] = data\n                    linesByFile[path] = html\n                }\n            }\n\n            for (usrID, _) in referencesByUSR {\n                referencesByUSR[usrID]!.sort { $0.0 < $0.1 }\n            }\n\n            func href( _ entity: Entity ) -> String {\n                return \"\\(htmlFile(state, entity.file))#L\\(entity.line)\"\n            }\n\n            let common = state.sourceHTML()\n\n            DispatchGroup.inParallel(work: entiesForFiles) {\n                (entities, locked) in\n                let path = entities[0].file\n                let out = common + self.htmlFor(path: path, data: dataByFile[path]!, entities: entities, selecting: Entity(file:\"\"), cleanPath: state.relative(path) ) {\n                    (text, entity) -> String in\n                    var text = text\n                    if let entity = entity,\n                        let decl = declarationsByUSR[entity.usrID!],\n                        let related = referencesByUSR[entity.usrID!] {\n                        if related.count > 1 {\n                            if entity.decl || state.project?.indexDB?.podDirIDs[entity.dirID] == nil {\n                                var popup = \"\"\n                                for ref in related {\n                                    if ref == entity {\n                                        continue\n                                    }\n                                    let keepListOpen = ref.file != decl.file ? \"event.stopPropagation(); \" : \"\"\n                                    popup += \"<tr\\(ref == decl ? \" class=decl\" : \"\")><td style='text-decoration: underline;' \" +\n                                    \"onclick='document.location.href=\\\"\\(href(ref))\\\"; \\(keepListOpen)return false;'>\\(ref.file.url.lastPathComponent)</td>\"\n                                    let lines = linesByFile[ref.file] ?? []\n                                    let reference = ref.line < lines.count ? lines[ref.line-1] : \"\"\n                                    popup += \"<td><pre>\\(reference.replacingOccurrences(of: \"\\n\", with: \"\"))</pre></td>\"\n                                }\n                                text = \"<a style='color: inherit' name='L\\(entity.line)' href='\\(href(decl))' target=_self onclick='return expand(this, event.metaKey);'>\" +\n                                \"\\(text)<span class='references'><table>\\(popup)</table></span></a>\"\n                            }\n                            else {\n                                text = \"<a style='color: inherit' href='\\(href(decl))'>\\(text)</a>\"\n                            }\n                        }\n                        else if entity.decl == true {\n                            text = \"<a style='color: inherit' name='L\\(entity.line)' no_href='\\(href(decl))'>\\(text)</a>\"\n                        }\n                    }\n                    return text\n                    }.joined()\n\n                let final = htmlDir.url.appendingPathComponent(self.htmlFile(state, path))\n                do {\n                    try out.write(to: final, atomically: false, encoding: .utf8)\n                    DispatchQueue.main.async {\n                        state.appendSource(title: \"\", text: \"Wrote <a href=\\\"file://\\(final.path)\\\">\\(final.path)</a>\\n\")\n                    }\n                }\n                catch (let e) {\n                    print(\"Could not save to \\(final): \\(e)\")\n                }\n            }\n\n            do {\n                let workspace = state.project?.workspaceName ?? \"unknown\"\n                var sources = common+\"</pre><div class=filelist><h2>Sources for Project \\(workspace)</h2><script> document.title = 'Sources for Project \\(workspace)' </script>\"\n                \n                for entities in entiesForFiles.sorted(by: { $0.0[0].file < $0.1[0].file }) {\n                    let path =  entities[0].file\n                    sources += \"<a href='\\(htmlFile(state, path))'>\\(state.relative(path))</a><br>\"\n                }\n                \n                sources += \"<p>Cross Reference can be found <a href='xref.html'>here</a>.\"\n                sources += \"<p>Dependencies Graph can be found <a href='canviz.html'>here</a>.\"\n                let index = htmlDir+\"index.html\"\n                try sources.write(toFile: index, atomically: false, encoding: .utf8)\n                DispatchQueue.main.async {\n                    state.appendSource(title: \"\", text: \"Wrote <a href=\\\"file://\\(index)\\\">\\(index)</a>\\n\")\n                }\n\n                sources = common+\"</pre><div class=filelist><h2>Symbols defined in \\(workspace)</h2><script> document.title = 'Symbols defined in \\(workspace)' </script>\"\n                \n                for entity in declarationsByUSR.values.sorted(by: {demangle($0.0.usr)! < demangle($0.1.usr)!}) {\n                    sources += \"<a href='\\(href(entity))'>\\(htmlEscape( demangle(entity.usr) ))</a><br>\"\n                }\n                \n                let xref = htmlDir+\"xref.html\"\n                try sources.write(toFile: xref, atomically: false, encoding: .utf8)\n                DispatchQueue.main.async {\n                    state.appendSource(title: \"\", text: \"Wrote <a href=\\\"file://\\(xref)\\\">\\(xref)</a>\\n\")\n                }\n\n                state.open(url: index)\n\n                runDepends(state: state, standalone: true)\n\n                let dotFile = htmlDir+\"refactorator.gv\"\n                try? FileManager.default.removeItem(atPath: dotFile)\n                try FileManager.default.copyItem(atPath: gvfile, toPath: dotFile)\n\n                let canviz = Bundle.main.path(forResource: \"canviz-0.1\", ofType: nil)!\n                try? FileManager.default.copyItem(atPath: canviz, toPath: htmlDir+\"canviz-0.1\")\n\n                let canviz2 = Bundle.main.path(forResource: \"canviz2\", ofType: \"html\")!\n                try? FileManager.default.removeItem(atPath: htmlDir+\"canviz.html\")\n                try FileManager.default.copyItem(atPath: canviz2, toPath: htmlDir+\"canviz.html\")\n            }\n            catch (let e) {\n                state.error( \"Error building site: \\(e)\")\n            }\n        }\n    }\n\n    var DOT_PATH = \"/usr/local/bin/dot\"\n    var gvfile: String {\n        return \"/tmp/canviz.gv\"\n    }\n\n    func runDepends( state: AppGui, standalone: Bool ) {\n        var nodeID = 0, nodes = [String:Int]()\n        var dot = \"digraph xref {\\n    node [fontname=\\\"Arial\\\"];\\n\"\n        func defineNode( _ path: String ) -> String {\n            if nodes[path] == nil {\n                nodeID += 1\n                nodes[path] = nodeID\n                let label = path.hasSuffix(\".swift\") ?\n                    path.url.deletingPathExtension().lastPathComponent : path.url.lastPathComponent\n                dot += \"N\\(nodeID) [href=\\\"javascript:void(click_node('\\(standalone ? htmlFile(state, path) : path)'))\\\" \" +\n                    \"label=\\\"\\(label)\\\" tooltip=\\\"\\(state.relative(path))\\\"];\\n\"\n            }\n            return \"N\\(nodes[path]!)\"\n        }\n\n        for (to, from, count) in state.project!.indexDB!.dependencies() {\n            dot += \"    \\(defineNode( from )) -> \\(defineNode( to )) [penwidth=\\(log10(Double(count)))]\\n\"\n        }\n\n        dot += \"}\\n\"\n\n        let dotfile = \"/tmp/refactorator.dot\"\n        try? dot.write(toFile: dotfile, atomically: false, encoding: .utf8)\n\n        Process.run(path: DOT_PATH, args: [dotfile, \"-Txdot\", \"-o\"+gvfile])\n    }\n\n    func indexAssociations( filePath: String, state: AppGui ) {\n\n        let logDir = state.project!.derivedData+\"/Logs/Build\"\n        let xcodeBuildLogs = LogParser( logDir: logDir )\n\n        guard let argv = xcodeBuildLogs.compilerArgumentsMatching( matcher: { line in\n            line.contains( \" -primary-file \\(filePath) \" ) ||\n                line.contains( \" -primary-file \\\"\\(filePath)\\\" \" ) } ) else {\n                    xcode.error( \"Could not find compiler arguments in \\(logDir). Have you built all files in the project?\" )\n                    return\n        }\n\n        state.setChangesSource(header: \"Re-indexing to capture associations between USRs\", target: nil, isApply: false)\n\n        DispatchQueue.global().async {\n            let SK = Formatter.sourceKit\n            var relatedUSRs = \"\", count = 0\n            let files = argv.filter { $0.hasSuffix( \".swift\" ) }\n            let notRelated = \"^source\\\\.lang\\\\.swift\\\\.decl\\\\.(extension\\\\.)?(class|struct|enum|protocol)$\"\n            let regexp = try! NSRegularExpression(pattern: notRelated, options: [])\n\n            DispatchGroup.inParallel(work: files ) {\n                (file, locked) in\n                DispatchQueue.main.async {\n                    state.appendSource(title: \"\", text: \"Indexing \\(file)\\n\")\n                }\n\n                var fileRelatedUSRs = [String]()\n                let resp = SK.indexFile( filePath: file, compilerArgs: SK.array( argv: argv ) )\n//                SKApi.sourcekitd_response_description_dump( resp )\n\n                SK.recurseOver( childID: SK.entitiesID, resp: SKApi.sourcekitd_response_get_value( resp ) ) {\n                    (entity) in\n                    let related = SKApi.sourcekitd_variant_dictionary_get_value( entity, SK.relatedID )\n                    if SKApi.sourcekitd_variant_get_type( related ) == SOURCEKITD_VARIANT_TYPE_ARRAY {\n                        let kind = entity.getUUIDString(key: SK.kindID )\n                        if regexp.firstMatch(in: kind, options: [], range: NSMakeRange(0, kind.utf16.count)) == nil,\n                            let usr = entity.getString(key: SK.usrID) {\n                            _ = SKApi.sourcekitd_variant_array_apply( related ) {\n                                (_,dict) in\n                                if let usr2 = dict.getString(key: SK.usrID) {\n                                    fileRelatedUSRs.append( \"\\(usr)\\t\\(usr2)\\n\" )\n                                }\n                                return true\n                            }\n                        }\n                    }\n                }\n\n                SKApi.sourcekitd_response_dispose( resp )\n\n                let entry = \"\\(mtime(file))\\t\\(file)\\n\"+fileRelatedUSRs.joined()\n                print( entry )\n\n                if fileRelatedUSRs.count != 0 {\n                    locked {\n                        relatedUSRs += entry\n                        count += fileRelatedUSRs.count\n                    }\n                }\n            }\n\n            if let relatedsPath = state.project?.indexDB?.relatedsDB {\n                try? relatedUSRs.write(toFile: relatedsPath, atomically: true, encoding: .utf8)\n            }\n\n            DispatchQueue.main.async {\n                state.appendSource(title: \"\", text: \"\\n<b>Indexing complete. \\(count) associations found in \\(files.count) files.</b>\\n\")\n            }\n        }\n    }\n\n    deinit {\n        for (_, entry) in maps {\n            SKApi.sourcekitd_request_release(entry.resp)\n        }\n    }\n\n}\n"
  },
  {
    "path": "Refactorator/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>App.icns</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.7</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>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016 John Holdsworth. 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\t<key>NSServices</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSKeyEquivalent</key>\n\t\t\t<dict>\n\t\t\t\t<key>default</key>\n\t\t\t\t<string>~</string>\n\t\t\t</dict>\n\t\t\t<key>NSMenuItem</key>\n\t\t\t<dict>\n\t\t\t\t<key>default</key>\n\t\t\t\t<string>Refactorator/Refactorator</string>\n\t\t\t</dict>\n\t\t\t<key>NSMessage</key>\n\t\t\t<string>refactorator</string>\n\t\t\t<key>NSPortName</key>\n\t\t\t<string>Refactorator</string>\n\t\t\t<key>NSSendTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>NSStringPboardType</string>\n\t\t\t\t<string>public.plain-text</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSMenuItem</key>\n\t\t\t<dict>\n\t\t\t\t<key>default</key>\n\t\t\t\t<string>Refactorator/Refactor File</string>\n\t\t\t</dict>\n\t\t\t<key>NSMessage</key>\n\t\t\t<string>refactorFile</string>\n\t\t\t<key>NSPortName</key>\n\t\t\t<string>Refactorator</string>\n\t\t\t<key>NSRequiredContext</key>\n\t\t\t<dict>\n\t\t\t\t<key>NSTextContent</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>FilePath</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t\t<key>NSSendTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>NSStringPboardType</string>\n\t\t\t\t<string>public.plain-text</string>\n\t\t\t\t<string>NSURLPboardType</string>\n\t\t\t\t<string>public.url</string>\n\t\t\t\t<string>public.file-url</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>swift</string>\n\t\t\t\t<string>m</string>\n\t\t\t\t<string>h</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeIconFile</key>\n\t\t\t<string>document.icns</string>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/css</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>Swift Source</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>AppDelegate</string>\n\t\t</dict>\n\t</array>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Refactorator/Integration.swift",
    "content": "//\n//  SubApp.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 21/12/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\nimport Foundation\n\nclass Integration {\n\n    init(appDelegate: AppDelegate, count: Int) {\n        if count % 10 == 0 {\n            DispatchQueue.global().async {\n                func appVersion( from dict: [String: Any]? ) -> Double? {\n                    return dict == nil ? -1 : (dict?[\"CFBundleShortVersionString\"] as AnyObject).doubleValue\n                }\n                let localVersion = appVersion(from: Bundle.main.infoDictionary)!\n                let url = \"https://raw.githubusercontent.com/johnno1962/RefactoratorApp/master/Refactorator/Info.plist\"\n                let currentVersion = appVersion(from: NSDictionary(contentsOf: URL(string: url)!) as? [String: Any])\n                if currentVersion != nil && currentVersion! > localVersion {\n                    DispatchQueue.main.async {\n                        let alert = NSAlert()\n                        alert.messageText = \"Refactorator\"\n                        alert.informativeText = \"An update is available for Refactorator, please download a new copy\"\n                        alert.runModal()\n                        appDelegate.help(sender: nil)\n                    }\n                }\n            }\n        }\n\n        if appDelegate.state.project == nil {\n            appDelegate.state.setup()\n        }\n    }\n\n}\n\nextension AppDelegate {\n\n    @IBAction func help(sender: NSMenuItem!) {\n        state.open(url: \"http://johnholdsworth.com/refactorator.html?index=\\(myIndex)\")\n    }\n\n    @IBAction func donate(sender: NSMenuItem!) {\n        state.open(url: \"http://johnholdsworth.com/cgi-bin/refactorator.cgi?index=\\(myIndex)\")\n    }\n\n}\n\nlet colors = String(data: Data(base64Encoded: \"QWxpY2VCbHVlOkFudGlxdWVXaGl0ZTpBcXVhOkFxdWFtYXJpbmU6QXp1cmU6QmVpZ2U6QmlzcXVlOkJsYWNrOkJsYW5jaGVkQWxtb25kOkJsdWU6Qmx1ZVZpb2xldDpCcm93bjpCdXJseVdvb2Q6Q2FkZXRCbHVlOkNoYXJ0cmV1c2U6Q2hvY29sYXRlOkNvcmFsOkNvcm5mbG93ZXJCbHVlOkNvcm5zaWxrOkNyaW1zb246Q3lhbjpEYXJrQmx1ZTpEYXJrQ3lhbjpEYXJrR29sZGVuUm9kOkRhcmtHcmF5OkRhcmtHcmV5OkRhcmtHcmVlbjpEYXJrS2hha2k6RGFya01hZ2VudGE6RGFya09saXZlR3JlZW46RGFya09yYW5nZTpEYXJrT3JjaGlkOkRhcmtSZWQ6RGFya1NhbG1vbjpEYXJrU2VhR3JlZW46RGFya1NsYXRlQmx1ZTpEYXJrU2xhdGVHcmF5OkRhcmtTbGF0ZUdyZXk6RGFya1R1cnF1b2lzZTpEYXJrVmlvbGV0OkRlZXBQaW5rOkRlZXBTa3lCbHVlOkRpbUdyYXk6RGltR3JleTpEb2RnZXJCbHVlOkZpcmVCcmljazpGbG9yYWxXaGl0ZTpGb3Jlc3RHcmVlbjpGdWNoc2lhOkdhaW5zYm9ybzpHaG9zdFdoaXRlOkdvbGQ6R29sZGVuUm9kOkdyYXk6R3JleTpHcmVlbjpHcmVlblllbGxvdzpIb25leURldzpIb3RQaW5rOkluZGlhblJlZDpJbmRpZ286SXZvcnk6S2hha2k6TGF2ZW5kZXI6TGF2ZW5kZXJCbHVzaDpMYXduR3JlZW46TGVtb25DaGlmZm9uOkxpZ2h0Qmx1ZTpMaWdodENvcmFsOkxpZ2h0Q3lhbjpMaWdodEdvbGRlblJvZFllbGxvdzpMaWdodEdyYXk6TGlnaHRHcmV5OkxpZ2h0R3JlZW46TGlnaHRQaW5rOkxpZ2h0U2FsbW9uOkxpZ2h0U2VhR3JlZW46TGlnaHRTa3lCbHVlOkxpZ2h0U2xhdGVHcmF5OkxpZ2h0U2xhdGVHcmV5OkxpZ2h0U3RlZWxCbHVlOkxpZ2h0WWVsbG93OkxpbWU6TGltZUdyZWVuOkxpbmVuOk1hZ2VudGE6TWFyb29uOk1lZGl1bUFxdWFNYXJpbmU6TWVkaXVtQmx1ZTpNZWRpdW1PcmNoaWQ6TWVkaXVtUHVycGxlOk1lZGl1bVNlYUdyZWVuOk1lZGl1bVNsYXRlQmx1ZTpNZWRpdW1TcHJpbmdHcmVlbjpNZWRpdW1UdXJxdW9pc2U6TWVkaXVtVmlvbGV0UmVkOk1pZG5pZ2h0Qmx1ZTpNaW50Q3JlYW06TWlzdHlSb3NlOk1vY2Nhc2luOk5hdmFqb1doaXRlOk5hdnk6T2xkTGFjZTpPbGl2ZTpPbGl2ZURyYWI6T3JhbmdlOk9yYW5nZVJlZDpPcmNoaWQ6UGFsZUdvbGRlblJvZDpQYWxlR3JlZW46UGFsZVR1cnF1b2lzZTpQYWxlVmlvbGV0UmVkOlBhcGF5YVdoaXA6UGVhY2hQdWZmOlBlcnU6UGluazpQbHVtOlBvd2RlckJsdWU6UHVycGxlOlJlYmVjY2FQdXJwbGU6UmVkOlJvc3lCcm93bjpSb3lhbEJsdWU6U2FkZGxlQnJvd246U2FsbW9uOlNhbmR5QnJvd246U2VhR3JlZW46U2VhU2hlbGw6U2llbm5hOlNpbHZlcjpTa3lCbHVlOlNsYXRlQmx1ZTpTbGF0ZUdyYXk6U2xhdGVHcmV5OlNub3c6U3ByaW5nR3JlZW46U3RlZWxCbHVlOlRhbjpUZWFsOlRoaXN0bGU6VG9tYXRvOlR1cnF1b2lzZTpWaW9sZXQ6V2hlYXQ6V2hpdGU6V2hpdGVTbW9rZTpZZWxsb3c6WWVsbG93R3JlZW4=\")!, encoding: .utf8 )!.components(separatedBy: \":\")\n"
  },
  {
    "path": "Refactorator/Intro.html",
    "content": "<style> #source { font: Arial: 10pt !important; } </style><apan style='font: Arial: 10pt important!;'>\n    <b>Welcome to Refactorator</b>\n\n    You're viewing this file becaue refactorator Couldn't find an source document\n    being edited in the frontmost window of Xcode. Make sure Xcode is running and\n    you have a Swift or Objective-C source open.\n</div>\n"
  },
  {
    "path": "Refactorator/Project.swift",
    "content": "//\n//  Project.swift\n//  Refactorator\n//\n//  Created by John Holdsworth on 20/11/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\nimport Cocoa\n\nlet HOME = String( cString: getenv(\"HOME\") )\n\nclass Project: NSObject {\n\n    static var lastProject: Project?\n    static var unknown = \"unknown\"\n\n    var xCode: SBApplication?\n    var workspaceDoc: SBObject?\n\n    var workspacePath = unknown\n    var projectRoot = unknown\n    var derivedData = unknown\n    var indexPath = unknown\n    var indexDB: IndexDB?\n\n    var entity: Entity?\n\n    var workspaceName: String {\n        return workspacePath.url.lastPathComponent\n    }\n\n    static func openWorkspace( workspaceDoc: SBObject?, workspacePath: String, relative: Bool ) throws -> (String, String, String, IndexDB?) {\n        let workspaceURL = workspacePath.url\n        let projectRoot = workspaceURL.deletingLastPathComponent().path\n        let projectName = workspaceURL.deletingPathExtension().lastPathComponent\n        let derivedData = (relative ? projectRoot.url.appendingPathComponent(\"DerivedData\") :\n            HOME.url.appendingPathComponent(\"Library/Developer/Xcode/DerivedData\")).appendingPathComponent( projectName\n                .replacingOccurrences(of: \" \", with: \"_\") + (relative ? \"\" : \"-\" + Utils.hashString(forPath: workspacePath)) ).path\n\n        var indexPaths = [String]()\n        for config in try FileManager.default.contentsOfDirectory(atPath: derivedData+\"/Index\" ) {\n            let configPath = \"\\(derivedData)/Index/\\(config)\"\n            if configPath.url.hasDirectoryPath {\n                for platformArch in try FileManager.default.contentsOfDirectory(atPath: configPath) {\n                    indexPaths.append( \"\\(configPath)/\\(platformArch)\" )\n                }\n            }\n        }\n\n        let runDest = workspaceDoc?.activeRunDestination\n        func makeIndexPath( _ indexPath: String ) -> String {\n            return \"\\(indexPath)/\\(projectName).xcindex/db.xcindexdb\"\n        }\n\n        let platformArch = indexPaths.filter { $0.url.hasDirectoryPath && (runDest == nil ||\n            ($0.contains(runDest!.platform) && $0.hasSuffix(runDest!.architecture))) }.sorted(by: {\n            (a, b) in\n            return mtime( makeIndexPath( a )+\".strings-res\" ) > mtime( makeIndexPath( b )+\".strings-res\" )\n        } ).first\n\n//        if platformArch == nil {\n//            throw NSError(domain: \"Could not find an index db\", code: 0, userInfo: [\"DerivedData\":derivedData])\n//        }\n\n        let indexPath = platformArch != nil ? makeIndexPath( platformArch! ) : \"notfound\"\n        return (projectRoot, derivedData, indexPath, IndexDB(dbPath: indexPath))\n    }\n\n    static func findProject(for target: Entity) -> String? {\n        let manager = FileManager.default\n\n        func fileWithExtension( ext: String, in dirURL: URL ) throws -> String? {\n            for name in try manager.contentsOfDirectory(atPath: dirURL.path) {\n                if name.url.pathExtension == ext {\n                    return name\n                }\n            }\n            return nil\n        }\n\n        print(\"findProject for: \\(target.file)\")\n        for ext in [\"xcworkspace\", \"xcodeproj\"] {\n            var potentialRoot = target.file.url.deletingLastPathComponent()\n            do {\n                while potentialRoot.path != \"/\" {\n                    if let foundProject = try fileWithExtension(ext: ext, in: potentialRoot) {\n                        return potentialRoot.appendingPathComponent(foundProject).path\n                    }\n                    potentialRoot.deleteLastPathComponent()\n                }\n            }\n            catch {\n                xcode.error(\"Could not list directory \\(potentialRoot)\")\n            }\n        }\n\n        return nil\n    }\n\n    init(target: Entity?) {\n        xCode = SBApplication(bundleIdentifier:\"com.apple.dt.Xcode\")\n        IndexDB.projectDirs.removeAll()\n\n        if let xCode = xCode {\n            var workspaceDocs = [String:SBObject]()\n            for workspace in xCode.workspaceDocuments().map( { $0 as! SBObject } ) {\n                if let path = workspace.path {\n                    workspaceDocs[path] = workspace\n                }\n            }\n\n            let windows = xCode.windows().sorted(by: {\n                return ($0 as! SBObject).index < ($1 as! SBObject).index\n            }).filter { ($0 as! SBObject).document.path != nil }\n\n            for window in windows {\n                workspacePath = (window as! SBObject).document!.path\n                workspaceDoc = workspaceDocs[workspacePath]\n                do {\n                    (projectRoot, derivedData, indexPath, indexDB) =\n                        try Project.openWorkspace(workspaceDoc: workspaceDoc, workspacePath: workspacePath, relative: true)\n                    if target != nil ? IndexDB.projectIncludes(file: target!.file) : true {\n                        print(\"workspace: \\(workspacePath)\")\n                        break\n                    }\n                }\n                catch {\n                    do {\n                        (projectRoot, derivedData, indexPath, indexDB) =\n                            try Project.openWorkspace(workspaceDoc: workspaceDoc, workspacePath: workspacePath, relative: false)\n                        if target != nil ? IndexDB.projectIncludes(file: target!.file) : true {\n                            print(\"workspace: \\(workspacePath)\")\n                            break\n                        }\n                    }\n                    catch (let e) {\n                        xcode.log(\"Could not find indexDB for any open workspace docs \\(e)\")\n                    }\n                }\n            }\n\n            let relevantDoc = xCode.sourceDocuments().filter {\n                let sourceDoc = $0 as! SBObject, ext = sourceDoc.path?.url.pathExtension\n//                print(\"sourceDoc: \\(sourceDoc.path!)\")\n                return IndexDB.projectIncludes(file: sourceDoc.path) && sourceDoc.selectedCharacterRange != nil &&\n                    (ext == \"swift\" || ext == \"m\" || ext == \"mm\" || ext == \"c\" || ext == \"h\")\n            }.last\n\n            if let sourceDoc = relevantDoc as? SBObject {\n                print(\"relevantDoc: \\(sourceDoc.path!)\")\n                let sourcePath = sourceDoc.path.url.resolvingSymlinksInPath().path\n\n//                if let onDisk = try? String(contentsOfFile: sourceDoc.path, encoding: .utf8),\n//                    sourceDoc.text != onDisk {\n//                    print(sourceDoc.text)\n//                    try? sourceDoc.text.write(toFile: sourceDoc.path, atomically: false, encoding: .utf8)\n//                }\n\n                do {\n                    let sourceString = try NSString( contentsOfFile: sourcePath, encoding: String.Encoding.utf8.rawValue )\n                    let range = sourceDoc.selectedCharacterRange\n                    let sourceOffset = range == nil ? nil :\n                        sourceString.substring(with: NSMakeRange(0, range![0].intValue-1)).utf8.count\n\n                    entity = Entity( file: sourcePath, offset: sourceOffset )\n                }\n                catch (let e) {\n                    xcode.error( \"Could not load source \\(sourcePath) - \\(e)\" )\n                }\n            }\n        }\n\n        if target != nil && !IndexDB.projectIncludes(file: target!.file),\n            let alternate = Project.findProject(for: target!) {\n            workspacePath = alternate\n            workspaceDoc = nil\n            do {\n                (projectRoot, derivedData, indexPath, indexDB) =\n                    try Project.openWorkspace(workspaceDoc: workspaceDoc, workspacePath: workspacePath, relative: true)\n                print(\"alternate workspace: \\(workspacePath)\")\n            }\n            catch {\n                do {\n                    (projectRoot, derivedData, indexPath, indexDB) =\n                        try Project.openWorkspace(workspaceDoc: workspaceDoc, workspacePath: workspacePath, relative: false)\n                    print(\"alternate workspace: \\(workspacePath)\")\n                }\n                catch {\n                    xcode.error(\"Error finding indexDB for \\(workspacePath)\")\n                }\n            }\n        }\n\n        if indexDB == nil && Project.lastProject?.indexDB != nil, let previous = Project.lastProject {\n            (workspacePath, projectRoot, derivedData, indexPath, indexDB) =\n                (previous.workspacePath, previous.projectRoot, previous.derivedData,\n                 previous.indexPath, IndexDB(dbPath: previous.indexPath))\n        }\n\n        super.init()\n        Project.lastProject = self\n    }\n\n}\n"
  },
  {
    "path": "Refactorator/Refactorator-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 <sqlite3.h>\n#import <regex.h>\n\n#import \"sourcekitd.h\"\n#import \"Xcode.h\"\n\n#import \"Utils.h\"\n"
  },
  {
    "path": "Refactorator/Source.html",
    "content": "<html><head><meta charset=\"utf-8\"/><style>\n\nbody, table { font: 10pt Menlo Regular; }\n\n.builtin  { color: #A90D91; }\n.comment  { color: #10743E; }\n.url  { color: blue; }\n.doccomment { color: #10743E; }\n.identifier { color: #3F6E74; }\n.keyword { color: #AD0D91; }\n.number { color: #1D26E1; }\n.string { color: #CB444D; }\n.typeidentifier { color: #5C2599; }\n\n.XcAttention { }\n.XcBinding { }\n.XcBuiltinType { }\n.XcCallable { }\n.XcCategory { color: blue; }\n.XcClass { color: blue; }\n.XcClassMethod { color: darkgreen; }\n.XcClassMethodTemplate {  color: darkgreen; }\n.XcClassProperty { color: darkred; }\n.XcClassTemplate { color: blue; }\n.XcClassVariable { color: darkred; }\n.XcContainer { }\n.XcEnum { color: #e68a00; }\n.XcEnumConstant { color: #e68a00; }\n.XcExtension { color: cyan; }\n.XcField { color: darkred; }\n.XcFixMe {}\n.XcFunction { color: darkgreen; }\n.XcFunctionTemplate { color: darkgreen; }\n.XcGKInspectableProperty {}\n.XcGlobal { color: darkred; }\n.XcGlobalVariable { color: darkred; }\n.XcIBActionMethod { color: brown; }\n.XcIBOutlet { color: brown; }\n.XcIBOutletCollection { color: brown; }\n.XcIBOutletCollectionProperty { color: brown; }\n.XcIBOutletCollectionVariable { color: brown; }\n.XcIBOutletProperty { color: brown; }\n.XcIBOutletVariable { color: brown; }\n.XcInstanceMethod { color: darkgreen; }\n.XcInstanceMethodTemplate { color: darkgreen; }\n.XcInstanceVariable { color: darkred; }\n.XcLocalVariable { }\n.XcMacro {}\n.XcMark {}\n.XcMember {}\n.XcMemberContainer {}\n.XcNamespace {}\n.XcParameter {}\n.XcProperty { color: darkred; }\n.XcProtocol { color: purple; }\n.XcQuestion {}\n.XcStaticMethod { color: darkgreen; }\n.XcStaticProperty { color: darkred; }\n.XcStruct { color: #5858ff; }\n/* .XcSwift.Struct */\n.XcTestMethod { }\n.XcToDo {}\n.XcTypedef {}\n.XcUnion  {}\n\npre.#source { font-family: -apple-system; }\nspan#selected { }\nspan.highlighted { font-weight: bold; }\n.declaration { font-style: italic; }\n\ndiv.changesHeader { font-weight: bold; padding-bottom: 8px; }\n\ndiv.error { font-weight: bold; }\ndiv.log { }\ndiv.usr { padding-bottom: 8px; }\n\ndiv.changesEntry { padding-top: 4px; padding-bottom: 8px; }\na.sourceLink { background-color: #e8e8e8; }\nspan.linenumber { color: darkgrey; }\nspan.covered { border-right: 2px inset green; }\n\ndiv.applying { }\nspan.oldValue { color: red; }\nspan.newValue { color: green; }\n\n/* HTML extract */\n\nspan.references { display: none; position: absolute; border: 2px outset; z-index: 100; }\nspan.references table { background-color: white; }\nspan.references table tr td { border: 1px inset; font: 10pt Courier New; }\nspan.references table tr.decl td { font-style: italic; }\n\ndiv.filelist { font-family: -apple-system; font-size: 12pt; }\ndiv.filelist a { margin: 4px; }\n\n</style><script>\n\nvar boldened, source\n\nfunction setSource( html ) {\n    if ( !source )\n        source = document.getElementById(\"source\")\n\n    if ( source.children.length )\n        source.children[0].style.display = \"none\"\n\n    var div = document.createElement(\"div\")\n    div.innerHTML = html\n    source.insertBefore(div,source.children[0])\n\n    boldened = null\n\n    var selected = document.getElementById( \"selected\" )\n    if ( selected ) {\n        scrollTo( 0, selected.offsetTop-window.innerHeight/3 )\n        if ( selected.getAttribute(\"cascade\") != 0 )\n            searchSelected( selected, 0, 1 )\n        else\n            getSelection().setBaseAndExtent(selected, 0, selected, 1)\n    }\n    else\n        scrollTo( 0, 0 )\n\n    window.onmouseup = function() {\n        searchSelected( event.srcElement, event.metaKey, 0, 1 )\n        event.cancelBubble = true\n    }\n}\n\nfunction appendSource( path, filtered ) {\n    var span = document.createElement(\"span\")\n    span.innerHTML = filtered\n    span.title = path\n    source.children[0].appendChild(span)\n}\n\nfunction searchSelected( span, meta, cascade, click ) {\n    var innerSpan = span\n    while ( span && !span.getAttribute(\"line\") )\n        span = span.parentElement\n\n    if ( span ) {\n\n        if ( window.appController && (span.getAttribute(\"entity\") != 0 || cascade) ) {\n            getSelection().setBaseAndExtent(span, 0, span, 1)\n\n            if ( boldened )\n                boldened.style.fontWeight = \"normal\"\n            boldened = innerSpan\n            if ( !cascade )\n                boldened.style.fontWeight = \"bold\"\n\n            if ( span.getAttribute(\"entity\") != 0 )\n                appController.selectedWithText_title_line_col_offset_metaKey_( span.innerText, span.title,\n                    span.getAttribute(\"line\"), span.getAttribute(\"col\"), span.getAttribute(\"offset\"), meta )\n        }\n\n        if ( window.appController2 && click ) {\n            getSelection().setBaseAndExtent(span, 0, span, 1)\n            appController2.changeSelectedWithText_title_line_col_offset_metaKey_( span.innerText, span.title,\n                span.getAttribute(\"line\"), span.getAttribute(\"col\"), span.getAttribute(\"offset\"), meta )\n        }\n    }\n}\n\nfunction gotoFile( file, line ) {\n    appController2.gotoWithFile_line_( file, line )\n    return false\n}\n\nfunction gotoLine( line ) {\n    var label = document.getElementById( \"L\"+line )\n    label.style.color = \"red\"\n    scrollTo( 0, label.offsetTop-window.innerHeight/3 )\n}\n\nvar lastlink;\n\nfunction expand(a, metaKey) {\n    if ( metaKey )\n        return true\n    var last = a.children.length-1\n    if ( a.children[last].style.display != \"block\" ) {\n        if ( lastlink )\n            lastlink.style.display = \"none\";\n        a.children[last].style.display = \"block\";\n        lastlink = a.children[last];\n    }\n    else {\n        a.children[last].style.display = \"none\";\n        lastlink = null;\n    }\n    return false;\n}\n\n</script></head>\n<body><pre id=\"source\">\n"
  },
  {
    "path": "Refactorator/Utils.h",
    "content": "//\n//  Utils.h\n//  Refactorator\n//\n//  Created by John Holdsworth on 19/11/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface Utils : NSObject\n+ (NSString *)hashStringForPath:(NSString *)path;\n@end\n"
  },
  {
    "path": "Refactorator/Utils.m",
    "content": "//\n//  Utils.m\n//  Refactorator\n//\n//  Created by John Holdsworth on 19/11/2016.\n//  Copyright © 2016 John Holdsworth. All rights reserved.\n//\n\n#import \"Utils.h\"\n\n#import <CommonCrypto/CommonCrypto.h>\n\n@implementation Utils\n\n// Thanks to: http://samdmarshall.com/blog/xcode_deriveddata_hashes.html\n\n// this function is used to swap byte ordering of a 64bit integer\nuint64_t swap_uint64(uint64_t val) {\n    val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );\n    val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );\n    return (val << 32) | (val >> 32);\n}\n\n/*!\n @method hashStringForPath\n\n Create the unique identifier string for a Xcode project path\n\n @param path (input) string path to the \".xcodeproj\" or \".xcworkspace\" file\n\n @result NSString* of the identifier\n */\n+ (NSString *)hashStringForPath:(NSString *)path;\n{\n    // using uint64_t[2] for ease of use, since it is the same size as char[CC_MD5_DIGEST_LENGTH]\n    uint64_t digest[CC_MD2_DIGEST_LENGTH] = {0};\n\n    // char array that will contain the identifier\n    unsigned char resultStr[28] = {0};\n\n    // setup md5 context\n    CC_MD5_CTX md5;\n    CC_MD5_Init(&md5);\n\n    // get the UTF8 string of the path\n    const char *c_path = [path UTF8String];\n\n    // get length of the path string\n    unsigned long length = strlen(c_path);\n\n    // update the md5 context with the full path string\n    CC_MD5_Update (&md5, c_path, (CC_LONG)length);\n\n    // finalize working with the md5 context and store into the digest\n    CC_MD5_Final ( (unsigned char *)digest, &md5);\n\n    // take the first 8 bytes of the digest and swap byte order\n    uint64_t startValue = swap_uint64(digest[0]);\n\n    // for indexes 13->0\n    int index = 13;\n    do {\n        // take 'startValue' mod 26 (restrict to alphabetic) and add based 'a'\n        resultStr[index] = (char)((startValue % 26) + 'a');\n\n        // divide 'startValue' by 26\n        startValue /= 26;\n\n        index--;\n    } while (index >= 0);\n\n    // The second loop, this time using the last 8 bytes\n    // repeating the same process as before but over indexes 27->14\n    startValue = swap_uint64(digest[1]);\n    index = 27;\n    do {\n        resultStr[index] = (char)((startValue % 26) + 'a');\n        startValue /= 26;\n        index--;\n    } while (index > 13);\n\n    //return [[NSString alloc] initWithString:@\"agyjsqofsyrdwafqcrbciitvnmmj\"];\n    // create a new string from the 'resultStr' char array and return\n    return [[NSString alloc] initWithBytes:resultStr length:28 encoding:NSUTF8StringEncoding];\n}\n\n@end\n\n"
  },
  {
    "path": "Refactorator/Xcode.h",
    "content": "/*\n * Xcode.h -- extracted using: sdef /Applications/Xcode.app | sdp -fh --basename Xcode and slightly modified for Swift\n */\n\n#import <AppKit/AppKit.h>\n#import <ScriptingBridge/ScriptingBridge.h>\n\n\n@class XcodeApplication, XcodeDocument, XcodeWindow, XcodeFileDocument, XcodeTextDocument, XcodeSourceDocument, XcodeWorkspaceDocument, XcodeSchemeActionResult, XcodeSchemeActionIssue, XcodeBuildError, XcodeBuildWarning, XcodeAnalyzerIssue, XcodeTestFailure, XcodeScheme, XcodeRunDestination, XcodeDevice, XcodeBuildConfiguration, XcodeProject, XcodeBuildSetting, XcodeResolvedBuildSetting, XcodeTarget;\n\nenum XcodeSaveOptions {\n\tXcodeSaveOptionsYes = 'yes ' /* Save the file. */,\n\tXcodeSaveOptionsNo = 'no  ' /* Do not save the file. */,\n\tXcodeSaveOptionsAsk = 'ask ' /* Ask the user whether or not to save the file. */\n};\ntypedef enum XcodeSaveOptions XcodeSaveOptions;\n\n// The status of a scheme action result object.\nenum XcodeSchemeActionResultStatus {\n\tXcodeSchemeActionResultStatusNotYetStarted = 'srsn' /* The action has not yet started. */,\n\tXcodeSchemeActionResultStatusRunning = 'srsr' /* The action is in progress. */,\n\tXcodeSchemeActionResultStatusCancelled = 'srsc' /* The action was cancelled. */,\n\tXcodeSchemeActionResultStatusFailed = 'srsf' /* The action ran but did not complete successfully. */,\n\tXcodeSchemeActionResultStatusErrorOccurred = 'srse' /* The action was not able to run due to an error. */,\n\tXcodeSchemeActionResultStatusSucceeded = 'srss' /* The action succeeded. */\n};\ntypedef enum XcodeSchemeActionResultStatus XcodeSchemeActionResultStatus;\n\n@protocol XcodeGenericMethods\n\n- (void) closeSaving:(XcodeSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.\n- (void) delete;  // Delete an object.\n- (void) moveTo:(SBObject *)to;  // Move an object to a new location.\n- (XcodeSchemeActionResult *) build;  // Invoke the \"build\" scheme action. This command should be sent to a workspace document. The build will be performed using the workspace document's current active scheme and active run destination. This command does not wait for the action to complete; its progress can be tracked with the returned scheme action result.\n- (XcodeSchemeActionResult *) clean;  // Invoke the \"clean\" scheme action. This command should be sent to a workspace document. The clean will be performed using the workspace document's current active scheme and active run destination. This command does not wait for the action to complete; its progress can be tracked with the returned scheme action result.\n- (void) stop;  // Stop the active scheme action, if one is running. This command should be sent to a workspace document. This command does not wait for the action to stop.\n- (XcodeSchemeActionResult *) runWithCommandLineArguments:(id)withCommandLineArguments withEnvironmentVariables:(id)withEnvironmentVariables;  // Invoke the \"run\" scheme action. This command should be sent to a workspace document. The run action will be performed using the workspace document's current active scheme and active run destination. This command does not wait for the action to complete; its progress can be tracked with the returned scheme action result.\n- (XcodeSchemeActionResult *) testWithCommandLineArguments:(id)withCommandLineArguments withEnvironmentVariables:(id)withEnvironmentVariables;  // Invoke the \"test\" scheme action. This command should be sent to a workspace document. The test action will be performed using the workspace document's current active scheme and active run destination. This command does not wait for the action to complete; its progress can be tracked with the returned scheme action result.\n\n@end\n\n\n\n/*\n * Standard Suite\n */\n\n// The application's top-level scripting object.\n@interface SBApplication(XcodeApplication)\n\n- (SBElementArray<XcodeDocument *> *) documents;\n- (SBElementArray<XcodeWindow *> *) windows;\n\n@property (copy, readonly) NSString *name;  // The name of the application.\n@property (readonly) BOOL frontmost;  // Is this the active application?\n@property (copy, readonly) NSString *version;  // The version number of the application.\n\n- (id) open:(id)x;  // Open a document.\n- (void) quitSaving:(XcodeSaveOptions)saving;  // Quit the application.\n- (BOOL) exists:(id)x;  // Verify that an object exists.\n\n@end\n\n// A document.\n@interface XcodeDocument : SBObject <XcodeGenericMethods>\n\n@property (copy, readonly) NSString *name;  // Its name.\n@property (readonly) BOOL modified;  // Has it been modified since the last save?\n@property (copy, readonly) NSURL *file;  // Its location on disk, if it has one.\n\n\n@end\n\n// A window.\n@interface SBObject(XcodeWindow) //: SBObject <XcodeGenericMethods>\n\n@property (copy, readonly) NSString *name;  // The title of the window.\n- (NSInteger) id;  // The unique identifier of the window.\n@property NSInteger index;  // The index of the window, ordered front to back.\n@property NSRect bounds;  // The bounding rectangle of the window.\n@property (readonly) BOOL closeable;  // Does the window have a close button?\n@property (readonly) BOOL miniaturizable;  // Does the window have a minimize button?\n@property BOOL miniaturized;  // Is the window minimized right now?\n@property (readonly) BOOL resizable;  // Can the window be resized?\n@property BOOL visible;  // Is the window visible right now?\n@property (readonly) BOOL zoomable;  // Does the window have a zoom button?\n@property BOOL zoomed;  // Is the window zoomed right now?\n@property (copy, readonly) /*XcodeDocument*/ SBObject *document;  // The document whose contents are displayed in the window.\n\n\n@end\n\n\n\n/*\n * Xcode Application Suite\n */\n\n// The Xcode application.\n@interface SBApplication (XcodeApplicationSuite)\n\n- (SBElementArray<XcodeFileDocument *> *) fileDocuments;\n- (SBElementArray<XcodeSourceDocument *> *) sourceDocuments;\n- (SBElementArray<XcodeWorkspaceDocument *> *) workspaceDocuments;\n\n@property (copy) /*XcodeWorkspaceDocument*/ SBObject *activeWorkspaceDocument;  // The active workspace document in Xcode.\n\n@end\n\n\n\n/*\n * Xcode Document Suite\n */\n\n// An Xcode-compatible document.\n@interface SBObject(XcodeDocument)// (XcodeDocumentSuite)\n\n@property (copy) NSString *path;  // The document's path.\n\n@end\n\n// A document that represents a file on disk. It also provides access to the window it appears in.\n@interface XcodeFileDocument : XcodeDocument\n\n\n@end\n\n// A document that represents a text file on disk. It also provides access to the window it appears in.\n@interface SBObject(XcodeTextDocument)// : XcodeFileDocument\n\n@property (copy) NSArray<NSNumber *> *selectedCharacterRange;  // The first and last character positions in the selection.\n@property (copy) NSArray<NSNumber *> *selectedParagraphRange;  // The first and last paragraph positions that contain the selection.\n@property (copy) NSString *text;  // The text of the text file referenced.\n@property BOOL notifiesWhenClosing;  // Should Xcode notify other apps when this document is closed?\n\n\n@end\n\n// A document that represents a source file on disk. It also provides access to the window it appears in.\n@interface SBObject(XcodeSourceDocument)// : XcodeTextDocument\n\n\n@end\n\n// A document that represents a workspace on disk. Workspaces are the top-level container for almost all objects and commands in Xcode.\n@interface SBObject(XcodeWorkspaceDocument) <XcodeGenericMethods>// : XcodeDocument\n\n- (SBElementArray<XcodeProject *> *) projects;\n- (SBElementArray<XcodeScheme *> *) schemes;\n- (SBElementArray<XcodeRunDestination *> *) runDestinations;\n\n@property BOOL loaded;  // Whether the workspace document has finsished loading after being opened. Messages sent to a workspace document before it has loaded will result in errors.\n@property (copy) XcodeScheme *activeScheme;  // The workspace's  scheme that will be used for scheme actions.\n@property (copy) /*XcodeRunDestination*/ SBObject *activeRunDestination;  // The workspace's run destination that will be used for scheme actions.\n@property (copy) XcodeSchemeActionResult *lastSchemeActionResult;  // The scheme action result for the last scheme action command issued to the workspace document.\n@property (copy, readonly) NSURL *file;  // Its location on disk, if it has one.\n\n\n@end\n\n/*\n * Xcode Scheme Suite\n */\n\n// An object describing the result of performing a scheme action command.\n@interface XcodeSchemeActionResult : SBObject <XcodeGenericMethods>\n\n- (SBElementArray<XcodeBuildError *> *) buildErrors;\n- (SBElementArray<XcodeBuildWarning *> *) buildWarnings;\n- (SBElementArray<XcodeAnalyzerIssue *> *) analyzerIssues;\n- (SBElementArray<XcodeTestFailure *> *) testFailures;\n\n- (NSString *) id;  // The unique identifier for the scheme.\n@property (readonly) BOOL completed;  // Whether this scheme action has completed (sucessfully or otherwise) or not.\n@property XcodeSchemeActionResultStatus status;  // Indicates the status of the scheme action.\n@property (copy) NSString *errorMessage;  // If the result's status is \"error occurred\", this will be the error message; otherwise, this will be \"missing value\".\n@property (copy) NSString *buildLog;  // If this scheme action performed a build, this will be the text of the build log.\n\n\n@end\n\n// An issue (like an error or warning) generated by a scheme action.\n@interface XcodeSchemeActionIssue : SBObject <XcodeGenericMethods>\n\n@property (copy) NSString *message;  // The text of the issue.\n@property (copy) NSString *filePath;  // The file path where the issue occurred. This may be 'missing value' if the issue is not associated with a specific source file.\n@property NSInteger startingLineNumber;  // The starting line number in the file where the issue occurred. This may be 'missing value' if the issue is not associated with a specific source file.\n@property NSInteger endingLineNumber;  // The ending line number in the file where the issue occurred. This may be 'missing value' if the issue is not associated with a specific source file.\n@property NSInteger startingColumnNumber;  // The starting column number in the file where the issue occurred. This may be 'missing value' if the issue is not associated with a specific source file.\n@property NSInteger endingColumnNumber;  // The ending column number in the file where the issue occurred. This may be 'missing value' if the issue is not associated with a specific source file.\n\n\n@end\n\n// An error generated by a build.\n@interface XcodeBuildError : XcodeSchemeActionIssue\n\n\n@end\n\n// A warning generated by a build.\n@interface XcodeBuildWarning : XcodeSchemeActionIssue\n\n\n@end\n\n// A warning generated by the static analyzer.\n@interface XcodeAnalyzerIssue : XcodeSchemeActionIssue\n\n\n@end\n\n// A failure from a test.\n@interface XcodeTestFailure : XcodeSchemeActionIssue\n\n\n@end\n\n// A set of parameters for building, testing, launching or distributing the products of a workspace.\n@interface XcodeScheme : SBObject <XcodeGenericMethods>\n\n@property (copy, readonly) NSString *name;  // The name of the scheme.\n- (NSString *) id;  // The unique identifier for the scheme.\n\n\n@end\n\n// An object which specifies parameters such as the device and architecture for which to perform a scheme action.\n@interface SBObject(XcodeRunDestination)// : SBObject <XcodeGenericMethods>\n\n@property (copy, readonly) NSString *name;  // The name of the run destination.\n@property (copy, readonly) NSString *architecture;  // The architecture for which this run destination results in execution.\n@property (copy, readonly) NSString *platform;  // The platform which this run destination targets.\n@property (copy, readonly) XcodeDevice *device;  // The device which this run destination targets.\n@property (copy, readonly) XcodeDevice *companionDevice;  // If the run destination's device has a companion (e.g. a paired watch for a phone) which it will use, this is that device.\n\n\n@end\n\n// A device which can be used as the target for a scheme action, as part of a run destination.\n@interface XcodeDevice : SBObject <XcodeGenericMethods>\n\n@property (copy, readonly) NSString *name;  // The name of the run destination.\n@property (copy, readonly) NSString *deviceIdentifier;  // The identifier of the device which this run destination targets.\n@property (copy, readonly) NSString *operatingSystemVersion;  // The version of the operating system installed on the device which this run destination targets.\n@property (copy, readonly) NSString *deviceModel;  // The model of device (e.g. \"iPad Air\") which this run destination targets.\n@property (readonly) BOOL generic;  // Whether this run destination is generic instead of representing a specific device.\n\n\n@end\n\n\n\n/*\n * Xcode Project Suite\n */\n\n// A set of build settings for a target or project. Each target in a project has the same named build configurations as the project.\n@interface XcodeBuildConfiguration : SBObject <XcodeGenericMethods>\n\n- (SBElementArray<XcodeBuildSetting *> *) buildSettings;\n- (SBElementArray<XcodeResolvedBuildSetting *> *) resolvedBuildSettings;\n\n- (NSString *) id;  // The unique identifier for the build configuration.\n@property (copy, readonly) NSString *name;  // The name of the build configuration.\n\n\n@end\n\n// An Xcode project. Projects represent project files on disk and are always open in the context of a workspace document.\n@interface XcodeProject : SBObject <XcodeGenericMethods>\n\n- (SBElementArray<XcodeBuildConfiguration *> *) buildConfigurations;\n- (SBElementArray<XcodeTarget *> *) targets;\n\n@property (copy, readonly) NSString *name;  // The name of the project\n- (NSString *) id;  // The unique identifier for the project.\n\n\n@end\n\n// A setting that controls how products are built.\n@interface XcodeBuildSetting : SBObject <XcodeGenericMethods>\n\n@property (copy) NSString *name;  // The unlocalized build setting name (e.g. DSTROOT).\n@property (copy) NSString *value;  // A string value for the build setting.\n\n\n@end\n\n// An object that represents a resolved value for a build setting.\n@interface XcodeResolvedBuildSetting : SBObject <XcodeGenericMethods>\n\n@property (copy) NSString *name;  // The unlocalized build setting name (e.g. DSTROOT).\n@property (copy) NSString *value;  // A string value for the build setting.\n\n\n@end\n\n// A target is a blueprint for building a product. Targets inherit build settings from their project if not overridden in the target.\n@interface XcodeTarget : SBObject <XcodeGenericMethods>\n\n- (SBElementArray<XcodeBuildConfiguration *> *) buildConfigurations;\n\n@property (copy) NSString *name;  // The name of this target.\n- (NSString *) id;  // The unique identifier for the target.\n@property (copy, readonly) XcodeProject *project;  // The project that contains this target\n\n\n@end\n\n"
  },
  {
    "path": "Refactorator/canviz.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<!--\n This file is part of Canviz. See http://www.canviz.org/\n $Id: new.html.in 256 2009-01-08 11:14:07Z ryandesign.com $\n -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n    <head>\n        <meta name=\"MSSmartTagsPreventParsing\" content=\"true\" />\n        <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"canviz-0.1/canviz.css\" />\n        <title>Project Dependencies</title>\n        <script type=\"text/javascript\" src=\"canviz-0.1/prototype/prototype.js\"></script>\n        <script type=\"text/javascript\" src=\"canviz-0.1/path/path.js\"></script>\n        <script type=\"text/javascript\" src=\"canviz-0.1/canviz.js\"></script>\n        <script>\n            var canviz;\n            document.observe('dom:loaded', function() {\n                 canviz = new Canviz('canviz', '/tmp/canviz.gv?flush='+Math.random());\n            });\n            function click_node(node) {\n                appController.dependsWithPath_( node )\n                return false\n            }\n            function set_graph_scale(select) {\n                canviz.setScale(select.value);\n                canviz.draw();\n                window.scrollTo(0,0);\n            }\n        </script>\n    </head>\n    <body>\n        <div id=\"menus\" style=\"position: relative;\">\n            &nbsp;Image Scale:\n\n            <select name=\"graph_scale\" id=\"graph_scale\" onchange=\"set_graph_scale(this)\">\n                <option value=\"1\" selected>100%</option>\n                <option value=\"0.75\">75%</option>\n                <option value=\"0.5\">50%</option>\n                <option value=\"0.35\">35%</option>\n                <option value=\"0.25\">25%</option>\n                <option value=\"0.15\">15%</option>\n                <option value=\"0.1\">10%</option>\n                <option value=\"0.05\">5%</option>\n            </select>\n\n            <button onclick=\"appController.graphvizExport()\">Export to Graphviz</button>\n\n            Click on file name to list references\n        </div>\n\n        <div class=\"graph\">\n            <div id=\"canviz\"></div>\n        </div>\n        <div id=\"debug_output\" style=\"display:none\"></div>\n    </body>\n</html>\n"
  },
  {
    "path": "Refactorator/canviz2.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<!--\n This file is part of Canviz. See http://www.canviz.org/\n $Id: new.html.in 256 2009-01-08 11:14:07Z ryandesign.com $\n -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n    <head>\n        <meta name=\"MSSmartTagsPreventParsing\" content=\"true\" />\n        <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"canviz-0.1/canviz.css\" />\n        <title>Project Dependencies</title>\n        <script type=\"text/javascript\" src=\"canviz-0.1/prototype/prototype.js\"></script>\n        <script type=\"text/javascript\" src=\"canviz-0.1/path/path.js\"></script>\n        <script type=\"text/javascript\" src=\"canviz-0.1/canviz.js\"></script>\n        <script>\n            var canviz;\n            document.observe('dom:loaded', function() {\n                 canviz = new Canviz('canviz', 'refactorator.gv?flush='+Math.random());\n            });\n            function click_node(href) {\n                document.location.href = href\n                return false\n            }\n            function set_graph_scale(select) {\n                canviz.setScale(select.value);\n                canviz.draw();\n                window.scrollTo(0,0);\n            }\n        </script>\n    </head>\n    <body>\n        <div id=\"menus\" style=\"position: relative;\">\n            &nbsp;Image Scale:\n\n            <select name=\"graph_scale\" id=\"graph_scale\" onchange=\"set_graph_scale(this)\">\n                <option value=\"1\" selected>100%</option>\n                <option value=\"0.75\">75%</option>\n                <option value=\"0.5\">50%</option>\n                <option value=\"0.35\">35%</option>\n                <option value=\"0.25\">25%</option>\n                <option value=\"0.15\">15%</option>\n                <option value=\"0.1\">10%</option>\n                <option value=\"0.05\">5%</option>\n            </select>\n\n            Click on file name to view source\n        </div>\n\n        <div class=\"graph\">\n            <div id=\"canviz\"></div>\n        </div>\n        <div id=\"debug_output\" style=\"display:none\"></div>\n    </body>\n</html>\n"
  },
  {
    "path": "Refactorator/coverage.rb",
    "content": "#!/usr/bin/ruby\n\n#  coverage.rb\n#  Refactorator\n#\n#  Created by John Holdsworth on 03/03/2017.\n#  Copyright © 2017 John Holdsworth. All rights reserved.\n\nprofdata, source = ARGV\n\nobjectdir = File.dirname( profdata )\nclassname = File.basename( source, \".swift\" )\n\nDir.chdir(objectdir)\n\nobject = Dir.glob(\"**/#{classname}.o\").first\n\ncoverage = `xcrun llvm-cov show -instr-profile '#{profdata}' '#{object}'`\n\ncoverage.scan( /^\\s+(\\d+)\\|\\s+(\\d+)\\|/ ) do |covered, line|\n    if covered != \"0\"\n        puts( \"#{line}\\n\" )\n    end\nend\n"
  },
  {
    "path": "Refactorator.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\tBB04C8351E04423B00FDF253 /* canviz2.html in Resources */ = {isa = PBXBuildFile; fileRef = BB04C8341E04423B00FDF253 /* canviz2.html */; };\n\t\tBB04C8381E045DF500FDF253 /* LineGenerators.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB04C8361E045DF500FDF253 /* LineGenerators.swift */; };\n\t\tBB04C8391E045DF500FDF253 /* LogParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB04C8371E045DF500FDF253 /* LogParser.swift */; };\n\t\tBB04C83B1E062FB200FDF253 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB04C83A1E062FB200FDF253 /* Common.swift */; };\n\t\tBB1BE5AB1DE443A800BB802F /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = BB1BE5AA1DE443A800BB802F /* Credits.rtf */; };\n\t\tBB1BE5AC1DE54D4100BB802F /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BBFFF4321DE13A0600398350 /* libsqlite3.tbd */; };\n\t\tBB1BE5AE1DE801B700BB802F /* Intro.html in Resources */ = {isa = PBXBuildFile; fileRef = BB1BE5AD1DE801B600BB802F /* Intro.html */; };\n\t\tBB2BAFDC1DEEDC36003715DB /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = BB2BAFD91DEED26E003715DB /* README.md */; };\n\t\tBB2CE5611E003A6A00BE0C52 /* Formatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2CE5601E003A6A00BE0C52 /* Formatter.swift */; };\n\t\tBB2CE5631E005ECC00BE0C52 /* AppController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2CE5621E005ECC00BE0C52 /* AppController.swift */; };\n\t\tBB2CE5711E01965E00BE0C52 /* canviz-0.1 in Resources */ = {isa = PBXBuildFile; fileRef = BB2CE5701E01965E00BE0C52 /* canviz-0.1 */; };\n\t\tBB2CE5731E0197AB00BE0C52 /* canviz.html in Resources */ = {isa = PBXBuildFile; fileRef = BB2CE5721E0197AB00BE0C52 /* canviz.html */; };\n\t\tBB356BE21E0C75A30056B10F /* Integration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB356BE11E0C75A30056B10F /* Integration.swift */; };\n\t\tBB3A5EEB1DE3A76C00184151 /* Xcode.h in Resources */ = {isa = PBXBuildFile; fileRef = BBFFF4281DE1311300398350 /* Xcode.h */; };\n\t\tBB6528251E69730300B8FB95 /* Coverage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6528241E69730300B8FB95 /* Coverage.swift */; };\n\t\tBB6528291E69821200B8FB95 /* coverage.rb in Resources */ = {isa = PBXBuildFile; fileRef = BB6528261E6973CD00B8FB95 /* coverage.rb */; };\n\t\tBB8E068B1DE869290006BB1D /* ByteRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8E06861DE869290006BB1D /* ByteRegex.swift */; };\n\t\tBB8E068C1DE869290006BB1D /* Entity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8E06871DE869290006BB1D /* Entity.swift */; };\n\t\tBB8E068D1DE869290006BB1D /* IndexDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8E06881DE869290006BB1D /* IndexDB.swift */; };\n\t\tBB8E068E1DE869290006BB1D /* IndexStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8E06891DE869290006BB1D /* IndexStrings.swift */; };\n\t\tBB8E068F1DE869290006BB1D /* SourceKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8E068A1DE869290006BB1D /* SourceKit.swift */; };\n\t\tBBFFF4061DE1083A00398350 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFFF4051DE1083A00398350 /* AppDelegate.swift */; };\n\t\tBBFFF4081DE1083A00398350 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BBFFF4071DE1083A00398350 /* Assets.xcassets */; };\n\t\tBBFFF40B1DE1083A00398350 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = BBFFF4091DE1083A00398350 /* MainMenu.xib */; };\n\t\tBBFFF4131DE1086B00398350 /* App.icns in Resources */ = {isa = PBXBuildFile; fileRef = BBFFF4121DE1086B00398350 /* App.icns */; };\n\t\tBBFFF4161DE109BC00398350 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBFFF4151DE109BC00398350 /* WebKit.framework */; };\n\t\tBBFFF4201DE10C6400398350 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = BBFFF41F1DE10C6400398350 /* Utils.m */; };\n\t\tBBFFF4241DE11DBB00398350 /* Source.html in Resources */ = {isa = PBXBuildFile; fileRef = BBFFF4231DE11DBB00398350 /* Source.html */; };\n\t\tBBFFF4351DE1781800398350 /* Project.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFFF4341DE1781800398350 /* Project.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tBB04C8341E04423B00FDF253 /* canviz2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = canviz2.html; sourceTree = \"<group>\"; };\n\t\tBB04C8361E045DF500FDF253 /* LineGenerators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LineGenerators.swift; path = ../../Refactorator/refactord/LineGenerators.swift; sourceTree = \"<group>\"; };\n\t\tBB04C8371E045DF500FDF253 /* LogParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LogParser.swift; path = ../../Refactorator/refactord/LogParser.swift; sourceTree = \"<group>\"; };\n\t\tBB04C83A1E062FB200FDF253 /* Common.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = \"<group>\"; };\n\t\tBB1BE5AA1DE443A800BB802F /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = \"<group>\"; };\n\t\tBB1BE5AD1DE801B600BB802F /* Intro.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Intro.html; sourceTree = \"<group>\"; };\n\t\tBB2BAFD91DEED26E003715DB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };\n\t\tBB2BAFDB1DEEDA85003715DB /* sourcekitd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sourcekitd.h; path = ../../Refactorator/refactord/sourcekitd.h; sourceTree = \"<group>\"; };\n\t\tBB2CE5601E003A6A00BE0C52 /* Formatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Formatter.swift; sourceTree = \"<group>\"; };\n\t\tBB2CE5621E005ECC00BE0C52 /* AppController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppController.swift; sourceTree = \"<group>\"; };\n\t\tBB2CE5701E01965E00BE0C52 /* canviz-0.1 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = \"canviz-0.1\"; sourceTree = \"<group>\"; };\n\t\tBB2CE5721E0197AB00BE0C52 /* canviz.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = canviz.html; sourceTree = \"<group>\"; };\n\t\tBB356BE11E0C75A30056B10F /* Integration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Integration.swift; sourceTree = \"<group>\"; };\n\t\tBB6528241E69730300B8FB95 /* Coverage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coverage.swift; sourceTree = \"<group>\"; };\n\t\tBB6528261E6973CD00B8FB95 /* coverage.rb */ = {isa = PBXFileReference; lastKnownFileType = text.script.ruby; path = coverage.rb; sourceTree = \"<group>\"; };\n\t\tBB8E06861DE869290006BB1D /* ByteRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ByteRegex.swift; path = ../../Refactorator/refactord/ByteRegex.swift; sourceTree = \"<group>\"; };\n\t\tBB8E06871DE869290006BB1D /* Entity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Entity.swift; path = ../../Refactorator/refactord/Entity.swift; sourceTree = \"<group>\"; };\n\t\tBB8E06881DE869290006BB1D /* IndexDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IndexDB.swift; path = ../../Refactorator/refactord/IndexDB.swift; sourceTree = \"<group>\"; };\n\t\tBB8E06891DE869290006BB1D /* IndexStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IndexStrings.swift; path = ../../Refactorator/refactord/IndexStrings.swift; sourceTree = \"<group>\"; };\n\t\tBB8E068A1DE869290006BB1D /* SourceKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SourceKit.swift; path = ../../Refactorator/refactord/SourceKit.swift; sourceTree = \"<group>\"; };\n\t\tBBFFF4021DE1083900398350 /* Refactorator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Refactorator.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBBFFF4051DE1083A00398350 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tBBFFF4071DE1083A00398350 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tBBFFF40A1DE1083A00398350 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\tBBFFF40C1DE1083A00398350 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tBBFFF4121DE1086B00398350 /* App.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = App.icns; sourceTree = \"<group>\"; };\n\t\tBBFFF4151DE109BC00398350 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };\n\t\tBBFFF41D1DE10C6400398350 /* Refactorator-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Refactorator-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tBBFFF41E1DE10C6400398350 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = \"<group>\"; };\n\t\tBBFFF41F1DE10C6400398350 /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utils.m; sourceTree = \"<group>\"; };\n\t\tBBFFF4211DE1130800398350 /* sourcekitd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = sourcekitd.framework; path = Toolchains/XcodeDefault.xctoolchain/usr/lib/sourcekitd.framework; sourceTree = DEVELOPER_DIR; };\n\t\tBBFFF4231DE11DBB00398350 /* Source.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Source.html; sourceTree = \"<group>\"; };\n\t\tBBFFF4281DE1311300398350 /* Xcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Xcode.h; sourceTree = \"<group>\"; };\n\t\tBBFFF4321DE13A0600398350 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };\n\t\tBBFFF4341DE1781800398350 /* Project.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Project.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tBBFFF3FF1DE1083900398350 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBBFFF4161DE109BC00398350 /* WebKit.framework in Frameworks */,\n\t\t\t\tBB1BE5AC1DE54D4100BB802F /* libsqlite3.tbd in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tBBFFF3F91DE1083900398350 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB2BAFD91DEED26E003715DB /* README.md */,\n\t\t\t\tBBFFF4041DE1083A00398350 /* Refactorator */,\n\t\t\t\tBB2CE5701E01965E00BE0C52 /* canviz-0.1 */,\n\t\t\t\tBBFFF4031DE1083900398350 /* Products */,\n\t\t\t\tBBFFF4141DE109BB00398350 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBBFFF4031DE1083900398350 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBBFFF4021DE1083900398350 /* Refactorator.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBBFFF4041DE1083A00398350 /* Refactorator */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBBFFF4051DE1083A00398350 /* AppDelegate.swift */,\n\t\t\t\tBB2CE5621E005ECC00BE0C52 /* AppController.swift */,\n\t\t\t\tBB2CE5601E003A6A00BE0C52 /* Formatter.swift */,\n\t\t\t\tBB04C83A1E062FB200FDF253 /* Common.swift */,\n\t\t\t\tBBFFF4341DE1781800398350 /* Project.swift */,\n\t\t\t\tBB6528241E69730300B8FB95 /* Coverage.swift */,\n\t\t\t\tBB356BE11E0C75A30056B10F /* Integration.swift */,\n\t\t\t\tBB04C8361E045DF500FDF253 /* LineGenerators.swift */,\n\t\t\t\tBB8E06891DE869290006BB1D /* IndexStrings.swift */,\n\t\t\t\tBB8E06861DE869290006BB1D /* ByteRegex.swift */,\n\t\t\t\tBB04C8371E045DF500FDF253 /* LogParser.swift */,\n\t\t\t\tBB8E068A1DE869290006BB1D /* SourceKit.swift */,\n\t\t\t\tBB8E06881DE869290006BB1D /* IndexDB.swift */,\n\t\t\t\tBB8E06871DE869290006BB1D /* Entity.swift */,\n\t\t\t\tBB2BAFDB1DEEDA85003715DB /* sourcekitd.h */,\n\t\t\t\tBBFFF4281DE1311300398350 /* Xcode.h */,\n\t\t\t\tBBFFF4071DE1083A00398350 /* Assets.xcassets */,\n\t\t\t\tBBFFF4091DE1083A00398350 /* MainMenu.xib */,\n\t\t\t\tBBFFF4231DE11DBB00398350 /* Source.html */,\n\t\t\t\tBB2CE5721E0197AB00BE0C52 /* canviz.html */,\n\t\t\t\tBB04C8341E04423B00FDF253 /* canviz2.html */,\n\t\t\t\tBB6528261E6973CD00B8FB95 /* coverage.rb */,\n\t\t\t\tBB1BE5AA1DE443A800BB802F /* Credits.rtf */,\n\t\t\t\tBB1BE5AD1DE801B600BB802F /* Intro.html */,\n\t\t\t\tBBFFF40C1DE1083A00398350 /* Info.plist */,\n\t\t\t\tBBFFF4121DE1086B00398350 /* App.icns */,\n\t\t\t\tBBFFF41E1DE10C6400398350 /* Utils.h */,\n\t\t\t\tBBFFF41F1DE10C6400398350 /* Utils.m */,\n\t\t\t\tBBFFF41D1DE10C6400398350 /* Refactorator-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = Refactorator;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBBFFF4141DE109BB00398350 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBBFFF4321DE13A0600398350 /* libsqlite3.tbd */,\n\t\t\t\tBBFFF4211DE1130800398350 /* sourcekitd.framework */,\n\t\t\t\tBBFFF4151DE109BC00398350 /* WebKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tBBFFF4011DE1083900398350 /* Refactorator */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BBFFF40F1DE1083A00398350 /* Build configuration list for PBXNativeTarget \"Refactorator\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBBFFF3FE1DE1083900398350 /* Sources */,\n\t\t\t\tBBFFF3FF1DE1083900398350 /* Frameworks */,\n\t\t\t\tBBFFF4001DE1083900398350 /* 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 = Refactorator;\n\t\t\tproductName = Refactorator;\n\t\t\tproductReference = BBFFF4021DE1083900398350 /* Refactorator.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tBBFFF3FA1DE1083900398350 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0810;\n\t\t\t\tLastUpgradeCheck = 0820;\n\t\t\t\tORGANIZATIONNAME = \"John Holdsworth\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tBBFFF4011DE1083900398350 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.1;\n\t\t\t\t\t\tDevelopmentTeam = 9V5A8WE85E;\n\t\t\t\t\t\tLastSwiftMigration = 0810;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = BBFFF3FD1DE1083900398350 /* Build configuration list for PBXProject \"Refactorator\" */;\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 = BBFFF3F91DE1083900398350;\n\t\t\tproductRefGroup = BBFFF4031DE1083900398350 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tBBFFF4011DE1083900398350 /* Refactorator */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tBBFFF4001DE1083900398350 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBB2BAFDC1DEEDC36003715DB /* README.md in Resources */,\n\t\t\t\tBB6528291E69821200B8FB95 /* coverage.rb in Resources */,\n\t\t\t\tBBFFF4081DE1083A00398350 /* Assets.xcassets in Resources */,\n\t\t\t\tBB1BE5AB1DE443A800BB802F /* Credits.rtf in Resources */,\n\t\t\t\tBB04C8351E04423B00FDF253 /* canviz2.html in Resources */,\n\t\t\t\tBBFFF4131DE1086B00398350 /* App.icns in Resources */,\n\t\t\t\tBBFFF40B1DE1083A00398350 /* MainMenu.xib in Resources */,\n\t\t\t\tBB2CE5731E0197AB00BE0C52 /* canviz.html in Resources */,\n\t\t\t\tBB1BE5AE1DE801B700BB802F /* Intro.html in Resources */,\n\t\t\t\tBBFFF4241DE11DBB00398350 /* Source.html in Resources */,\n\t\t\t\tBB2CE5711E01965E00BE0C52 /* canviz-0.1 in Resources */,\n\t\t\t\tBB3A5EEB1DE3A76C00184151 /* Xcode.h in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tBBFFF3FE1DE1083900398350 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBB8E068D1DE869290006BB1D /* IndexDB.swift in Sources */,\n\t\t\t\tBB04C8391E045DF500FDF253 /* LogParser.swift in Sources */,\n\t\t\t\tBB356BE21E0C75A30056B10F /* Integration.swift in Sources */,\n\t\t\t\tBB2CE5631E005ECC00BE0C52 /* AppController.swift in Sources */,\n\t\t\t\tBB8E068E1DE869290006BB1D /* IndexStrings.swift in Sources */,\n\t\t\t\tBB2CE5611E003A6A00BE0C52 /* Formatter.swift in Sources */,\n\t\t\t\tBB6528251E69730300B8FB95 /* Coverage.swift in Sources */,\n\t\t\t\tBB04C83B1E062FB200FDF253 /* Common.swift in Sources */,\n\t\t\t\tBBFFF4201DE10C6400398350 /* Utils.m in Sources */,\n\t\t\t\tBB8E068F1DE869290006BB1D /* SourceKit.swift in Sources */,\n\t\t\t\tBB8E068C1DE869290006BB1D /* Entity.swift in Sources */,\n\t\t\t\tBB8E068B1DE869290006BB1D /* ByteRegex.swift in Sources */,\n\t\t\t\tBBFFF4061DE1083A00398350 /* AppDelegate.swift in Sources */,\n\t\t\t\tBB04C8381E045DF500FDF253 /* LineGenerators.swift in Sources */,\n\t\t\t\tBBFFF4351DE1781800398350 /* Project.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tBBFFF4091DE1083A00398350 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tBBFFF40A1DE1083A00398350 /* 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\tBBFFF40D1DE1083A00398350 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\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_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = 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_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\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\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_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.11;\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_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBBFFF40E1DE1083A00398350 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\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_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = 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_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\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\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBBFFF4101DE1083A00398350 /* 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\tCODE_SIGN_IDENTITY = \"Mac Developer\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 9V5A8WE85E;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(TOOLCHAIN_DIR)/usr/lib\";\n\t\t\t\tINFOPLIST_FILE = Refactorator/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.johnholdsworth.Refactorator;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Refactorator/Refactorator-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBBFFF4111DE1083A00398350 /* 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\tCODE_SIGN_IDENTITY = \"Developer ID Application\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 9V5A8WE85E;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(TOOLCHAIN_DIR)/usr/lib\";\n\t\t\t\tINFOPLIST_FILE = Refactorator/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.johnholdsworth.Refactorator;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Refactorator/Refactorator-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tBBFFF3FD1DE1083900398350 /* Build configuration list for PBXProject \"Refactorator\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBBFFF40D1DE1083A00398350 /* Debug */,\n\t\t\t\tBBFFF40E1DE1083A00398350 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBBFFF40F1DE1083A00398350 /* Build configuration list for PBXNativeTarget \"Refactorator\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBBFFF4101DE1083A00398350 /* Debug */,\n\t\t\t\tBBFFF4111DE1083A00398350 /* 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 = BBFFF3FA1DE1083900398350 /* Project object */;\n}\n"
  },
  {
    "path": "Refactorator.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Refactorator.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "canviz-0.1/LICENSE.txt",
    "content": "MIT-style software license for Canviz library\n\nCopyright (c) 2006-2009 Ryan Schmidt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "canviz-0.1/README.txt",
    "content": "CANVIZ\n======\n\n\nIntroduction\n------------\n\nCanviz is a library for drawing Graphviz graphs to a web browser canvas. It is\ndesigned to be used by web applications that need to display or edit graphs, as\na replacement for sending graphs as bitmapped images and image maps.\n\nFor more information, please visit the Canviz web site at http://canviz.org/ .\n\n\nLicense\n-------\n\nCanviz is provided under the terms of the MIT license. See the file LICENSE.txt.\n\nThis product includes color specifications and designs developed by Cynthia\nBrewer (http://colorbrewer.org/). Use of the ColorBrewer color schemes is\nsubject to a separate license. See the file LICENSE-ColorBrewer.txt.\n\nCanviz requires the use of some other software, including the Path, Prototype\nand Excanvas libraries, and the Graphviz software, which have licenses of their\nown.\n"
  },
  {
    "path": "canviz-0.1/canviz.css",
    "content": "/*\n * This file is part of Canviz. See http://www.canviz.org/\n * $Id: canviz.css 246 2008-12-27 08:36:24Z ryandesign.com $\n */\n\nbody {\n\t/* background: #eee; */\n    font: 10pt Arial;\n\tmargin: 0;\n\tpadding: 0;\n}\n#busy {\n\tposition: fixed;\n\tz-index: 1;\n\tleft: 50%;\n\ttop: 50%;\n\twidth: 10em;\n\theight: 2em;\n\tmargin: -1em 0 0 -5em;\n\tline-height: 2em;\n\ttext-align: center;\n\tbackground: #333;\n\tcolor: #fff;\n\topacity: 0.95;\n}\n#graph_form {\n\tposition: fixed;\n\tz-index: 2;\n\tleft: 0;\n\ttop: 0;\n\tbackground: #eee;\n\tborder: solid #ccc;\n\tborder-width: 0 1px 1px 0;\n\topacity: 0.95;\n}\n#graph_form,\n#graph_form input,\n#graph_form select {\n\tfont: 12px \"Lucida Grande\", Arial, Helvetica, sans-serif;\n}\n#graph_form fieldset {\n\tmargin: 0.5em;\n\tpadding: 0.5em 0;\n\ttext-align: center;\n\tborder: solid #ccc;\n\tborder-width: 1px 0 0 0;\n}\n#graph_form legend {\n\tpadding: 0 0.5em 0 0;\n}\n#graph_form input.little_button {\n\twidth: 3em;\n}\n#graph_form select,\n#graph_form input.big_button {\n\twidth: 15em;\n}\n#graph_container {\n\tbackground: #fff;\n\tmargin: 0 auto;\n}\n#debug_output {\n\tmargin: 1em;\n}\n"
  },
  {
    "path": "canviz-0.1/canviz.js",
    "content": "/*\n * This file is part of Canviz. See http://www.canviz.org/\n * $Id: canviz.js 265 2009-05-19 13:35:13Z ryandesign.com $\n */\n\nvar CanvizTokenizer = Class.create({\n\tinitialize: function(str) {\n\t\tthis.str = str;\n\t},\n\ttakeChars: function(num) {\n\t\tif (!num) {\n\t\t\tnum = 1;\n\t\t}\n\t\tvar tokens = new Array();\n\t\twhile (num--) {\n\t\t\tvar matches = this.str.match(/^(\\S+)\\s*/);\n\t\t\tif (matches) {\n\t\t\t\tthis.str = this.str.substr(matches[0].length);\n\t\t\t\ttokens.push(matches[1]);\n\t\t\t} else {\n\t\t\t\ttokens.push(false);\n\t\t\t}\n\t\t}\n\t\tif (1 == tokens.length) {\n\t\t\treturn tokens[0];\n\t\t} else {\n\t\t\treturn tokens;\n\t\t}\n\t},\n\ttakeNumber: function(num) {\n\t\tif (!num) {\n\t\t\tnum = 1;\n\t\t}\n\t\tif (1 == num) {\n\t\t\treturn Number(this.takeChars());\n\t\t} else {\n\t\t\tvar tokens = this.takeChars(num);\n\t\t\twhile (num--) {\n\t\t\t\ttokens[num] = Number(tokens[num]);\n\t\t\t}\n\t\t\treturn tokens;\n\t\t}\n\t},\n\ttakeString: function() {\n\t\tvar byteCount = Number(this.takeChars()), charCount = 0, charCode;\n\t\tif ('-' != this.str.charAt(0)) {\n\t\t\treturn false;\n\t\t}\n\t\twhile (0 < byteCount) {\n\t\t\t++charCount;\n\t\t\tcharCode = this.str.charCodeAt(charCount);\n\t\t\tif (0x80 > charCode) {\n\t\t\t\t--byteCount;\n\t\t\t} else if (0x800 > charCode) {\n\t\t\t\tbyteCount -= 2;\n\t\t\t} else {\n\t\t\t\tbyteCount -= 3;\n\t\t\t}\n\t\t}\n\t\tvar str = this.str.substr(1, charCount);\n\t\tthis.str = this.str.substr(1 + charCount).replace(/^\\s+/, '');\n\t\treturn str;\n\t}\n});\n\nvar edgePaths = {};\nvar edgeHeads = {};\n\nvar CanvizEntity = Class.create({\n\tinitialize: function(defaultAttrHashName, name, canviz, rootGraph, parentGraph, immediateGraph) {\n\t\tthis.defaultAttrHashName = defaultAttrHashName;\n\t\tthis.name = name;\n\t\tthis.canviz = canviz;\n\t\tthis.rootGraph = rootGraph;\n\t\tthis.parentGraph = parentGraph;\n\t\tthis.immediateGraph = immediateGraph;\n\t\tthis.attrs = $H();\n\t\tthis.drawAttrs = $H();\n\t},\n\tinitBB: function() {\n\t\tvar matches = this.getAttr('pos').match(/([0-9.]+),([0-9.]+)/);\n\t\tvar x = Math.round(matches[1]);\n\t\tvar y = Math.round(this.canviz.height - matches[2]);\n\t\tthis.bbRect = new Rect(x, y, x, y);\n\t},\n\tgetAttr: function(attrName, escString) {\n\t\tif (Object.isUndefined(escString)) escString = false;\n\t\tvar attrValue = this.attrs.get(attrName);\n\t\tif (Object.isUndefined(attrValue)) {\n\t\t\tvar graph = this.parentGraph;\n\t\t\twhile (!Object.isUndefined(graph)) {\n\t\t\t\tattrValue = graph[this.defaultAttrHashName].get(attrName);\n\t\t\t\tif (Object.isUndefined(attrValue)) {\n\t\t\t\t\tgraph = graph.parentGraph;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (attrValue && escString) {\n\t\t\tattrValue = attrValue.replace(this.escStringMatchRe, function(match, p1) {\n\t\t\t\tswitch (p1) {\n\t\t\t\t\tcase 'N': // fall through\n\t\t\t\t\tcase 'E': return this.name;\n\t\t\t\t\tcase 'T': return this.tailNode;\n\t\t\t\t\tcase 'H': return this.headNode;\n\t\t\t\t\tcase 'G': return this.immediateGraph.name;\n\t\t\t\t\tcase 'L': return this.getAttr('label', true);\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t}.bind(this));\n\t\t}\n\t\treturn attrValue;\n\t},\n\tdraw: function(ctx, ctxScale, redrawCanvasOnly) {\n\t\tvar i, tokens, fillColor, strokeColor;\n\t\tif (!redrawCanvasOnly) {\n\t\t\tthis.initBB();\n\t\t\tvar bbDiv = new Element('div');\n\t\t\tthis.canviz.elements.appendChild(bbDiv);\n\t\t}\n\t\tthis.drawAttrs.each(function(drawAttr) {\n\t\t\tvar command = drawAttr.value;\n//\t\t\tdebug(command);\n\t\t\tvar tokenizer = new CanvizTokenizer(command);\n\t\t\tvar token = tokenizer.takeChars();\n\t\t\tif (token) {\n\t\t\t\tvar dashStyle = 'solid';\n\t\t\t\tctx.save();\n\t\t\t\twhile (token) {\n//\t\t\t\t\tdebug('processing token ' + token);\n\t\t\t\t\tswitch (token) {\n\t\t\t\t\t\tcase 'E': // filled ellipse\n\t\t\t\t\t\tcase 'e': // unfilled ellipse\n\t\t\t\t\t\t\tvar filled = ('E' == token);\n\t\t\t\t\t\t\tvar cx = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar cy = this.canviz.height - tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar rx = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar ry = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar path = new Ellipse(cx, cy, rx, ry);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'P': // filled polygon\n\t\t\t\t\t\tcase 'p': // unfilled polygon\n\t\t\t\t\t\tcase 'L': // polyline\n\t\t\t\t\t\t\tvar filled = ('P' == token);\n\t\t\t\t\t\t\tvar closed = ('L' != token);\n\t\t\t\t\t\t\tvar numPoints = tokenizer.takeNumber();\n\t\t\t\t\t\t\ttokens = tokenizer.takeNumber(2 * numPoints); // points\n\t\t\t\t\t\t\tvar path = new Path();\n\t\t\t\t\t\t\tfor (i = 2; i < 2 * numPoints; i += 2) {\n\t\t\t\t\t\t\t\tpath.addBezier([\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i - 2], this.canviz.height - tokens[i - 1]),\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i],     this.canviz.height - tokens[i + 1])\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (closed) {\n\t\t\t\t\t\t\t\tpath.addBezier([\n\t\t\t\t\t\t\t\t\tnew Point(tokens[2 * numPoints - 2], this.canviz.height - tokens[2 * numPoints - 1]),\n\t\t\t\t\t\t\t\t\tnew Point(tokens[0],                  this.canviz.height - tokens[1])\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'B': // unfilled b-spline\n\t\t\t\t\t\tcase 'b': // filled b-spline\n\t\t\t\t\t\t\tvar filled = ('b' == token);\n\t\t\t\t\t\t\tvar numPoints = tokenizer.takeNumber();\n\t\t\t\t\t\t\ttokens = tokenizer.takeNumber(2 * numPoints); // points\n\t\t\t\t\t\t\tvar path = new Path();\n\t\t\t\t\t\t\tfor (i = 2; i < 2 * numPoints; i += 6) {\n\t\t\t\t\t\t\t\tpath.addBezier([\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i - 2], this.canviz.height - tokens[i - 1]),\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i],     this.canviz.height - tokens[i + 1]),\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i + 2], this.canviz.height - tokens[i + 3]),\n\t\t\t\t\t\t\t\t\tnew Point(tokens[i + 4], this.canviz.height - tokens[i + 5])\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'I': // image\n\t\t\t\t\t\t\tvar l = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar b = this.canviz.height - tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar w = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar h = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar src = tokenizer.takeString();\n\t\t\t\t\t\t\tif (!this.canviz.images[src]) {\n\t\t\t\t\t\t\t\tthis.canviz.images[src] = new CanvizImage(this.canviz, src);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.canviz.images[src].draw(ctx, l, b - h, w, h);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'T': // text\n\t\t\t\t\t\t\tvar l = Math.round(ctxScale * tokenizer.takeNumber() + this.canviz.padding);\n\t\t\t\t\t\t\tvar t = Math.round(ctxScale * this.canviz.height + 2 * this.canviz.padding - (ctxScale * (tokenizer.takeNumber() + this.canviz.bbScale * fontSize) + this.canviz.padding));\n\t\t\t\t\t\t\tvar textAlign = tokenizer.takeNumber();\n\t\t\t\t\t\t\tvar textWidth = Math.round(ctxScale * tokenizer.takeNumber());\n\t\t\t\t\t\t\tvar str = tokenizer.takeString();\n\t\t\t\t\t\t\tif (!redrawCanvasOnly && !/^\\s*$/.test(str)) {\n//\t\t\t\t\t\t\t\tdebug('draw text ' + str + ' ' + l + ' ' + t + ' ' + textAlign + ' ' + textWidth);\n\t\t\t\t\t\t\t\tstr = str.escapeHTML();\n\t\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\t\tmatches = str.match(/ ( +)/);\n\t\t\t\t\t\t\t\t\tif (matches) {\n\t\t\t\t\t\t\t\t\t\tvar spaces = ' ';\n\t\t\t\t\t\t\t\t\t\tmatches[1].length.times(function() {\n\t\t\t\t\t\t\t\t\t\t\tspaces += '&nbsp;';\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tstr = str.replace(/  +/, spaces);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} while (matches);\n\t\t\t\t\t\t\t\tvar text;\n\t\t\t\t\t\t\t\tvar href = this.getAttr('URL', true) || this.getAttr('href', true);\n\t\t\t\t\t\t\t\tif (href) {\n\t\t\t\t\t\t\t\t\tvar target = this.getAttr('target', true) || '_self';\n\t\t\t\t\t\t\t\t\tvar tooltip = this.getAttr('tooltip', true) || this.getAttr('label', true);\n//\t\t\t\t\t\t\t\t\tdebug(this.name + ', href ' + href + ', target ' + target + ', tooltip ' + tooltip);\n                                    text = new Element('a', {href: href, target: target, title: tooltip});\n                                    // modified here to pass through an ID for the <a> element\n\t\t\t\t\t\t\t\t\t['id', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout'].each(function(attrName) {\n\t\t\t\t\t\t\t\t\t\tvar attrValue = this.getAttr(attrName, true);\n\t\t\t\t\t\t\t\t\t\tif (attrValue) {\n\t\t\t\t\t\t\t\t\t\t\ttext.writeAttribute(attrName, attrValue);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t\t\t\t\ttext.setStyle({\n\t\t\t\t\t\t\t\t\t\ttextDecoration: 'none'\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\ttext = new Element('span');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttext.update(str);\n\t\t\t\t\t\t\t\ttext.setStyle({\n\t\t\t\t\t\t\t\t\tfontSize: Math.round(fontSize * ctxScale * this.canviz.bbScale) + 'px',\n\t\t\t\t\t\t\t\t\tfontFamily: fontFamily,\n\t\t\t\t\t\t\t\t\tcolor: strokeColor.textColor,\n\t\t\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\t\t\ttextAlign: (-1 == textAlign) ? 'left' : (1 == textAlign) ? 'right' : 'center',\n\t\t\t\t\t\t\t\t\tleft: (l - (1 + textAlign) * textWidth) + 'px',\n\t\t\t\t\t\t\t\t\ttop: t + 'px',\n\t\t\t\t\t\t\t\t\twidth: (2 * textWidth) + 'px'\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tif (1 != strokeColor.opacity) text.setOpacity(strokeColor.opacity);\n\t\t\t\t\t\t\t\tthis.canviz.elements.appendChild(text);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'C': // set fill color\n\t\t\t\t\t\tcase 'c': // set pen color\n\t\t\t\t\t\t\tvar fill = ('C' == token);\n\t\t\t\t\t\t\tvar color = this.parseColor(tokenizer.takeString());\n\t\t\t\t\t\t\tif (fill) {\n\t\t\t\t\t\t\t\tfillColor = color;\n\t\t\t\t\t\t\t\tctx.fillStyle = color.canvasColor;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tstrokeColor = color;\n\t\t\t\t\t\t\t\tctx.strokeStyle = color.canvasColor;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'F': // set font\n\t\t\t\t\t\t\tfontSize = tokenizer.takeNumber();\n\t\t\t\t\t\t\tfontFamily = tokenizer.takeString();\n\t\t\t\t\t\t\tswitch (fontFamily) {\n\t\t\t\t\t\t\t\tcase 'Times-Roman':\n\t\t\t\t\t\t\t\t\tfontFamily = 'Times New Roman';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'Courier':\n\t\t\t\t\t\t\t\t\tfontFamily = 'Courier New';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'Helvetica':\n\t\t\t\t\t\t\t\t\tfontFamily = 'Arial';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t// nothing\n\t\t\t\t\t\t\t}\n//\t\t\t\t\t\t\tdebug('set font ' + fontSize + 'pt ' + fontFamily);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'S': // set style\n\t\t\t\t\t\t\tvar style = tokenizer.takeString();\n\t\t\t\t\t\t\tswitch (style) {\n\t\t\t\t\t\t\t\tcase 'solid':\n\t\t\t\t\t\t\t\tcase 'filled':\n\t\t\t\t\t\t\t\t\t// nothing\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'dashed':\n\t\t\t\t\t\t\t\tcase 'dotted':\n\t\t\t\t\t\t\t\t\tdashStyle = style;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'bold':\n\t\t\t\t\t\t\t\t\tctx.lineWidth = 2;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tmatches = style.match(/^setlinewidth\\((.*)\\)$/);\n\t\t\t\t\t\t\t\t\tif (matches) {\n\t\t\t\t\t\t\t\t\t\tctx.lineWidth = Number(matches[1]);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tdebug('unknown style ' + style);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tdebug('unknown token ' + token);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (path) {\n\t\t\t\t\t\tthis.canviz.drawPath(ctx, path, filled, dashStyle);\n\t\t\t\t\t\tif (!redrawCanvasOnly) this.bbRect.expandToInclude(path.getBB());\n                        // store edge paths so they can be redrawn\n                        if ( drawAttr.key == '_draw_' )\n                            edgePaths[this.getAttr(\"eid\")] = path;\n                        if ( drawAttr.key == '_hdraw_' )\n                            edgeHeads[this.getAttr(\"eid\")] = path;\n\t\t\t\t\t\tpath = undefined;\n\t\t\t\t\t}\n\t\t\t\t\ttoken = tokenizer.takeChars();\n\t\t\t\t}\n\t\t\t\tif (!redrawCanvasOnly) {\n\t\t\t\t\tbbDiv.setStyle({\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tleft:   Math.round(ctxScale * this.bbRect.l + this.canviz.padding) + 'px',\n\t\t\t\t\t\ttop:    Math.round(ctxScale * this.bbRect.t + this.canviz.padding) + 'px',\n\t\t\t\t\t\twidth:  Math.round(ctxScale * this.bbRect.getWidth()) + 'px',\n\t\t\t\t\t\theight: Math.round(ctxScale * this.bbRect.getHeight()) + 'px'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tctx.restore();\n\t\t\t}\n\t\t}.bind(this));\n\t},\n\tparseColor: function(color) {\n\t\tvar parsedColor = {opacity: 1};\n\t\t// rgb/rgba\n\t\tif (/^#(?:[0-9a-f]{2}\\s*){3,4}$/i.test(color)) {\n\t\t\treturn this.canviz.parseHexColor(color);\n\t\t}\n\t\t// hsv\n\t\tvar matches = color.match(/^(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)$/);\n\t\tif (matches) {\n\t\t\tparsedColor.canvasColor = parsedColor.textColor = this.canviz.hsvToRgbColor(matches[1], matches[2], matches[3]);\n\t\t\treturn parsedColor;\n\t\t}\n\t\t// named color\n\t\tvar colorScheme = this.getAttr('colorscheme') || 'X11';\n\t\tvar colorName = color;\n\t\tmatches = color.match(/^\\/(.*)\\/(.*)$/);\n\t\tif (matches) {\n\t\t\tif (matches[1]) {\n\t\t\t\tcolorScheme = matches[1];\n\t\t\t}\n\t\t\tcolorName = matches[2];\n\t\t} else {\n\t\t\tmatches = color.match(/^\\/(.*)$/);\n\t\t\tif (matches) {\n\t\t\t\tcolorScheme = 'X11';\n\t\t\t\tcolorName = matches[1];\n\t\t\t}\n\t\t}\n\t\tcolorName = colorName.toLowerCase();\n\t\tvar colorSchemeName = colorScheme.toLowerCase();\n\t\tvar colorSchemeData = Canviz.prototype.colors.get(colorSchemeName);\n\t\tif (colorSchemeData) {\n\t\t\tvar colorData = colorSchemeData[colorName];\n\t\t\tif (colorData) {\n\t\t\t\treturn this.canviz.parseHexColor('#' + colorData);\n\t\t\t}\n\t\t}\n\t\tcolorData = Canviz.prototype.colors.get('fallback')[colorName];\n\t\tif (colorData) {\n\t\t\treturn this.canviz.parseHexColor('#' + colorData);\n\t\t}\n\t\tif (!colorSchemeData) {\n\t\t\tdebug('unknown color scheme ' + colorScheme);\n\t\t}\n\t\t// unknown\n\t\tdebug('unknown color ' + color + '; color scheme is ' + colorScheme);\n\t\tparsedColor.canvasColor = parsedColor.textColor = '#000000';\n\t\treturn parsedColor;\n\t}\n});\n\nvar CanvizNode = Class.create(CanvizEntity, {\n\tinitialize: function($super, name, canviz, rootGraph, parentGraph) {\n\t\t$super('nodeAttrs', name, canviz, rootGraph, parentGraph, parentGraph);\n\t}\n});\nObject.extend(CanvizNode.prototype, {\n\tescStringMatchRe: /\\\\([NGL])/g\n});\n\nvar CanvizEdge = Class.create(CanvizEntity, {\n\tinitialize: function($super, name, canviz, rootGraph, parentGraph, tailNode, headNode) {\n\t\t$super('edgeAttrs', name, canviz, rootGraph, parentGraph, parentGraph);\n\t\tthis.tailNode = tailNode;\n\t\tthis.headNode = headNode;\n\t}\n});\nObject.extend(CanvizEdge.prototype, {\n\tescStringMatchRe: /\\\\([EGTHL])/g\n});\n\nvar CanvizGraph = Class.create(CanvizEntity, {\n\tinitialize: function($super, name, canviz, rootGraph, parentGraph) {\n\t\t$super('attrs', name, canviz, rootGraph, parentGraph, this);\n\t\tthis.nodeAttrs = $H();\n\t\tthis.edgeAttrs = $H();\n\t\tthis.nodes = $A();\n\t\tthis.edges = $A();\n\t\tthis.subgraphs = $A();\n\t},\n\tinitBB: function() {\n\t\tvar coords = this.getAttr('bb').split(',');\n\t\tthis.bbRect = new Rect(coords[0], this.canviz.height - coords[1], coords[2], this.canviz.height - coords[3]);\n\t},\n\tdraw: function($super, ctx, ctxScale, redrawCanvasOnly) {\n\t\t$super(ctx, ctxScale, redrawCanvasOnly);\n// modifed, was:\n//\t\t[this.subgraphs, this.nodes, this.edges].each(function(type) {\n\t\t[this.subgraphs, this.edges, this.nodes].each(function(type) {\n\t\t\ttype.each(function(entity) {\n\t\t\t\tentity.draw(ctx, ctxScale, redrawCanvasOnly);\n\t\t\t});\n\t\t});\n\t}\n});\nObject.extend(CanvizGraph.prototype, {\n\tescStringMatchRe: /\\\\([GL])/g\n});\n\nvar Canviz = Class.create({\n\tmaxXdotVersion: '1.2',\n\tcolors: $H({\n\t\tfallback:{\n\t\t\tblack:'000000',\n\t\t\tlightgrey:'d3d3d3',\n\t\t\twhite:'ffffff'\n\t\t}\n\t}),\n\tinitialize: function(container, url, urlParams) {\n\t\t// excanvas can't init the element if we use new Element()\n\t\tthis.canvas = document.createElement('canvas');\n\t\tElement.setStyle(this.canvas, {\n\t\t\tposition: 'absolute'\n\t\t});\n\t\tif (!Canviz.canvasCounter) Canviz.canvasCounter = 0;\n\t\tthis.canvas.id = 'canviz_canvas_' + ++Canviz.canvasCounter;\n\t\tthis.elements = new Element('div');\n\t\tthis.elements.setStyle({\n\t\t\tposition: 'absolute'\n\t\t});\n\t\tthis.container = $(container);\n\t\tthis.container.setStyle({\n\t\t\tposition: 'relative'\n\t\t});\n\t\tthis.container.appendChild(this.canvas);\n\t\tif (Prototype.Browser.IE) {\n\t\t\tG_vmlCanvasManager.initElement(this.canvas);\n\t\t\tthis.canvas = $(this.canvas.id);\n\t\t}\n\t\tthis.container.appendChild(this.elements);\n\t\tthis.ctx = this.canvas.getContext('2d');\n\t\tthis.scale = 1;\n\t\tthis.padding = 8;\n\t\tthis.dashLength = 6;\n\t\tthis.dotSpacing = 4;\n\t\tthis.graphs = $A();\n\t\tthis.images = new Hash();\n\t\tthis.numImages = 0;\n\t\tthis.numImagesFinished = 0;\n\t\tif (url) {\n\t\t\tthis.load(url, urlParams);\n\t\t}\n\t},\n\tsetScale: function(scale) {\n\t\tthis.scale = scale;\n\t},\n\tsetImagePath: function(imagePath) {\n\t\tthis.imagePath = imagePath;\n\t},\n\tload: function(url, urlParams) {\n\t\t$('debug_output').innerHTML = '';\n\t\tnew Ajax.Request(url, {\n\t\t\tmethod: 'get',\n\t\t\tparameters: urlParams,\n\t\t\tonComplete: function(response) {\n\t\t\t\tthis.parse(response.responseText);\n\t\t\t}.bind(this)\n\t\t});\n\t},\n\tparse: function(xdot) {\n\t\tthis.graphs = $A();\n\t\tthis.width = 0;\n\t\tthis.height = 0;\n\t\tthis.maxWidth = false;\n\t\tthis.maxHeight = false;\n\t\tthis.bbEnlarge = false;\n\t\tthis.bbScale = 1;\n\t\tthis.dpi = 96;\n\t\tthis.bgcolor = {opacity: 1};\n\t\tthis.bgcolor.canvasColor = this.bgcolor.textColor = '#ffffff';\n\t\tvar lines = xdot.split(/\\r?\\n/);\n\t\tvar i = 0;\n\t\tvar line, lastChar, matches, rootGraph, isGraph, entity, entityName, attrs, attrName, attrValue, attrHash, drawAttrHash;\n\t\tvar containers = $A();\n\t\twhile (i < lines.length) {\n\t\t\tline = lines[i++].replace(/^\\s+/, '');\n\t\t\tif ('' != line && '#' != line.substr(0, 1)) {\n\t\t\t\twhile (i < lines.length && ';' != (lastChar = line.substr(line.length - 1, line.length)) && '{' != lastChar && '}' != lastChar) {\n\t\t\t\t\tif ('\\\\' == lastChar) {\n\t\t\t\t\t\tline = line.substr(0, line.length - 1);\n\t\t\t\t\t}\n\t\t\t\t\tline += lines[i++];\n\t\t\t\t}\n//\t\t\t\tdebug(line);\n\t\t\t\tif (0 == containers.length) {\n\t\t\t\t\tmatches = line.match(this.graphMatchRe);\n\t\t\t\t\tif (matches) {\n\t\t\t\t\t\trootGraph = new CanvizGraph(matches[3], this);\n\t\t\t\t\t\tcontainers.unshift(rootGraph);\n\t\t\t\t\t\tcontainers[0].strict = !Object.isUndefined(matches[1]);\n\t\t\t\t\t\tcontainers[0].type = ('graph' == matches[2]) ? 'undirected' : 'directed';\n\t\t\t\t\t\tcontainers[0].attrs.set('xdotversion', '1.0');\n\t\t\t\t\t\tthis.graphs.push(containers[0]);\n//\t\t\t\t\t\tdebug('graph: ' + containers[0].name);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmatches = line.match(this.subgraphMatchRe);\n\t\t\t\t\tif (matches) {\n\t\t\t\t\t\tcontainers.unshift(new CanvizGraph(matches[1], this, rootGraph, containers[0]));\n\t\t\t\t\t\tcontainers[1].subgraphs.push(containers[0]);\n//\t\t\t\t\t\tdebug('subgraph: ' + containers[0].name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (matches) {\n//\t\t\t\t\tdebug('begin container ' + containers[0].name);\n\t\t\t\t} else if ('}' == line) {\n//\t\t\t\t\tdebug('end container ' + containers[0].name);\n\t\t\t\t\tcontainers.shift();\n\t\t\t\t\tif (0 == containers.length) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmatches = line.match(this.nodeMatchRe);\n\t\t\t\t\tif (matches) {\n\t\t\t\t\t\tentityName = matches[2];\n\t\t\t\t\t\tattrs = matches[5];\n\t\t\t\t\t\tdrawAttrHash = containers[0].drawAttrs;\n\t\t\t\t\t\tisGraph = false;\n\t\t\t\t\t\tswitch (entityName) {\n\t\t\t\t\t\t\tcase 'graph':\n\t\t\t\t\t\t\t\tattrHash = containers[0].attrs;\n\t\t\t\t\t\t\t\tisGraph = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'node':\n\t\t\t\t\t\t\t\tattrHash = containers[0].nodeAttrs;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'edge':\n\t\t\t\t\t\t\t\tattrHash = containers[0].edgeAttrs;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tentity = new CanvizNode(entityName, this, rootGraph, containers[0]);\n\t\t\t\t\t\t\t\tattrHash = entity.attrs;\n\t\t\t\t\t\t\t\tdrawAttrHash = entity.drawAttrs;\n\t\t\t\t\t\t\t\tcontainers[0].nodes.push(entity);\n\t\t\t\t\t\t}\n//\t\t\t\t\t\tdebug('node: ' + entityName);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmatches = line.match(this.edgeMatchRe);\n\t\t\t\t\t\tif (matches) {\n\t\t\t\t\t\t\tentityName = matches[1];\n\t\t\t\t\t\t\tattrs = matches[8];\n\t\t\t\t\t\t\tentity = new CanvizEdge(entityName, this, rootGraph, containers[0], matches[2], matches[5]);\n\t\t\t\t\t\t\tattrHash = entity.attrs;\n\t\t\t\t\t\t\tdrawAttrHash = entity.drawAttrs;\n\t\t\t\t\t\t\tcontainers[0].edges.push(entity);\n//\t\t\t\t\t\t\tdebug('edge: ' + entityName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (matches) {\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\tif (0 == attrs.length) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmatches = attrs.match(this.attrMatchRe);\n\t\t\t\t\t\t\tif (matches) {\n\t\t\t\t\t\t\t\tattrs = attrs.substr(matches[0].length);\n\t\t\t\t\t\t\t\tattrName = matches[1];\n\t\t\t\t\t\t\t\tattrValue = this.unescape(matches[2]);\n\t\t\t\t\t\t\t\tif (/^_.*draw_$/.test(attrName)) {\n\t\t\t\t\t\t\t\t\tdrawAttrHash.set(attrName, attrValue);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tattrHash.set(attrName, attrValue);\n\t\t\t\t\t\t\t\t}\n//\t\t\t\t\t\t\t\tdebug(attrName + ' ' + attrValue);\n\t\t\t\t\t\t\t\tif (isGraph && 1 == containers.length) {\n\t\t\t\t\t\t\t\t\tswitch (attrName) {\n\t\t\t\t\t\t\t\t\t\tcase 'bb':\n\t\t\t\t\t\t\t\t\t\t\tvar bb = attrValue.split(/,/);\n\t\t\t\t\t\t\t\t\t\t\tthis.width  = Number(bb[2]);\n\t\t\t\t\t\t\t\t\t\t\tthis.height = Number(bb[3]);\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tcase 'bgcolor':\n\t\t\t\t\t\t\t\t\t\t\tthis.bgcolor = rootGraph.parseColor(attrValue);\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tcase 'dpi':\n\t\t\t\t\t\t\t\t\t\t\tthis.dpi = attrValue;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tcase 'size':\n\t\t\t\t\t\t\t\t\t\t\tvar size = attrValue.match(/^(\\d+|\\d*(?:\\.\\d+)),\\s*(\\d+|\\d*(?:\\.\\d+))(!?)$/);\n\t\t\t\t\t\t\t\t\t\t\tif (size) {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.maxWidth  = 72 * Number(size[1]);\n\t\t\t\t\t\t\t\t\t\t\t\tthis.maxHeight = 72 * Number(size[2]);\n\t\t\t\t\t\t\t\t\t\t\t\tthis.bbEnlarge = ('!' == size[3]);\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\tdebug('can\\'t parse size');\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tcase 'xdotversion':\n\t\t\t\t\t\t\t\t\t\t\tif (0 > this.versionCompare(this.maxXdotVersion, attrHash.get('xdotversion'))) {\n\t\t\t\t\t\t\t\t\t\t\t\tdebug('unsupported xdotversion ' + attrHash.get('xdotversion') + '; this script currently supports up to xdotversion ' + this.maxXdotVersion);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdebug('can\\'t read attributes for entity ' + entityName + ' from ' + attrs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} while (matches);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n/*\n\t\tif (this.maxWidth && this.maxHeight) {\n\t\t\tif (this.width > this.maxWidth || this.height > this.maxHeight || this.bbEnlarge) {\n\t\t\t\tthis.bbScale = Math.min(this.maxWidth / this.width, this.maxHeight / this.height);\n\t\t\t\tthis.width  = Math.round(this.width  * this.bbScale);\n\t\t\t\tthis.height = Math.round(this.height * this.bbScale);\n\t\t\t}\n\t\t}\n*/\n//\t\tdebug('done');\n\t\tthis.draw();\n\t},\n\tdraw: function(redrawCanvasOnly) {\n\t\tif (Object.isUndefined(redrawCanvasOnly)) redrawCanvasOnly = false;\n\t\tvar ctxScale = this.scale * this.dpi / 72;\n\t\tvar width  = Math.round(ctxScale * this.width  + 2 * this.padding);\n\t\tvar height = Math.round(ctxScale * this.height + 2 * this.padding);\n\t\tif (!redrawCanvasOnly) {\n\t\t\tthis.canvas.width  = width;\n\t\t\tthis.canvas.height = height;\n\t\t\tthis.canvas.setStyle({\n\t\t\t\twidth:  width  + 'px',\n\t\t\t\theight: height + 'px'\n\t\t\t});\n\t\t\tthis.container.setStyle({\n\t\t\t\twidth:  width  + 'px'\n\t\t\t});\n\t\t\twhile (this.elements.firstChild) {\n\t\t\t\tthis.elements.removeChild(this.elements.firstChild);\n\t\t\t}\n\t\t}\n\t\tthis.ctx.save();\n\t\tthis.ctx.lineCap = 'round';\n\t\tthis.ctx.fillStyle = this.bgcolor.canvasColor;\n\t\tthis.ctx.fillRect(0, 0, width, height);\n\t\tthis.ctx.translate(this.padding, this.padding);\n\t\tthis.ctx.scale(ctxScale, ctxScale);\n\t\tthis.graphs[0].draw(this.ctx, ctxScale, redrawCanvasOnly);\n\t\tthis.ctx.restore();\n\t},\n\tdrawPath: function(ctx, path, filled, dashStyle) {\n\t\tif (filled) {\n\t\t\tctx.beginPath();\n\t\t\tpath.makePath(ctx);\n\t\t\tctx.fill();\n\t\t}\n\t\tif (ctx.fillStyle != ctx.strokeStyle || !filled) {\n\t\t\tswitch (dashStyle) {\n\t\t\t\tcase 'dashed':\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tpath.makeDashedPath(ctx, this.dashLength);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'dotted':\n\t\t\t\t\tvar oldLineWidth = ctx.lineWidth;\n\t\t\t\t\tctx.lineWidth *= 2;\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tpath.makeDottedPath(ctx, this.dotSpacing);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'solid':\n\t\t\t\tdefault:\n\t\t\t\t\tif (!filled) {\n\t\t\t\t\t\tctx.beginPath();\n\t\t\t\t\t\tpath.makePath(ctx);\n\t\t\t\t\t}\n\t\t\t}\n\t\t\tctx.stroke();\n\t\t\tif (oldLineWidth) ctx.lineWidth = oldLineWidth;\n\t\t}\n\t},\n\tunescape: function(str) {\n\t\tvar matches = str.match(/^\"(.*)\"$/);\n\t\tif (matches) {\n\t\t\treturn matches[1].replace(/\\\\\"/g, '\"');\n\t\t} else {\n\t\t\treturn str;\n\t\t}\n\t},\n\tparseHexColor: function(color) {\n\t\tvar matches = color.match(/^#([0-9a-f]{2})\\s*([0-9a-f]{2})\\s*([0-9a-f]{2})\\s*([0-9a-f]{2})?$/i);\n\t\tif (matches) {\n\t\t\tvar canvasColor, textColor = '#' + matches[1] + matches[2] + matches[3], opacity = 1;\n\t\t\tif (matches[4]) { // rgba\n\t\t\t\topacity = parseInt(matches[4], 16) / 255;\n\t\t\t\tcanvasColor = 'rgba(' + parseInt(matches[1], 16) + ',' + parseInt(matches[2], 16) + ',' + parseInt(matches[3], 16) + ',' + opacity + ')';\n\t\t\t} else { // rgb\n\t\t\t\tcanvasColor = textColor;\n\t\t\t}\n\t\t}\n\t\treturn {canvasColor: canvasColor, textColor: textColor, opacity: opacity};\n\t},\n\thsvToRgbColor: function(h, s, v) {\n\t\tvar i, f, p, q, t, r, g, b;\n\t\th *= 360;\n\t\ti = Math.floor(h / 60) % 6;\n\t\tf = h / 60 - i;\n\t\tp = v * (1 - s);\n\t\tq = v * (1 - f * s);\n\t\tt = v * (1 - (1 - f) * s);\n\t\tswitch (i) {\n\t\t\tcase 0: r = v; g = t; b = p; break;\n\t\t\tcase 1: r = q; g = v; b = p; break;\n\t\t\tcase 2: r = p; g = v; b = t; break;\n\t\t\tcase 3: r = p; g = q; b = v; break;\n\t\t\tcase 4: r = t; g = p; b = v; break;\n\t\t\tcase 5: r = v; g = p; b = q; break;\n\t\t}\n\t\treturn 'rgb(' + Math.round(255 * r) + ',' + Math.round(255 * g) + ',' + Math.round(255 * b) + ')';\n\t},\n\tversionCompare: function(a, b) {\n\t\ta = a.split('.');\n\t\tb = b.split('.');\n\t\tvar a1, b1;\n\t\twhile (a.length || b.length) {\n\t\t\ta1 = a.length ? a.shift() : 0;\n\t\t\tb1 = b.length ? b.shift() : 0;\n\t\t\tif (a1 < b1) return -1;\n\t\t\tif (a1 > b1) return 1;\n\t\t}\n\t\treturn 0;\n\t},\n\t// an alphanumeric string or a number or a double-quoted string or an HTML string\n\tidMatch: '([a-zA-Z\\u0080-\\uFFFF_][0-9a-zA-Z\\u0080-\\uFFFF_]*|-?(?:\\\\.\\\\d+|\\\\d+(?:\\\\.\\\\d*)?)|\"(?:\\\\\\\\\"|[^\"])*\"|<(?:<[^>]*>|[^<>]+?)+>)'\n});\nObject.extend(Canviz.prototype, {\n\t// ID or ID:port or ID:compassPoint or ID:port:compassPoint\n\tnodeIdMatch: Canviz.prototype.idMatch + '(?::' + Canviz.prototype.idMatch + ')?(?::' + Canviz.prototype.idMatch + ')?'\n});\nObject.extend(Canviz.prototype, {\n\tgraphMatchRe: new RegExp('^(strict\\\\s+)?(graph|digraph)(?:\\\\s+' + Canviz.prototype.idMatch + ')?\\\\s*{$', 'i'),\n\tsubgraphMatchRe: new RegExp('^(?:subgraph\\\\s+)?' + Canviz.prototype.idMatch + '?\\\\s*{$', 'i'),\n\tnodeMatchRe: new RegExp('^(' + Canviz.prototype.nodeIdMatch + ')\\\\s+\\\\[(.+)\\\\];$'),\n\tedgeMatchRe: new RegExp('^(' + Canviz.prototype.nodeIdMatch + '\\\\s*-[->]\\\\s*' + Canviz.prototype.nodeIdMatch + ')\\\\s+\\\\[(.+)\\\\];$'),\n\tattrMatchRe: new RegExp('^' + Canviz.prototype.idMatch + '=' + Canviz.prototype.idMatch + '(?:[,\\\\s]+|$)')\n});\n\nvar CanvizImage = Class.create({\n\tinitialize: function(canviz, src) {\n\t\tthis.canviz = canviz;\n\t\t++this.canviz.numImages;\n\t\tthis.finished = this.loaded = false;\n\t\tthis.img = new Image();\n\t\tthis.img.onload = this.onLoad.bind(this);\n\t\tthis.img.onerror = this.onFinish.bind(this);\n\t\tthis.img.onabort = this.onFinish.bind(this);\n\t\tthis.img.src = this.canviz.imagePath + src;\n\t},\n\tonLoad: function() {\n\t\tthis.loaded = true;\n\t\tthis.onFinish();\n\t},\n\tonFinish: function() {\n\t\tthis.finished = true;\n\t\t++this.canviz.numImagesFinished;\n\t\tif (this.canviz.numImages == this.canviz.numImagesFinished) {\n\t\t\tthis.canviz.draw(true);\n\t\t}\n\t},\n\tdraw: function(ctx, l, t, w, h) {\n\t\tif (this.finished) {\n\t\t\tif (this.loaded) {\n\t\t\t\tctx.drawImage(this.img, l, t, w, h);\n\t\t\t} else {\n\t\t\t\tdebug('can\\'t load image ' + this.img.src);\n\t\t\t\tthis.drawBrokenImage(ctx, l, t, w, h);\n\t\t\t}\n\t\t}\n\t},\n\tdrawBrokenImage: function(ctx, l, t, w, h) {\n\t\tctx.save();\n\t\tctx.beginPath();\n\t\tnew Rect(l, t, l + w, t + w).draw(ctx);\n\t\tctx.moveTo(l, t);\n\t\tctx.lineTo(l + w, t + w);\n\t\tctx.moveTo(l + w, t);\n\t\tctx.lineTo(l, t + h);\n\t\tctx.strokeStyle = '#f00';\n\t\tctx.lineWidth = 1;\n\t\tctx.stroke();\n\t\tctx.restore();\n\t}\n});\n\nfunction debug(str, escape) {\n\tstr = String(str);\n\tif (Object.isUndefined(escape)) {\n\t\tescape = true;\n\t}\n\tif (escape) {\n\t\tstr = str.escapeHTML();\n\t}\n\t$('debug_output').innerHTML += '&raquo;' + str + '&laquo;<br />';\n}\n"
  },
  {
    "path": "canviz-0.1/path/path.js",
    "content": "// $Id: path.js 262 2009-05-19 11:55:24Z ryandesign.com $\n\nvar Point = Class.create({\n\tinitialize: function(x, y) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t},\n\toffset: function(dx, dy) {\n\t\tthis.x += dx;\n\t\tthis.y += dy;\n\t},\n\tdistanceFrom: function(point) {\n\t\tvar dx = this.x - point.x;\n\t\tvar dy = this.y - point.y;\n\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t},\n\tmakePath: function(ctx) {\n\t\tctx.moveTo(this.x, this.y);\n\t\tctx.lineTo(this.x + 0.001, this.y);\n\t}\n});\n\nvar Bezier = Class.create({\n\tinitialize: function(points) {\n\t\tthis.points = points;\n\t\tthis.order = points.length;\n\t},\n\treset: function() {\n\t\twith (Bezier.prototype) {\n\t\t\tthis.controlPolygonLength = controlPolygonLength;\n\t\t\tthis.chordLength = chordLength;\n\t\t\tthis.triangle = triangle;\n\t\t\tthis.chordPoints = chordPoints;\n\t\t\tthis.coefficients = coefficients;\n\t\t}\n\t},\n\toffset: function(dx, dy) {\n\t\tthis.points.each(function(point) {\n\t\t\tpoint.offset(dx, dy);\n\t\t});\n\t\tthis.reset();\n\t},\n\tgetBB: function() {\n\t\tif (!this.order) return undefined;\n\t\tvar l, t, r, b, p = this.points[0];\n\t\tl = r = p.x;\n\t\tt = b = p.y;\n\t\tthis.points.each(function(point) {\n\t\t\tl = Math.min(l, point.x);\n\t\t\tt = Math.min(t, point.y);\n\t\t\tr = Math.max(r, point.x);\n\t\t\tb = Math.max(b, point.y);\n\t\t});\n\t\tvar rect = new Rect(l, t, r, b);\n\t\treturn (this.getBB = function() {return rect;})();\n\t},\n\tisPointInBB: function(x, y, tolerance) {\n\t\tif (Object.isUndefined(tolerance)) tolerance = 0;\n\t\tvar bb = this.getBB();\n\t\tif (0 < tolerance) {\n\t\t\tbb = Object.clone(bb);\n\t\t\tbb.inset(-tolerance, -tolerance);\n\t\t}\n\t\treturn !(x < bb.l || x > bb.r || y < bb.t || y > bb.b);\n\t},\n\tisPointOnBezier: function(x, y, tolerance) {\n\t\tif (Object.isUndefined(tolerance)) tolerance = 0;\n\t\tif (!this.isPointInBB(x, y, tolerance)) return false;\n\t\tvar segments = this.chordPoints();\n\t\tvar p1 = segments[0].p;\n\t\tvar p2, x1, y1, x2, y2, bb, twice_area, base, height;\n\t\tfor (var i = 1; i < segments.length; ++i) {\n\t\t\tp2 = segments[i].p;\n\t\t\tx1 = p1.x;\n\t\t\ty1 = p1.y;\n\t\t\tx2 = p2.x;\n\t\t\ty2 = p2.y;\n\t\t\tbb = new Rect(x1, y1, x2, y2);\n\t\t\tif (bb.isPointInBB(x, y, tolerance)) {\n\t\t\t\ttwice_area = Math.abs(x1 * y2 + x2 * y + x * y1 - x2 * y1 - x * y2 - x1 * y);\n\t\t\t\tbase = p1.distanceFrom(p2);\n\t\t\t\theight = twice_area / base;\n\t\t\t\tif (height <= tolerance) return true;\n\t\t\t}\n\t\t\tp1 = p2;\n\t\t}\n\t\treturn false;\n\t},\n\t// Based on Oliver Steele's bezier.js library.\n\tcontrolPolygonLength: function() {\n\t\tvar len = 0;\n\t\tfor (var i = 1; i < this.order; ++i) {\n\t\t\tlen += this.points[i - 1].distanceFrom(this.points[i]);\n\t\t}\n\t\treturn (this.controlPolygonLength = function() {return len;})();\n\t},\n\t// Based on Oliver Steele's bezier.js library.\n\tchordLength: function() {\n\t\tvar len = this.points[0].distanceFrom(this.points[this.order - 1]);\n\t\treturn (this.chordLength = function() {return len;})();\n\t},\n\t// From Oliver Steele's bezier.js library.\n\ttriangle: function() {\n\t\tvar upper = this.points;\n\t\tvar m = [upper];\n\t\tfor (var i = 1; i < this.order; ++i) {\n\t\t\tvar lower = [];\n\t\t\tfor (var j = 0; j < this.order - i; ++j) {\n\t\t\t\tvar c0 = upper[j];\n\t\t\t\tvar c1 = upper[j + 1];\n\t\t\t\tlower[j] = new Point((c0.x + c1.x) / 2, (c0.y + c1.y) / 2);\n\t\t\t}\n\t\t\tm.push(lower);\n\t\t\tupper = lower;\n\t\t}\n\t\treturn (this.triangle = function() {return m;})();\n\t},\n\t// Based on Oliver Steele's bezier.js library.\n\ttriangleAtT: function(t) {\n\t\tvar s = 1 - t;\n\t\tvar upper = this.points;\n\t\tvar m = [upper];\n\t\tfor (var i = 1; i < this.order; ++i) {\n\t\t\tvar lower = [];\n\t\t\tfor (var j = 0; j < this.order - i; ++j) {\n\t\t\t\tvar c0 = upper[j];\n\t\t\t\tvar c1 = upper[j + 1];\n\t\t\t\tlower[j] = new Point(c0.x * s + c1.x * t, c0.y * s + c1.y * t);\n\t\t\t}\n\t\t\tm.push(lower);\n\t\t\tupper = lower;\n\t\t}\n\t\treturn m;\n\t},\n\t// Returns two beziers resulting from splitting this bezier at t=0.5.\n\t// Based on Oliver Steele's bezier.js library.\n\tsplit: function(t) {\n\t\tif ('undefined' == typeof t) t = 0.5;\n\t\tvar m = (0.5 == t) ? this.triangle() : this.triangleAtT(t);\n\t\tvar leftPoints  = new Array(this.order);\n\t\tvar rightPoints = new Array(this.order);\n\t\tfor (var i = 0; i < this.order; ++i) {\n\t\t\tleftPoints[i]  = m[i][0];\n\t\t\trightPoints[i] = m[this.order - 1 - i][i];\n\t\t}\n\t\treturn {left: new Bezier(leftPoints), right: new Bezier(rightPoints)};\n\t},\n\t// Returns a bezier which is the portion of this bezier from t1 to t2.\n\t// Thanks to Peter Zin on comp.graphics.algorithms.\n\tmid: function(t1, t2) {\n\t\treturn this.split(t2).left.split(t1 / t2).right;\n\t},\n\t// Returns points (and their corresponding times in the bezier) that form\n\t// an approximate polygonal representation of the bezier.\n\t// Based on the algorithm described in Jeremy Gibbons' dashed.ps.gz\n\tchordPoints: function() {\n\t\tvar p = [{tStart: 0, tEnd: 0, dt: 0, p: this.points[0]}].concat(this._chordPoints(0, 1));\n\t\treturn (this.chordPoints = function() {return p;})();\n\t},\n\t_chordPoints: function(tStart, tEnd) {\n\t\tvar tolerance = 0.001;\n\t\tvar dt = tEnd - tStart;\n\t\tif (this.controlPolygonLength() <= (1 + tolerance) * this.chordLength()) {\n\t\t\treturn [{tStart: tStart, tEnd: tEnd, dt: dt, p: this.points[this.order - 1]}];\n\t\t} else {\n\t\t\tvar tMid = tStart + dt / 2;\n\t\t\tvar halves = this.split();\n\t\t\treturn halves.left._chordPoints(tStart, tMid).concat(halves.right._chordPoints(tMid, tEnd));\n\t\t}\n\t},\n\t// Returns an array of times between 0 and 1 that mark the bezier evenly\n\t// in space.\n\t// Based in part on the algorithm described in Jeremy Gibbons' dashed.ps.gz\n\tmarkedEvery: function(distance, firstDistance) {\n\t\tvar nextDistance = firstDistance || distance;\n\t\tvar segments = this.chordPoints();\n\t\tvar times = [];\n\t\tvar t = 0; // time\n\t\tvar dt; // delta t\n\t\tvar segment;\n\t\tvar remainingDistance;\n\t\tfor (var i = 1; i < segments.length; ++i) {\n\t\t\tsegment = segments[i];\n\t\t\tsegment.length = segment.p.distanceFrom(segments[i - 1].p);\n\t\t\tif (0 == segment.length) {\n\t\t\t\tt += segment.dt;\n\t\t\t} else {\n\t\t\t\tdt = nextDistance / segment.length * segment.dt;\n\t\t\t\tsegment.remainingLength = segment.length;\n\t\t\t\twhile (segment.remainingLength >= nextDistance) {\n\t\t\t\t\tsegment.remainingLength -= nextDistance;\n\t\t\t\t\tt += dt;\n\t\t\t\t\ttimes.push(t);\n\t\t\t\t\tif (distance != nextDistance) {\n\t\t\t\t\t\tnextDistance = distance;\n\t\t\t\t\t\tdt = nextDistance / segment.length * segment.dt;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnextDistance -= segment.remainingLength;\n\t\t\t\tt = segment.tEnd;\n\t\t\t}\n\t\t}\n\t\treturn {times: times, nextDistance: nextDistance};\n\t},\n\t// Return the coefficients of the polynomials for x and y in t.\n\t// From Oliver Steele's bezier.js library.\n\tcoefficients: function() {\n\t\t// This function deals with polynomials, represented as\n\t\t// arrays of coefficients.  p[i] is the coefficient of n^i.\n\t\t\n\t\t// p0, p1 => p0 + (p1 - p0) * n\n\t\t// side-effects (denormalizes) p0, for convienence\n\t\tfunction interpolate(p0, p1) {\n\t\t\tp0.push(0);\n\t\t\tvar p = new Array(p0.length);\n\t\t\tp[0] = p0[0];\n\t\t\tfor (var i = 0; i < p1.length; ++i) {\n\t\t\t\tp[i + 1] = p0[i + 1] + p1[i] - p0[i];\n\t\t\t}\n\t\t\treturn p;\n\t\t}\n\t\t// folds +interpolate+ across a graph whose fringe is\n\t\t// the polynomial elements of +ns+, and returns its TOP\n\t\tfunction collapse(ns) {\n\t\t\twhile (ns.length > 1) {\n\t\t\t\tvar ps = new Array(ns.length-1);\n\t\t\t\tfor (var i = 0; i < ns.length - 1; ++i) {\n\t\t\t\t\tps[i] = interpolate(ns[i], ns[i + 1]);\n\t\t\t\t}\n\t\t\t\tns = ps;\n\t\t\t}\n\t\t\treturn ns[0];\n\t\t}\n\t\t// xps and yps are arrays of polynomials --- concretely realized\n\t\t// as arrays of arrays\n\t\tvar xps = [];\n\t\tvar yps = [];\n\t\tfor (var i = 0, pt; pt = this.points[i++]; ) {\n\t\t\txps.push([pt.x]);\n\t\t\typs.push([pt.y]);\n\t\t}\n\t\tvar result = {xs: collapse(xps), ys: collapse(yps)};\n\t\treturn (this.coefficients = function() {return result;})();\n\t},\n\t// Return the point at time t.\n\t// From Oliver Steele's bezier.js library.\n\tpointAtT: function(t) {\n\t\tvar c = this.coefficients();\n\t\tvar cx = c.xs, cy = c.ys;\n\t\t// evaluate cx[0] + cx[1]t +cx[2]t^2 ....\n\t\t\n\t\t// optimization: start from the end, to save one\n\t\t// muliplicate per order (we never need an explicit t^n)\n\t\t\n\t\t// optimization: special-case the last element\n\t\t// to save a multiply-add\n\t\tvar x = cx[cx.length - 1], y = cy[cy.length - 1];\n\t\t\n\t\tfor (var i = cx.length - 1; --i >= 0; ) {\n\t\t\tx = x * t + cx[i];\n\t\t\ty = y * t + cy[i];\n\t\t}\n\t\treturn new Point(x, y);\n\t},\n\t// Render the Bezier to a WHATWG 2D canvas context.\n\t// Based on Oliver Steele's bezier.js library.\n\tmakePath: function (ctx, moveTo) {\n\t\tif ('undefined' == typeof moveTo) moveTo = true;\n\t\tif (moveTo) ctx.moveTo(this.points[0].x, this.points[0].y);\n\t\tvar fn = this.pathCommands[this.order];\n\t\tif (fn) {\n\t\t\tvar coords = [];\n\t\t\tfor (var i = 1 == this.order ? 0 : 1; i < this.points.length; ++i) {\n\t\t\t\tcoords.push(this.points[i].x);\n\t\t\t\tcoords.push(this.points[i].y);\n\t\t\t}\n\t\t\tfn.apply(ctx, coords);\n\t\t}\n\t},\n\t// Wrapper functions to work around Safari, in which, up to at least 2.0.3,\n\t// fn.apply isn't defined on the context primitives.\n\t// Based on Oliver Steele's bezier.js library.\n\tpathCommands: [\n\t\tnull,\n\t\t// This will have an effect if there's a line thickness or end cap.\n\t\tfunction(x, y) {\n\t\t\tthis.lineTo(x + 0.001, y);\n\t\t},\n\t\tfunction(x, y) {\n\t\t\tthis.lineTo(x, y);\n\t\t},\n\t\tfunction(x1, y1, x2, y2) {\n\t\t\tthis.quadraticCurveTo(x1, y1, x2, y2);\n\t\t},\n\t\tfunction(x1, y1, x2, y2, x3, y3) {\n\t\t\tthis.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n\t\t}\n\t],\n\tmakeDashedPath: function(ctx, dashLength, firstDistance, drawFirst) {\n\t\tif (!firstDistance) firstDistance = dashLength;\n\t\tif ('undefined' == typeof drawFirst) drawFirst = true;\n\t\tvar markedEvery = this.markedEvery(dashLength, firstDistance);\n\t\tif (drawFirst) markedEvery.times.unshift(0);\n\t\tvar drawLast = (markedEvery.times.length % 2);\n\t\tif (drawLast) markedEvery.times.push(1);\n\t\tfor (var i = 1; i < markedEvery.times.length; i += 2) {\n\t\t\tthis.mid(markedEvery.times[i - 1], markedEvery.times[i]).makePath(ctx);\n\t\t}\n\t\treturn {firstDistance: markedEvery.nextDistance, drawFirst: drawLast};\n\t},\n\tmakeDottedPath: function(ctx, dotSpacing, firstDistance) {\n\t\tif (!firstDistance) firstDistance = dotSpacing;\n\t\tvar markedEvery = this.markedEvery(dotSpacing, firstDistance);\n\t\tif (dotSpacing == firstDistance) markedEvery.times.unshift(0);\n\t\tmarkedEvery.times.each(function(t) {\n\t\t\tthis.pointAtT(t).makePath(ctx);\n\t\t}.bind(this));\n\t\treturn markedEvery.nextDistance;\n\t}\n});\n\nvar Path = Class.create({\n\tinitialize: function(segments) {\n\t\tthis.segments = segments || [];\n\t},\n\tsetupSegments: function() {},\n\t// Based on Oliver Steele's bezier.js library.\n\taddBezier: function(pointsOrBezier) {\n\t\tthis.segments.push(pointsOrBezier instanceof Array ? new Bezier(pointsOrBezier) : pointsOrBezier);\n\t},\n\toffset: function(dx, dy) {\n\t\tif (0 == this.segments.length) this.setupSegments();\n\t\tthis.segments.each(function(segment) {\n\t\t\tsegment.offset(dx, dy);\n\t\t});\n\t},\n\tgetBB: function() {\n\t\tif (0 == this.segments.length) this.setupSegments();\n\t\tvar l, t, r, b, p = this.segments[0].points[0];\n\t\tl = r = p.x;\n\t\tt = b = p.y;\n\t\tthis.segments.each(function(segment) {\n\t\t\tsegment.points.each(function(point) {\n\t\t\t\tl = Math.min(l, point.x);\n\t\t\t\tt = Math.min(t, point.y);\n\t\t\t\tr = Math.max(r, point.x);\n\t\t\t\tb = Math.max(b, point.y);\n\t\t\t});\n\t\t});\n\t\tvar rect = new Rect(l, t, r, b);\n\t\treturn (this.getBB = function() {return rect;})();\n\t},\n\tisPointInBB: function(x, y, tolerance) {\n\t\tif (Object.isUndefined(tolerance)) tolerance = 0;\n\t\tvar bb = this.getBB();\n\t\tif (0 < tolerance) {\n\t\t\tbb = Object.clone(bb);\n\t\t\tbb.inset(-tolerance, -tolerance);\n\t\t}\n\t\treturn !(x < bb.l || x > bb.r || y < bb.t || y > bb.b);\n\t},\n\tisPointOnPath: function(x, y, tolerance) {\n\t\tif (Object.isUndefined(tolerance)) tolerance = 0;\n\t\tif (!this.isPointInBB(x, y, tolerance)) return false;\n\t\tvar result = false;\n\t\tthis.segments.each(function(segment) {\n\t\t\tif (segment.isPointOnBezier(x, y, tolerance)) {\n\t\t\t\tresult = true;\n\t\t\t\tthrow $break;\n\t\t\t}\n\t\t});\n\t\treturn result;\n\t},\n\tisPointInPath: function(x, y) {\n\t\treturn false;\n\t},\n\t// Based on Oliver Steele's bezier.js library.\n\tmakePath: function(ctx) {\n\t\tif (0 == this.segments.length) this.setupSegments();\n\t\tvar moveTo = true;\n\t\tthis.segments.each(function(segment) {\n\t\t\tsegment.makePath(ctx, moveTo);\n\t\t\tmoveTo = false;\n\t\t});\n\t},\n\tmakeDashedPath: function(ctx, dashLength, firstDistance, drawFirst) {\n\t\tif (0 == this.segments.length) this.setupSegments();\n\t\tvar info = {\n\t\t\tdrawFirst: ('undefined' == typeof drawFirst) ? true : drawFirst,\n\t\t\tfirstDistance: firstDistance || dashLength\n\t\t};\n\t\tthis.segments.each(function(segment) {\n\t\t\tinfo = segment.makeDashedPath(ctx, dashLength, info.firstDistance, info.drawFirst);\n\t\t});\n\t},\n\tmakeDottedPath: function(ctx, dotSpacing, firstDistance) {\n\t\tif (0 == this.segments.length) this.setupSegments();\n\t\tif (!firstDistance) firstDistance = dotSpacing;\n\t\tthis.segments.each(function(segment) {\n\t\t\tfirstDistance = segment.makeDottedPath(ctx, dotSpacing, firstDistance);\n\t\t});\n\t}\n});\n\nvar Polygon = Class.create(Path, {\n\tinitialize: function($super, points) {\n\t\tthis.points = points || [];\n\t\t$super();\n\t},\n\tsetupSegments: function() {\n\t\tthis.points.each(function(p, i) {\n\t\t\tvar next = i + 1;\n\t\t\tif (this.points.length == next) next = 0;\n\t\t\tthis.addBezier([\n\t\t\t\tp,\n\t\t\t\tthis.points[next]\n\t\t\t]);\n\t\t}.bind(this));\n\t}\n});\n\nvar Rect = Class.create(Polygon, {\n\tinitialize: function($super, l, t, r, b) {\n\t\tthis.l = l;\n\t\tthis.t = t;\n\t\tthis.r = r;\n\t\tthis.b = b;\n\t\t$super();\n\t},\n\tinset: function (ix, iy) {\n\t\tthis.l += ix;\n\t\tthis.t += iy;\n\t\tthis.r -= ix;\n\t\tthis.b -= iy;\n\t\treturn this;\n\t},\n\texpandToInclude: function(rect) {\n\t\tthis.l = Math.min(this.l, rect.l);\n\t\tthis.t = Math.min(this.t, rect.t);\n\t\tthis.r = Math.max(this.r, rect.r);\n\t\tthis.b = Math.max(this.b, rect.b);\n\t},\n\tgetWidth: function() {\n\t\treturn this.r - this.l;\n\t},\n\tgetHeight: function() {\n\t\treturn this.b - this.t;\n\t},\n\tsetupSegments: function($super) {\n\t\tvar w = this.getWidth();\n\t\tvar h = this.getHeight();\n\t\tthis.points = [\n\t\t\tnew Point(this.l, this.t),\n\t\t\tnew Point(this.l + w, this.t),\n\t\t\tnew Point(this.l + w, this.t + h),\n\t\t\tnew Point(this.l, this.t + h)\n\t\t];\n\t\t$super();\n\t}\n});\n\nvar Ellipse = Class.create(Path, {\n\tKAPPA: 0.5522847498,\n\tinitialize: function($super, cx, cy, rx, ry) {\n\t\tthis.cx = cx; // center x\n\t\tthis.cy = cy; // center y\n\t\tthis.rx = rx; // radius x\n\t\tthis.ry = ry; // radius y\n\t\t$super();\n\t},\n\tsetupSegments: function() {\n\t\tthis.addBezier([\n\t\t\tnew Point(this.cx, this.cy - this.ry),\n\t\t\tnew Point(this.cx + this.KAPPA * this.rx, this.cy - this.ry),\n\t\t\tnew Point(this.cx + this.rx, this.cy - this.KAPPA * this.ry),\n\t\t\tnew Point(this.cx + this.rx, this.cy)\n\t\t]);\n\t\tthis.addBezier([\n\t\t\tnew Point(this.cx + this.rx, this.cy),\n\t\t\tnew Point(this.cx + this.rx, this.cy + this.KAPPA * this.ry),\n\t\t\tnew Point(this.cx + this.KAPPA * this.rx, this.cy + this.ry),\n\t\t\tnew Point(this.cx, this.cy + this.ry)\n\t\t]);\n\t\tthis.addBezier([\n\t\t\tnew Point(this.cx, this.cy + this.ry),\n\t\t\tnew Point(this.cx - this.KAPPA * this.rx, this.cy + this.ry),\n\t\t\tnew Point(this.cx - this.rx, this.cy + this.KAPPA * this.ry),\n\t\t\tnew Point(this.cx - this.rx, this.cy)\n\t\t]);\n\t\tthis.addBezier([\n\t\t\tnew Point(this.cx - this.rx, this.cy),\n\t\t\tnew Point(this.cx - this.rx, this.cy - this.KAPPA * this.ry),\n\t\t\tnew Point(this.cx - this.KAPPA * this.rx, this.cy - this.ry),\n\t\t\tnew Point(this.cx, this.cy - this.ry)\n\t\t]);\n\t}\n});\n"
  },
  {
    "path": "canviz-0.1/prototype/prototype.js",
    "content": "/*  Prototype JavaScript framework, version 1.6.0.3\n *  (c) 2005-2008 Sam Stephenson\n *\n *  Prototype is freely distributable under the terms of an MIT-style license.\n *  For details, see the Prototype web site: http://www.prototypejs.org/\n *\n *--------------------------------------------------------------------------*/\n\nvar Prototype = {\n  Version: '1.6.0.3',\n\n  Browser: {\n    IE:     !!(window.attachEvent &&\n      navigator.userAgent.indexOf('Opera') === -1),\n    Opera:  navigator.userAgent.indexOf('Opera') > -1,\n    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,\n    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&\n      navigator.userAgent.indexOf('KHTML') === -1,\n    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)\n  },\n\n  BrowserFeatures: {\n    XPath: !!document.evaluate,\n    SelectorsAPI: !!document.querySelector,\n    ElementExtensions: !!window.HTMLElement,\n    SpecificElementExtensions:\n      document.createElement('div')['__proto__'] &&\n      document.createElement('div')['__proto__'] !==\n        document.createElement('form')['__proto__']\n  },\n\n  ScriptFragment: '<script[^>]*>([\\\\S\\\\s]*?)<\\/script>',\n  JSONFilter: /^\\/\\*-secure-([\\s\\S]*)\\*\\/\\s*$/,\n\n  emptyFunction: function() { },\n  K: function(x) { return x }\n};\n\nif (Prototype.Browser.MobileSafari)\n  Prototype.BrowserFeatures.SpecificElementExtensions = false;\n\n\n/* Based on Alex Arnell's inheritance implementation. */\nvar Class = {\n  create: function() {\n    var parent = null, properties = $A(arguments);\n    if (Object.isFunction(properties[0]))\n      parent = properties.shift();\n\n    function klass() {\n      this.initialize.apply(this, arguments);\n    }\n\n    Object.extend(klass, Class.Methods);\n    klass.superclass = parent;\n    klass.subclasses = [];\n\n    if (parent) {\n      var subclass = function() { };\n      subclass.prototype = parent.prototype;\n      klass.prototype = new subclass;\n      parent.subclasses.push(klass);\n    }\n\n    for (var i = 0; i < properties.length; i++)\n      klass.addMethods(properties[i]);\n\n    if (!klass.prototype.initialize)\n      klass.prototype.initialize = Prototype.emptyFunction;\n\n    klass.prototype.constructor = klass;\n\n    return klass;\n  }\n};\n\nClass.Methods = {\n  addMethods: function(source) {\n    var ancestor   = this.superclass && this.superclass.prototype;\n    var properties = Object.keys(source);\n\n    if (!Object.keys({ toString: true }).length)\n      properties.push(\"toString\", \"valueOf\");\n\n    for (var i = 0, length = properties.length; i < length; i++) {\n      var property = properties[i], value = source[property];\n      if (ancestor && Object.isFunction(value) &&\n          value.argumentNames().first() == \"$super\") {\n        var method = value;\n        value = (function(m) {\n          return function() { return ancestor[m].apply(this, arguments) };\n        })(property).wrap(method);\n\n        value.valueOf = method.valueOf.bind(method);\n        value.toString = method.toString.bind(method);\n      }\n      this.prototype[property] = value;\n    }\n\n    return this;\n  }\n};\n\nvar Abstract = { };\n\nObject.extend = function(destination, source) {\n  for (var property in source)\n    destination[property] = source[property];\n  return destination;\n};\n\nObject.extend(Object, {\n  inspect: function(object) {\n    try {\n      if (Object.isUndefined(object)) return 'undefined';\n      if (object === null) return 'null';\n      return object.inspect ? object.inspect() : String(object);\n    } catch (e) {\n      if (e instanceof RangeError) return '...';\n      throw e;\n    }\n  },\n\n  toJSON: function(object) {\n    var type = typeof object;\n    switch (type) {\n      case 'undefined':\n      case 'function':\n      case 'unknown': return;\n      case 'boolean': return object.toString();\n    }\n\n    if (object === null) return 'null';\n    if (object.toJSON) return object.toJSON();\n    if (Object.isElement(object)) return;\n\n    var results = [];\n    for (var property in object) {\n      var value = Object.toJSON(object[property]);\n      if (!Object.isUndefined(value))\n        results.push(property.toJSON() + ': ' + value);\n    }\n\n    return '{' + results.join(', ') + '}';\n  },\n\n  toQueryString: function(object) {\n    return $H(object).toQueryString();\n  },\n\n  toHTML: function(object) {\n    return object && object.toHTML ? object.toHTML() : String.interpret(object);\n  },\n\n  keys: function(object) {\n    var keys = [];\n    for (var property in object)\n      keys.push(property);\n    return keys;\n  },\n\n  values: function(object) {\n    var values = [];\n    for (var property in object)\n      values.push(object[property]);\n    return values;\n  },\n\n  clone: function(object) {\n    return Object.extend({ }, object);\n  },\n\n  isElement: function(object) {\n    return !!(object && object.nodeType == 1);\n  },\n\n  isArray: function(object) {\n    return object != null && typeof object == \"object\" &&\n      'splice' in object && 'join' in object;\n  },\n\n  isHash: function(object) {\n    return object instanceof Hash;\n  },\n\n  isFunction: function(object) {\n    return typeof object == \"function\";\n  },\n\n  isString: function(object) {\n    return typeof object == \"string\";\n  },\n\n  isNumber: function(object) {\n    return typeof object == \"number\";\n  },\n\n  isUndefined: function(object) {\n    return typeof object == \"undefined\";\n  }\n});\n\nObject.extend(Function.prototype, {\n  argumentNames: function() {\n    var names = this.toString().match(/^[\\s\\(]*function[^(]*\\(([^\\)]*)\\)/)[1]\n      .replace(/\\s+/g, '').split(',');\n    return names.length == 1 && !names[0] ? [] : names;\n  },\n\n  bind: function() {\n    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;\n    var __method = this, args = $A(arguments), object = args.shift();\n    return function() {\n      return __method.apply(object, args.concat($A(arguments)));\n    }\n  },\n\n  bindAsEventListener: function() {\n    var __method = this, args = $A(arguments), object = args.shift();\n    return function(event) {\n      return __method.apply(object, [event || window.event].concat(args));\n    }\n  },\n\n  curry: function() {\n    if (!arguments.length) return this;\n    var __method = this, args = $A(arguments);\n    return function() {\n      return __method.apply(this, args.concat($A(arguments)));\n    }\n  },\n\n  delay: function() {\n    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;\n    return window.setTimeout(function() {\n      return __method.apply(__method, args);\n    }, timeout);\n  },\n\n  defer: function() {\n    var args = [0.01].concat($A(arguments));\n    return this.delay.apply(this, args);\n  },\n\n  wrap: function(wrapper) {\n    var __method = this;\n    return function() {\n      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));\n    }\n  },\n\n  methodize: function() {\n    if (this._methodized) return this._methodized;\n    var __method = this;\n    return this._methodized = function() {\n      return __method.apply(null, [this].concat($A(arguments)));\n    };\n  }\n});\n\nDate.prototype.toJSON = function() {\n  return '\"' + this.getUTCFullYear() + '-' +\n    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +\n    this.getUTCDate().toPaddedString(2) + 'T' +\n    this.getUTCHours().toPaddedString(2) + ':' +\n    this.getUTCMinutes().toPaddedString(2) + ':' +\n    this.getUTCSeconds().toPaddedString(2) + 'Z\"';\n};\n\nvar Try = {\n  these: function() {\n    var returnValue;\n\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      var lambda = arguments[i];\n      try {\n        returnValue = lambda();\n        break;\n      } catch (e) { }\n    }\n\n    return returnValue;\n  }\n};\n\nRegExp.prototype.match = RegExp.prototype.test;\n\nRegExp.escape = function(str) {\n  return String(str).replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$1');\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar PeriodicalExecuter = Class.create({\n  initialize: function(callback, frequency) {\n    this.callback = callback;\n    this.frequency = frequency;\n    this.currentlyExecuting = false;\n\n    this.registerCallback();\n  },\n\n  registerCallback: function() {\n    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n\n  execute: function() {\n    this.callback(this);\n  },\n\n  stop: function() {\n    if (!this.timer) return;\n    clearInterval(this.timer);\n    this.timer = null;\n  },\n\n  onTimerEvent: function() {\n    if (!this.currentlyExecuting) {\n      try {\n        this.currentlyExecuting = true;\n        this.execute();\n      } finally {\n        this.currentlyExecuting = false;\n      }\n    }\n  }\n});\nObject.extend(String, {\n  interpret: function(value) {\n    return value == null ? '' : String(value);\n  },\n  specialChar: {\n    '\\b': '\\\\b',\n    '\\t': '\\\\t',\n    '\\n': '\\\\n',\n    '\\f': '\\\\f',\n    '\\r': '\\\\r',\n    '\\\\': '\\\\\\\\'\n  }\n});\n\nObject.extend(String.prototype, {\n  gsub: function(pattern, replacement) {\n    var result = '', source = this, match;\n    replacement = arguments.callee.prepareReplacement(replacement);\n\n    while (source.length > 0) {\n      if (match = source.match(pattern)) {\n        result += source.slice(0, match.index);\n        result += String.interpret(replacement(match));\n        source  = source.slice(match.index + match[0].length);\n      } else {\n        result += source, source = '';\n      }\n    }\n    return result;\n  },\n\n  sub: function(pattern, replacement, count) {\n    replacement = this.gsub.prepareReplacement(replacement);\n    count = Object.isUndefined(count) ? 1 : count;\n\n    return this.gsub(pattern, function(match) {\n      if (--count < 0) return match[0];\n      return replacement(match);\n    });\n  },\n\n  scan: function(pattern, iterator) {\n    this.gsub(pattern, iterator);\n    return String(this);\n  },\n\n  truncate: function(length, truncation) {\n    length = length || 30;\n    truncation = Object.isUndefined(truncation) ? '...' : truncation;\n    return this.length > length ?\n      this.slice(0, length - truncation.length) + truncation : String(this);\n  },\n\n  strip: function() {\n    return this.replace(/^\\s+/, '').replace(/\\s+$/, '');\n  },\n\n  stripTags: function() {\n    return this.replace(/<\\/?[^>]+>/gi, '');\n  },\n\n  stripScripts: function() {\n    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');\n  },\n\n  extractScripts: function() {\n    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');\n    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');\n    return (this.match(matchAll) || []).map(function(scriptTag) {\n      return (scriptTag.match(matchOne) || ['', ''])[1];\n    });\n  },\n\n  evalScripts: function() {\n    return this.extractScripts().map(function(script) { return eval(script) });\n  },\n\n  escapeHTML: function() {\n    var self = arguments.callee;\n    self.text.data = this;\n    return self.div.innerHTML;\n  },\n\n  unescapeHTML: function() {\n    var div = new Element('div');\n    div.innerHTML = this.stripTags();\n    return div.childNodes[0] ? (div.childNodes.length > 1 ?\n      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :\n      div.childNodes[0].nodeValue) : '';\n  },\n\n  toQueryParams: function(separator) {\n    var match = this.strip().match(/([^?#]*)(#.*)?$/);\n    if (!match) return { };\n\n    return match[1].split(separator || '&').inject({ }, function(hash, pair) {\n      if ((pair = pair.split('='))[0]) {\n        var key = decodeURIComponent(pair.shift());\n        var value = pair.length > 1 ? pair.join('=') : pair[0];\n        if (value != undefined) value = decodeURIComponent(value);\n\n        if (key in hash) {\n          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];\n          hash[key].push(value);\n        }\n        else hash[key] = value;\n      }\n      return hash;\n    });\n  },\n\n  toArray: function() {\n    return this.split('');\n  },\n\n  succ: function() {\n    return this.slice(0, this.length - 1) +\n      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);\n  },\n\n  times: function(count) {\n    return count < 1 ? '' : new Array(count + 1).join(this);\n  },\n\n  camelize: function() {\n    var parts = this.split('-'), len = parts.length;\n    if (len == 1) return parts[0];\n\n    var camelized = this.charAt(0) == '-'\n      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)\n      : parts[0];\n\n    for (var i = 1; i < len; i++)\n      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);\n\n    return camelized;\n  },\n\n  capitalize: function() {\n    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();\n  },\n\n  underscore: function() {\n    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();\n  },\n\n  dasherize: function() {\n    return this.gsub(/_/,'-');\n  },\n\n  inspect: function(useDoubleQuotes) {\n    var escapedString = this.gsub(/[\\x00-\\x1f\\\\]/, function(match) {\n      var character = String.specialChar[match[0]];\n      return character ? character : '\\\\u00' + match[0].charCodeAt().toPaddedString(2, 16);\n    });\n    if (useDoubleQuotes) return '\"' + escapedString.replace(/\"/g, '\\\\\"') + '\"';\n    return \"'\" + escapedString.replace(/'/g, '\\\\\\'') + \"'\";\n  },\n\n  toJSON: function() {\n    return this.inspect(true);\n  },\n\n  unfilterJSON: function(filter) {\n    return this.sub(filter || Prototype.JSONFilter, '#{1}');\n  },\n\n  isJSON: function() {\n    var str = this;\n    if (str.blank()) return false;\n    str = this.replace(/\\\\./g, '@').replace(/\"[^\"\\\\\\n\\r]*\"/g, '');\n    return (/^[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]*$/).test(str);\n  },\n\n  evalJSON: function(sanitize) {\n    var json = this.unfilterJSON();\n    try {\n      if (!sanitize || json.isJSON()) return eval('(' + json + ')');\n    } catch (e) { }\n    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());\n  },\n\n  include: function(pattern) {\n    return this.indexOf(pattern) > -1;\n  },\n\n  startsWith: function(pattern) {\n    return this.indexOf(pattern) === 0;\n  },\n\n  endsWith: function(pattern) {\n    var d = this.length - pattern.length;\n    return d >= 0 && this.lastIndexOf(pattern) === d;\n  },\n\n  empty: function() {\n    return this == '';\n  },\n\n  blank: function() {\n    return /^\\s*$/.test(this);\n  },\n\n  interpolate: function(object, pattern) {\n    return new Template(this, pattern).evaluate(object);\n  }\n});\n\nif (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {\n  escapeHTML: function() {\n    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\n  },\n  unescapeHTML: function() {\n    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');\n  }\n});\n\nString.prototype.gsub.prepareReplacement = function(replacement) {\n  if (Object.isFunction(replacement)) return replacement;\n  var template = new Template(replacement);\n  return function(match) { return template.evaluate(match) };\n};\n\nString.prototype.parseQuery = String.prototype.toQueryParams;\n\nObject.extend(String.prototype.escapeHTML, {\n  div:  document.createElement('div'),\n  text: document.createTextNode('')\n});\n\nString.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);\n\nvar Template = Class.create({\n  initialize: function(template, pattern) {\n    this.template = template.toString();\n    this.pattern = pattern || Template.Pattern;\n  },\n\n  evaluate: function(object) {\n    if (Object.isFunction(object.toTemplateReplacements))\n      object = object.toTemplateReplacements();\n\n    return this.template.gsub(this.pattern, function(match) {\n      if (object == null) return '';\n\n      var before = match[1] || '';\n      if (before == '\\\\') return match[2];\n\n      var ctx = object, expr = match[3];\n      var pattern = /^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;\n      match = pattern.exec(expr);\n      if (match == null) return before;\n\n      while (match != null) {\n        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\\\\\]', ']') : match[1];\n        ctx = ctx[comp];\n        if (null == ctx || '' == match[3]) break;\n        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);\n        match = pattern.exec(expr);\n      }\n\n      return before + String.interpret(ctx);\n    });\n  }\n});\nTemplate.Pattern = /(^|.|\\r|\\n)(#\\{(.*?)\\})/;\n\nvar $break = { };\n\nvar Enumerable = {\n  each: function(iterator, context) {\n    var index = 0;\n    try {\n      this._each(function(value) {\n        iterator.call(context, value, index++);\n      });\n    } catch (e) {\n      if (e != $break) throw e;\n    }\n    return this;\n  },\n\n  eachSlice: function(number, iterator, context) {\n    var index = -number, slices = [], array = this.toArray();\n    if (number < 1) return array;\n    while ((index += number) < array.length)\n      slices.push(array.slice(index, index+number));\n    return slices.collect(iterator, context);\n  },\n\n  all: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result = true;\n    this.each(function(value, index) {\n      result = result && !!iterator.call(context, value, index);\n      if (!result) throw $break;\n    });\n    return result;\n  },\n\n  any: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result = false;\n    this.each(function(value, index) {\n      if (result = !!iterator.call(context, value, index))\n        throw $break;\n    });\n    return result;\n  },\n\n  collect: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var results = [];\n    this.each(function(value, index) {\n      results.push(iterator.call(context, value, index));\n    });\n    return results;\n  },\n\n  detect: function(iterator, context) {\n    var result;\n    this.each(function(value, index) {\n      if (iterator.call(context, value, index)) {\n        result = value;\n        throw $break;\n      }\n    });\n    return result;\n  },\n\n  findAll: function(iterator, context) {\n    var results = [];\n    this.each(function(value, index) {\n      if (iterator.call(context, value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  grep: function(filter, iterator, context) {\n    iterator = iterator || Prototype.K;\n    var results = [];\n\n    if (Object.isString(filter))\n      filter = new RegExp(filter);\n\n    this.each(function(value, index) {\n      if (filter.match(value))\n        results.push(iterator.call(context, value, index));\n    });\n    return results;\n  },\n\n  include: function(object) {\n    if (Object.isFunction(this.indexOf))\n      if (this.indexOf(object) != -1) return true;\n\n    var found = false;\n    this.each(function(value) {\n      if (value == object) {\n        found = true;\n        throw $break;\n      }\n    });\n    return found;\n  },\n\n  inGroupsOf: function(number, fillWith) {\n    fillWith = Object.isUndefined(fillWith) ? null : fillWith;\n    return this.eachSlice(number, function(slice) {\n      while(slice.length < number) slice.push(fillWith);\n      return slice;\n    });\n  },\n\n  inject: function(memo, iterator, context) {\n    this.each(function(value, index) {\n      memo = iterator.call(context, memo, value, index);\n    });\n    return memo;\n  },\n\n  invoke: function(method) {\n    var args = $A(arguments).slice(1);\n    return this.map(function(value) {\n      return value[method].apply(value, args);\n    });\n  },\n\n  max: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result;\n    this.each(function(value, index) {\n      value = iterator.call(context, value, index);\n      if (result == null || value >= result)\n        result = value;\n    });\n    return result;\n  },\n\n  min: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result;\n    this.each(function(value, index) {\n      value = iterator.call(context, value, index);\n      if (result == null || value < result)\n        result = value;\n    });\n    return result;\n  },\n\n  partition: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var trues = [], falses = [];\n    this.each(function(value, index) {\n      (iterator.call(context, value, index) ?\n        trues : falses).push(value);\n    });\n    return [trues, falses];\n  },\n\n  pluck: function(property) {\n    var results = [];\n    this.each(function(value) {\n      results.push(value[property]);\n    });\n    return results;\n  },\n\n  reject: function(iterator, context) {\n    var results = [];\n    this.each(function(value, index) {\n      if (!iterator.call(context, value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  sortBy: function(iterator, context) {\n    return this.map(function(value, index) {\n      return {\n        value: value,\n        criteria: iterator.call(context, value, index)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }).pluck('value');\n  },\n\n  toArray: function() {\n    return this.map();\n  },\n\n  zip: function() {\n    var iterator = Prototype.K, args = $A(arguments);\n    if (Object.isFunction(args.last()))\n      iterator = args.pop();\n\n    var collections = [this].concat(args).map($A);\n    return this.map(function(value, index) {\n      return iterator(collections.pluck(index));\n    });\n  },\n\n  size: function() {\n    return this.toArray().length;\n  },\n\n  inspect: function() {\n    return '#<Enumerable:' + this.toArray().inspect() + '>';\n  }\n};\n\nObject.extend(Enumerable, {\n  map:     Enumerable.collect,\n  find:    Enumerable.detect,\n  select:  Enumerable.findAll,\n  filter:  Enumerable.findAll,\n  member:  Enumerable.include,\n  entries: Enumerable.toArray,\n  every:   Enumerable.all,\n  some:    Enumerable.any\n});\nfunction $A(iterable) {\n  if (!iterable) return [];\n  if (iterable.toArray) return iterable.toArray();\n  var length = iterable.length || 0, results = new Array(length);\n  while (length--) results[length] = iterable[length];\n  return results;\n}\n\nif (Prototype.Browser.WebKit) {\n  $A = function(iterable) {\n    if (!iterable) return [];\n    // In Safari, only use the `toArray` method if it's not a NodeList.\n    // A NodeList is a function, has an function `item` property, and a numeric\n    // `length` property. Adapted from Google Doctype.\n    if (!(typeof iterable === 'function' && typeof iterable.length ===\n        'number' && typeof iterable.item === 'function') && iterable.toArray)\n      return iterable.toArray();\n    var length = iterable.length || 0, results = new Array(length);\n    while (length--) results[length] = iterable[length];\n    return results;\n  };\n}\n\nArray.from = $A;\n\nObject.extend(Array.prototype, Enumerable);\n\nif (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;\n\nObject.extend(Array.prototype, {\n  _each: function(iterator) {\n    for (var i = 0, length = this.length; i < length; i++)\n      iterator(this[i]);\n  },\n\n  clear: function() {\n    this.length = 0;\n    return this;\n  },\n\n  first: function() {\n    return this[0];\n  },\n\n  last: function() {\n    return this[this.length - 1];\n  },\n\n  compact: function() {\n    return this.select(function(value) {\n      return value != null;\n    });\n  },\n\n  flatten: function() {\n    return this.inject([], function(array, value) {\n      return array.concat(Object.isArray(value) ?\n        value.flatten() : [value]);\n    });\n  },\n\n  without: function() {\n    var values = $A(arguments);\n    return this.select(function(value) {\n      return !values.include(value);\n    });\n  },\n\n  reverse: function(inline) {\n    return (inline !== false ? this : this.toArray())._reverse();\n  },\n\n  reduce: function() {\n    return this.length > 1 ? this : this[0];\n  },\n\n  uniq: function(sorted) {\n    return this.inject([], function(array, value, index) {\n      if (0 == index || (sorted ? array.last() != value : !array.include(value)))\n        array.push(value);\n      return array;\n    });\n  },\n\n  intersect: function(array) {\n    return this.uniq().findAll(function(item) {\n      return array.detect(function(value) { return item === value });\n    });\n  },\n\n  clone: function() {\n    return [].concat(this);\n  },\n\n  size: function() {\n    return this.length;\n  },\n\n  inspect: function() {\n    return '[' + this.map(Object.inspect).join(', ') + ']';\n  },\n\n  toJSON: function() {\n    var results = [];\n    this.each(function(object) {\n      var value = Object.toJSON(object);\n      if (!Object.isUndefined(value)) results.push(value);\n    });\n    return '[' + results.join(', ') + ']';\n  }\n});\n\n// use native browser JS 1.6 implementation if available\nif (Object.isFunction(Array.prototype.forEach))\n  Array.prototype._each = Array.prototype.forEach;\n\nif (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {\n  i || (i = 0);\n  var length = this.length;\n  if (i < 0) i = length + i;\n  for (; i < length; i++)\n    if (this[i] === item) return i;\n  return -1;\n};\n\nif (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {\n  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;\n  var n = this.slice(0, i).reverse().indexOf(item);\n  return (n < 0) ? n : i - n - 1;\n};\n\nArray.prototype.toArray = Array.prototype.clone;\n\nfunction $w(string) {\n  if (!Object.isString(string)) return [];\n  string = string.strip();\n  return string ? string.split(/\\s+/) : [];\n}\n\nif (Prototype.Browser.Opera){\n  Array.prototype.concat = function() {\n    var array = [];\n    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      if (Object.isArray(arguments[i])) {\n        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)\n          array.push(arguments[i][j]);\n      } else {\n        array.push(arguments[i]);\n      }\n    }\n    return array;\n  };\n}\nObject.extend(Number.prototype, {\n  toColorPart: function() {\n    return this.toPaddedString(2, 16);\n  },\n\n  succ: function() {\n    return this + 1;\n  },\n\n  times: function(iterator, context) {\n    $R(0, this, true).each(iterator, context);\n    return this;\n  },\n\n  toPaddedString: function(length, radix) {\n    var string = this.toString(radix || 10);\n    return '0'.times(length - string.length) + string;\n  },\n\n  toJSON: function() {\n    return isFinite(this) ? this.toString() : 'null';\n  }\n});\n\n$w('abs round ceil floor').each(function(method){\n  Number.prototype[method] = Math[method].methodize();\n});\nfunction $H(object) {\n  return new Hash(object);\n};\n\nvar Hash = Class.create(Enumerable, (function() {\n\n  function toQueryPair(key, value) {\n    if (Object.isUndefined(value)) return key;\n    return key + '=' + encodeURIComponent(String.interpret(value));\n  }\n\n  return {\n    initialize: function(object) {\n      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);\n    },\n\n    _each: function(iterator) {\n      for (var key in this._object) {\n        var value = this._object[key], pair = [key, value];\n        pair.key = key;\n        pair.value = value;\n        iterator(pair);\n      }\n    },\n\n    set: function(key, value) {\n      return this._object[key] = value;\n    },\n\n    get: function(key) {\n      // simulating poorly supported hasOwnProperty\n      if (this._object[key] !== Object.prototype[key])\n        return this._object[key];\n    },\n\n    unset: function(key) {\n      var value = this._object[key];\n      delete this._object[key];\n      return value;\n    },\n\n    toObject: function() {\n      return Object.clone(this._object);\n    },\n\n    keys: function() {\n      return this.pluck('key');\n    },\n\n    values: function() {\n      return this.pluck('value');\n    },\n\n    index: function(value) {\n      var match = this.detect(function(pair) {\n        return pair.value === value;\n      });\n      return match && match.key;\n    },\n\n    merge: function(object) {\n      return this.clone().update(object);\n    },\n\n    update: function(object) {\n      return new Hash(object).inject(this, function(result, pair) {\n        result.set(pair.key, pair.value);\n        return result;\n      });\n    },\n\n    toQueryString: function() {\n      return this.inject([], function(results, pair) {\n        var key = encodeURIComponent(pair.key), values = pair.value;\n\n        if (values && typeof values == 'object') {\n          if (Object.isArray(values))\n            return results.concat(values.map(toQueryPair.curry(key)));\n        } else results.push(toQueryPair(key, values));\n        return results;\n      }).join('&');\n    },\n\n    inspect: function() {\n      return '#<Hash:{' + this.map(function(pair) {\n        return pair.map(Object.inspect).join(': ');\n      }).join(', ') + '}>';\n    },\n\n    toJSON: function() {\n      return Object.toJSON(this.toObject());\n    },\n\n    clone: function() {\n      return new Hash(this);\n    }\n  }\n})());\n\nHash.prototype.toTemplateReplacements = Hash.prototype.toObject;\nHash.from = $H;\nvar ObjectRange = Class.create(Enumerable, {\n  initialize: function(start, end, exclusive) {\n    this.start = start;\n    this.end = end;\n    this.exclusive = exclusive;\n  },\n\n  _each: function(iterator) {\n    var value = this.start;\n    while (this.include(value)) {\n      iterator(value);\n      value = value.succ();\n    }\n  },\n\n  include: function(value) {\n    if (value < this.start)\n      return false;\n    if (this.exclusive)\n      return value < this.end;\n    return value <= this.end;\n  }\n});\n\nvar $R = function(start, end, exclusive) {\n  return new ObjectRange(start, end, exclusive);\n};\n\nvar Ajax = {\n  getTransport: function() {\n    return Try.these(\n      function() {return new XMLHttpRequest()},\n      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\n      function() {return new ActiveXObject('Microsoft.XMLHTTP')}\n    ) || false;\n  },\n\n  activeRequestCount: 0\n};\n\nAjax.Responders = {\n  responders: [],\n\n  _each: function(iterator) {\n    this.responders._each(iterator);\n  },\n\n  register: function(responder) {\n    if (!this.include(responder))\n      this.responders.push(responder);\n  },\n\n  unregister: function(responder) {\n    this.responders = this.responders.without(responder);\n  },\n\n  dispatch: function(callback, request, transport, json) {\n    this.each(function(responder) {\n      if (Object.isFunction(responder[callback])) {\n        try {\n          responder[callback].apply(responder, [request, transport, json]);\n        } catch (e) { }\n      }\n    });\n  }\n};\n\nObject.extend(Ajax.Responders, Enumerable);\n\nAjax.Responders.register({\n  onCreate:   function() { Ajax.activeRequestCount++ },\n  onComplete: function() { Ajax.activeRequestCount-- }\n});\n\nAjax.Base = Class.create({\n  initialize: function(options) {\n    this.options = {\n      method:       'post',\n      asynchronous: true,\n      contentType:  'application/x-www-form-urlencoded',\n      encoding:     'UTF-8',\n      parameters:   '',\n      evalJSON:     true,\n      evalJS:       true\n    };\n    Object.extend(this.options, options || { });\n\n    this.options.method = this.options.method.toLowerCase();\n\n    if (Object.isString(this.options.parameters))\n      this.options.parameters = this.options.parameters.toQueryParams();\n    else if (Object.isHash(this.options.parameters))\n      this.options.parameters = this.options.parameters.toObject();\n  }\n});\n\nAjax.Request = Class.create(Ajax.Base, {\n  _complete: false,\n\n  initialize: function($super, url, options) {\n    $super(options);\n    this.transport = Ajax.getTransport();\n    this.request(url);\n  },\n\n  request: function(url) {\n    this.url = url;\n    this.method = this.options.method;\n    var params = Object.clone(this.options.parameters);\n\n    if (!['get', 'post'].include(this.method)) {\n      // simulate other verbs over post\n      params['_method'] = this.method;\n      this.method = 'post';\n    }\n\n    this.parameters = params;\n\n    if (params = Object.toQueryString(params)) {\n      // when GET, append parameters to URL\n      if (this.method == 'get')\n        this.url += (this.url.include('?') ? '&' : '?') + params;\n      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))\n        params += '&_=';\n    }\n\n    try {\n      var response = new Ajax.Response(this);\n      if (this.options.onCreate) this.options.onCreate(response);\n      Ajax.Responders.dispatch('onCreate', this, response);\n\n      this.transport.open(this.method.toUpperCase(), this.url,\n        this.options.asynchronous);\n\n      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);\n\n      this.transport.onreadystatechange = this.onStateChange.bind(this);\n      this.setRequestHeaders();\n\n      this.body = this.method == 'post' ? (this.options.postBody || params) : null;\n      this.transport.send(this.body);\n\n      /* Force Firefox to handle ready state 4 for synchronous requests */\n      if (!this.options.asynchronous && this.transport.overrideMimeType)\n        this.onStateChange();\n\n    }\n    catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  onStateChange: function() {\n    var readyState = this.transport.readyState;\n    if (readyState > 1 && !((readyState == 4) && this._complete))\n      this.respondToReadyState(this.transport.readyState);\n  },\n\n  setRequestHeaders: function() {\n    var headers = {\n      'X-Requested-With': 'XMLHttpRequest',\n      'X-Prototype-Version': Prototype.Version,\n      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'\n    };\n\n    if (this.method == 'post') {\n      headers['Content-type'] = this.options.contentType +\n        (this.options.encoding ? '; charset=' + this.options.encoding : '');\n\n      /* Force \"Connection: close\" for older Mozilla browsers to work\n       * around a bug where XMLHttpRequest sends an incorrect\n       * Content-length header. See Mozilla Bugzilla #246651.\n       */\n      if (this.transport.overrideMimeType &&\n          (navigator.userAgent.match(/Gecko\\/(\\d{4})/) || [0,2005])[1] < 2005)\n            headers['Connection'] = 'close';\n    }\n\n    // user-defined headers\n    if (typeof this.options.requestHeaders == 'object') {\n      var extras = this.options.requestHeaders;\n\n      if (Object.isFunction(extras.push))\n        for (var i = 0, length = extras.length; i < length; i += 2)\n          headers[extras[i]] = extras[i+1];\n      else\n        $H(extras).each(function(pair) { headers[pair.key] = pair.value });\n    }\n\n    for (var name in headers)\n      this.transport.setRequestHeader(name, headers[name]);\n  },\n\n  success: function() {\n    var status = this.getStatus();\n    return !status || (status >= 200 && status < 300);\n  },\n\n  getStatus: function() {\n    try {\n      return this.transport.status || 0;\n    } catch (e) { return 0 }\n  },\n\n  respondToReadyState: function(readyState) {\n    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);\n\n    if (state == 'Complete') {\n      try {\n        this._complete = true;\n        (this.options['on' + response.status]\n         || this.options['on' + (this.success() ? 'Success' : 'Failure')]\n         || Prototype.emptyFunction)(response, response.headerJSON);\n      } catch (e) {\n        this.dispatchException(e);\n      }\n\n      var contentType = response.getHeader('Content-type');\n      if (this.options.evalJS == 'force'\n          || (this.options.evalJS && this.isSameOrigin() && contentType\n          && contentType.match(/^\\s*(text|application)\\/(x-)?(java|ecma)script(;.*)?\\s*$/i)))\n        this.evalResponse();\n    }\n\n    try {\n      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);\n      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);\n    } catch (e) {\n      this.dispatchException(e);\n    }\n\n    if (state == 'Complete') {\n      // avoid memory leak in MSIE: clean up\n      this.transport.onreadystatechange = Prototype.emptyFunction;\n    }\n  },\n\n  isSameOrigin: function() {\n    var m = this.url.match(/^\\s*https?:\\/\\/[^\\/]*/);\n    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({\n      protocol: location.protocol,\n      domain: document.domain,\n      port: location.port ? ':' + location.port : ''\n    }));\n  },\n\n  getHeader: function(name) {\n    try {\n      return this.transport.getResponseHeader(name) || null;\n    } catch (e) { return null }\n  },\n\n  evalResponse: function() {\n    try {\n      return eval((this.transport.responseText || '').unfilterJSON());\n    } catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  dispatchException: function(exception) {\n    (this.options.onException || Prototype.emptyFunction)(this, exception);\n    Ajax.Responders.dispatch('onException', this, exception);\n  }\n});\n\nAjax.Request.Events =\n  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\n\nAjax.Response = Class.create({\n  initialize: function(request){\n    this.request = request;\n    var transport  = this.transport  = request.transport,\n        readyState = this.readyState = transport.readyState;\n\n    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {\n      this.status       = this.getStatus();\n      this.statusText   = this.getStatusText();\n      this.responseText = String.interpret(transport.responseText);\n      this.headerJSON   = this._getHeaderJSON();\n    }\n\n    if(readyState == 4) {\n      var xml = transport.responseXML;\n      this.responseXML  = Object.isUndefined(xml) ? null : xml;\n      this.responseJSON = this._getResponseJSON();\n    }\n  },\n\n  status:      0,\n  statusText: '',\n\n  getStatus: Ajax.Request.prototype.getStatus,\n\n  getStatusText: function() {\n    try {\n      return this.transport.statusText || '';\n    } catch (e) { return '' }\n  },\n\n  getHeader: Ajax.Request.prototype.getHeader,\n\n  getAllHeaders: function() {\n    try {\n      return this.getAllResponseHeaders();\n    } catch (e) { return null }\n  },\n\n  getResponseHeader: function(name) {\n    return this.transport.getResponseHeader(name);\n  },\n\n  getAllResponseHeaders: function() {\n    return this.transport.getAllResponseHeaders();\n  },\n\n  _getHeaderJSON: function() {\n    var json = this.getHeader('X-JSON');\n    if (!json) return null;\n    json = decodeURIComponent(escape(json));\n    try {\n      return json.evalJSON(this.request.options.sanitizeJSON ||\n        !this.request.isSameOrigin());\n    } catch (e) {\n      this.request.dispatchException(e);\n    }\n  },\n\n  _getResponseJSON: function() {\n    var options = this.request.options;\n    if (!options.evalJSON || (options.evalJSON != 'force' &&\n      !(this.getHeader('Content-type') || '').include('application/json')) ||\n        this.responseText.blank())\n          return null;\n    try {\n      return this.responseText.evalJSON(options.sanitizeJSON ||\n        !this.request.isSameOrigin());\n    } catch (e) {\n      this.request.dispatchException(e);\n    }\n  }\n});\n\nAjax.Updater = Class.create(Ajax.Request, {\n  initialize: function($super, container, url, options) {\n    this.container = {\n      success: (container.success || container),\n      failure: (container.failure || (container.success ? null : container))\n    };\n\n    options = Object.clone(options);\n    var onComplete = options.onComplete;\n    options.onComplete = (function(response, json) {\n      this.updateContent(response.responseText);\n      if (Object.isFunction(onComplete)) onComplete(response, json);\n    }).bind(this);\n\n    $super(url, options);\n  },\n\n  updateContent: function(responseText) {\n    var receiver = this.container[this.success() ? 'success' : 'failure'],\n        options = this.options;\n\n    if (!options.evalScripts) responseText = responseText.stripScripts();\n\n    if (receiver = $(receiver)) {\n      if (options.insertion) {\n        if (Object.isString(options.insertion)) {\n          var insertion = { }; insertion[options.insertion] = responseText;\n          receiver.insert(insertion);\n        }\n        else options.insertion(receiver, responseText);\n      }\n      else receiver.update(responseText);\n    }\n  }\n});\n\nAjax.PeriodicalUpdater = Class.create(Ajax.Base, {\n  initialize: function($super, container, url, options) {\n    $super(options);\n    this.onComplete = this.options.onComplete;\n\n    this.frequency = (this.options.frequency || 2);\n    this.decay = (this.options.decay || 1);\n\n    this.updater = { };\n    this.container = container;\n    this.url = url;\n\n    this.start();\n  },\n\n  start: function() {\n    this.options.onComplete = this.updateComplete.bind(this);\n    this.onTimerEvent();\n  },\n\n  stop: function() {\n    this.updater.options.onComplete = undefined;\n    clearTimeout(this.timer);\n    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\n  },\n\n  updateComplete: function(response) {\n    if (this.options.decay) {\n      this.decay = (response.responseText == this.lastText ?\n        this.decay * this.options.decay : 1);\n\n      this.lastText = response.responseText;\n    }\n    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);\n  },\n\n  onTimerEvent: function() {\n    this.updater = new Ajax.Updater(this.container, this.url, this.options);\n  }\n});\nfunction $(element) {\n  if (arguments.length > 1) {\n    for (var i = 0, elements = [], length = arguments.length; i < length; i++)\n      elements.push($(arguments[i]));\n    return elements;\n  }\n  if (Object.isString(element))\n    element = document.getElementById(element);\n  return Element.extend(element);\n}\n\nif (Prototype.BrowserFeatures.XPath) {\n  document._getElementsByXPath = function(expression, parentElement) {\n    var results = [];\n    var query = document.evaluate(expression, $(parentElement) || document,\n      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n    for (var i = 0, length = query.snapshotLength; i < length; i++)\n      results.push(Element.extend(query.snapshotItem(i)));\n    return results;\n  };\n}\n\n/*--------------------------------------------------------------------------*/\n\nif (!window.Node) var Node = { };\n\nif (!Node.ELEMENT_NODE) {\n  // DOM level 2 ECMAScript Language Binding\n  Object.extend(Node, {\n    ELEMENT_NODE: 1,\n    ATTRIBUTE_NODE: 2,\n    TEXT_NODE: 3,\n    CDATA_SECTION_NODE: 4,\n    ENTITY_REFERENCE_NODE: 5,\n    ENTITY_NODE: 6,\n    PROCESSING_INSTRUCTION_NODE: 7,\n    COMMENT_NODE: 8,\n    DOCUMENT_NODE: 9,\n    DOCUMENT_TYPE_NODE: 10,\n    DOCUMENT_FRAGMENT_NODE: 11,\n    NOTATION_NODE: 12\n  });\n}\n\n(function() {\n  var element = this.Element;\n  this.Element = function(tagName, attributes) {\n    attributes = attributes || { };\n    tagName = tagName.toLowerCase();\n    var cache = Element.cache;\n    if (Prototype.Browser.IE && attributes.name) {\n      tagName = '<' + tagName + ' name=\"' + attributes.name + '\">';\n      delete attributes.name;\n      return Element.writeAttribute(document.createElement(tagName), attributes);\n    }\n    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));\n    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);\n  };\n  Object.extend(this.Element, element || { });\n  if (element) this.Element.prototype = element.prototype;\n}).call(window);\n\nElement.cache = { };\n\nElement.Methods = {\n  visible: function(element) {\n    return $(element).style.display != 'none';\n  },\n\n  toggle: function(element) {\n    element = $(element);\n    Element[Element.visible(element) ? 'hide' : 'show'](element);\n    return element;\n  },\n\n  hide: function(element) {\n    element = $(element);\n    element.style.display = 'none';\n    return element;\n  },\n\n  show: function(element) {\n    element = $(element);\n    element.style.display = '';\n    return element;\n  },\n\n  remove: function(element) {\n    element = $(element);\n    element.parentNode.removeChild(element);\n    return element;\n  },\n\n  update: function(element, content) {\n    element = $(element);\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) return element.update().insert(content);\n    content = Object.toHTML(content);\n    element.innerHTML = content.stripScripts();\n    content.evalScripts.bind(content).defer();\n    return element;\n  },\n\n  replace: function(element, content) {\n    element = $(element);\n    if (content && content.toElement) content = content.toElement();\n    else if (!Object.isElement(content)) {\n      content = Object.toHTML(content);\n      var range = element.ownerDocument.createRange();\n      range.selectNode(element);\n      content.evalScripts.bind(content).defer();\n      content = range.createContextualFragment(content.stripScripts());\n    }\n    element.parentNode.replaceChild(content, element);\n    return element;\n  },\n\n  insert: function(element, insertions) {\n    element = $(element);\n\n    if (Object.isString(insertions) || Object.isNumber(insertions) ||\n        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))\n          insertions = {bottom:insertions};\n\n    var content, insert, tagName, childNodes;\n\n    for (var position in insertions) {\n      content  = insertions[position];\n      position = position.toLowerCase();\n      insert = Element._insertionTranslations[position];\n\n      if (content && content.toElement) content = content.toElement();\n      if (Object.isElement(content)) {\n        insert(element, content);\n        continue;\n      }\n\n      content = Object.toHTML(content);\n\n      tagName = ((position == 'before' || position == 'after')\n        ? element.parentNode : element).tagName.toUpperCase();\n\n      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\n\n      if (position == 'top' || position == 'after') childNodes.reverse();\n      childNodes.each(insert.curry(element));\n\n      content.evalScripts.bind(content).defer();\n    }\n\n    return element;\n  },\n\n  wrap: function(element, wrapper, attributes) {\n    element = $(element);\n    if (Object.isElement(wrapper))\n      $(wrapper).writeAttribute(attributes || { });\n    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);\n    else wrapper = new Element('div', wrapper);\n    if (element.parentNode)\n      element.parentNode.replaceChild(wrapper, element);\n    wrapper.appendChild(element);\n    return wrapper;\n  },\n\n  inspect: function(element) {\n    element = $(element);\n    var result = '<' + element.tagName.toLowerCase();\n    $H({'id': 'id', 'className': 'class'}).each(function(pair) {\n      var property = pair.first(), attribute = pair.last();\n      var value = (element[property] || '').toString();\n      if (value) result += ' ' + attribute + '=' + value.inspect(true);\n    });\n    return result + '>';\n  },\n\n  recursivelyCollect: function(element, property) {\n    element = $(element);\n    var elements = [];\n    while (element = element[property])\n      if (element.nodeType == 1)\n        elements.push(Element.extend(element));\n    return elements;\n  },\n\n  ancestors: function(element) {\n    return $(element).recursivelyCollect('parentNode');\n  },\n\n  descendants: function(element) {\n    return $(element).select(\"*\");\n  },\n\n  firstDescendant: function(element) {\n    element = $(element).firstChild;\n    while (element && element.nodeType != 1) element = element.nextSibling;\n    return $(element);\n  },\n\n  immediateDescendants: function(element) {\n    if (!(element = $(element).firstChild)) return [];\n    while (element && element.nodeType != 1) element = element.nextSibling;\n    if (element) return [element].concat($(element).nextSiblings());\n    return [];\n  },\n\n  previousSiblings: function(element) {\n    return $(element).recursivelyCollect('previousSibling');\n  },\n\n  nextSiblings: function(element) {\n    return $(element).recursivelyCollect('nextSibling');\n  },\n\n  siblings: function(element) {\n    element = $(element);\n    return element.previousSiblings().reverse().concat(element.nextSiblings());\n  },\n\n  match: function(element, selector) {\n    if (Object.isString(selector))\n      selector = new Selector(selector);\n    return selector.match($(element));\n  },\n\n  up: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(element.parentNode);\n    var ancestors = element.ancestors();\n    return Object.isNumber(expression) ? ancestors[expression] :\n      Selector.findElement(ancestors, expression, index);\n  },\n\n  down: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return element.firstDescendant();\n    return Object.isNumber(expression) ? element.descendants()[expression] :\n      Element.select(element, expression)[index || 0];\n  },\n\n  previous: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));\n    var previousSiblings = element.previousSiblings();\n    return Object.isNumber(expression) ? previousSiblings[expression] :\n      Selector.findElement(previousSiblings, expression, index);\n  },\n\n  next: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));\n    var nextSiblings = element.nextSiblings();\n    return Object.isNumber(expression) ? nextSiblings[expression] :\n      Selector.findElement(nextSiblings, expression, index);\n  },\n\n  select: function() {\n    var args = $A(arguments), element = $(args.shift());\n    return Selector.findChildElements(element, args);\n  },\n\n  adjacent: function() {\n    var args = $A(arguments), element = $(args.shift());\n    return Selector.findChildElements(element.parentNode, args).without(element);\n  },\n\n  identify: function(element) {\n    element = $(element);\n    var id = element.readAttribute('id'), self = arguments.callee;\n    if (id) return id;\n    do { id = 'anonymous_element_' + self.counter++ } while ($(id));\n    element.writeAttribute('id', id);\n    return id;\n  },\n\n  readAttribute: function(element, name) {\n    element = $(element);\n    if (Prototype.Browser.IE) {\n      var t = Element._attributeTranslations.read;\n      if (t.values[name]) return t.values[name](element, name);\n      if (t.names[name]) name = t.names[name];\n      if (name.include(':')) {\n        return (!element.attributes || !element.attributes[name]) ? null :\n         element.attributes[name].value;\n      }\n    }\n    return element.getAttribute(name);\n  },\n\n  writeAttribute: function(element, name, value) {\n    element = $(element);\n    var attributes = { }, t = Element._attributeTranslations.write;\n\n    if (typeof name == 'object') attributes = name;\n    else attributes[name] = Object.isUndefined(value) ? true : value;\n\n    for (var attr in attributes) {\n      name = t.names[attr] || attr;\n      value = attributes[attr];\n      if (t.values[attr]) name = t.values[attr](element, value);\n      if (value === false || value === null)\n        element.removeAttribute(name);\n      else if (value === true)\n        element.setAttribute(name, name);\n      else element.setAttribute(name, value);\n    }\n    return element;\n  },\n\n  getHeight: function(element) {\n    return $(element).getDimensions().height;\n  },\n\n  getWidth: function(element) {\n    return $(element).getDimensions().width;\n  },\n\n  classNames: function(element) {\n    return new Element.ClassNames(element);\n  },\n\n  hasClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    var elementClassName = element.className;\n    return (elementClassName.length > 0 && (elementClassName == className ||\n      new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\").test(elementClassName)));\n  },\n\n  addClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    if (!element.hasClassName(className))\n      element.className += (element.className ? ' ' : '') + className;\n    return element;\n  },\n\n  removeClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    element.className = element.className.replace(\n      new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), ' ').strip();\n    return element;\n  },\n\n  toggleClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    return element[element.hasClassName(className) ?\n      'removeClassName' : 'addClassName'](className);\n  },\n\n  // removes whitespace-only text node children\n  cleanWhitespace: function(element) {\n    element = $(element);\n    var node = element.firstChild;\n    while (node) {\n      var nextNode = node.nextSibling;\n      if (node.nodeType == 3 && !/\\S/.test(node.nodeValue))\n        element.removeChild(node);\n      node = nextNode;\n    }\n    return element;\n  },\n\n  empty: function(element) {\n    return $(element).innerHTML.blank();\n  },\n\n  descendantOf: function(element, ancestor) {\n    element = $(element), ancestor = $(ancestor);\n\n    if (element.compareDocumentPosition)\n      return (element.compareDocumentPosition(ancestor) & 8) === 8;\n\n    if (ancestor.contains)\n      return ancestor.contains(element) && ancestor !== element;\n\n    while (element = element.parentNode)\n      if (element == ancestor) return true;\n\n    return false;\n  },\n\n  scrollTo: function(element) {\n    element = $(element);\n    var pos = element.cumulativeOffset();\n    window.scrollTo(pos[0], pos[1]);\n    return element;\n  },\n\n  getStyle: function(element, style) {\n    element = $(element);\n    style = style == 'float' ? 'cssFloat' : style.camelize();\n    var value = element.style[style];\n    if (!value || value == 'auto') {\n      var css = document.defaultView.getComputedStyle(element, null);\n      value = css ? css[style] : null;\n    }\n    if (style == 'opacity') return value ? parseFloat(value) : 1.0;\n    return value == 'auto' ? null : value;\n  },\n\n  getOpacity: function(element) {\n    return $(element).getStyle('opacity');\n  },\n\n  setStyle: function(element, styles) {\n    element = $(element);\n    var elementStyle = element.style, match;\n    if (Object.isString(styles)) {\n      element.style.cssText += ';' + styles;\n      return styles.include('opacity') ?\n        element.setOpacity(styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]) : element;\n    }\n    for (var property in styles)\n      if (property == 'opacity') element.setOpacity(styles[property]);\n      else\n        elementStyle[(property == 'float' || property == 'cssFloat') ?\n          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :\n            property] = styles[property];\n\n    return element;\n  },\n\n  setOpacity: function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1 || value === '') ? '' :\n      (value < 0.00001) ? 0 : value;\n    return element;\n  },\n\n  getDimensions: function(element) {\n    element = $(element);\n    var display = element.getStyle('display');\n    if (display != 'none' && display != null) // Safari bug\n      return {width: element.offsetWidth, height: element.offsetHeight};\n\n    // All *Width and *Height properties give 0 on elements with display none,\n    // so enable the element temporarily\n    var els = element.style;\n    var originalVisibility = els.visibility;\n    var originalPosition = els.position;\n    var originalDisplay = els.display;\n    els.visibility = 'hidden';\n    els.position = 'absolute';\n    els.display = 'block';\n    var originalWidth = element.clientWidth;\n    var originalHeight = element.clientHeight;\n    els.display = originalDisplay;\n    els.position = originalPosition;\n    els.visibility = originalVisibility;\n    return {width: originalWidth, height: originalHeight};\n  },\n\n  makePositioned: function(element) {\n    element = $(element);\n    var pos = Element.getStyle(element, 'position');\n    if (pos == 'static' || !pos) {\n      element._madePositioned = true;\n      element.style.position = 'relative';\n      // Opera returns the offset relative to the positioning context, when an\n      // element is position relative but top and left have not been defined\n      if (Prototype.Browser.Opera) {\n        element.style.top = 0;\n        element.style.left = 0;\n      }\n    }\n    return element;\n  },\n\n  undoPositioned: function(element) {\n    element = $(element);\n    if (element._madePositioned) {\n      element._madePositioned = undefined;\n      element.style.position =\n        element.style.top =\n        element.style.left =\n        element.style.bottom =\n        element.style.right = '';\n    }\n    return element;\n  },\n\n  makeClipping: function(element) {\n    element = $(element);\n    if (element._overflow) return element;\n    element._overflow = Element.getStyle(element, 'overflow') || 'auto';\n    if (element._overflow !== 'hidden')\n      element.style.overflow = 'hidden';\n    return element;\n  },\n\n  undoClipping: function(element) {\n    element = $(element);\n    if (!element._overflow) return element;\n    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;\n    element._overflow = null;\n    return element;\n  },\n\n  cumulativeOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  positionedOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n      if (element) {\n        if (element.tagName.toUpperCase() == 'BODY') break;\n        var p = Element.getStyle(element, 'position');\n        if (p !== 'static') break;\n      }\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  absolutize: function(element) {\n    element = $(element);\n    if (element.getStyle('position') == 'absolute') return element;\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\n\n    var offsets = element.positionedOffset();\n    var top     = offsets[1];\n    var left    = offsets[0];\n    var width   = element.clientWidth;\n    var height  = element.clientHeight;\n\n    element._originalLeft   = left - parseFloat(element.style.left  || 0);\n    element._originalTop    = top  - parseFloat(element.style.top || 0);\n    element._originalWidth  = element.style.width;\n    element._originalHeight = element.style.height;\n\n    element.style.position = 'absolute';\n    element.style.top    = top + 'px';\n    element.style.left   = left + 'px';\n    element.style.width  = width + 'px';\n    element.style.height = height + 'px';\n    return element;\n  },\n\n  relativize: function(element) {\n    element = $(element);\n    if (element.getStyle('position') == 'relative') return element;\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\n\n    element.style.position = 'relative';\n    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);\n    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);\n\n    element.style.top    = top + 'px';\n    element.style.left   = left + 'px';\n    element.style.height = element._originalHeight;\n    element.style.width  = element._originalWidth;\n    return element;\n  },\n\n  cumulativeScrollOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.scrollTop  || 0;\n      valueL += element.scrollLeft || 0;\n      element = element.parentNode;\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  getOffsetParent: function(element) {\n    if (element.offsetParent) return $(element.offsetParent);\n    if (element == document.body) return $(element);\n\n    while ((element = element.parentNode) && element != document.body)\n      if (Element.getStyle(element, 'position') != 'static')\n        return $(element);\n\n    return $(document.body);\n  },\n\n  viewportOffset: function(forElement) {\n    var valueT = 0, valueL = 0;\n\n    var element = forElement;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n\n      // Safari fix\n      if (element.offsetParent == document.body &&\n        Element.getStyle(element, 'position') == 'absolute') break;\n\n    } while (element = element.offsetParent);\n\n    element = forElement;\n    do {\n      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {\n        valueT -= element.scrollTop  || 0;\n        valueL -= element.scrollLeft || 0;\n      }\n    } while (element = element.parentNode);\n\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  clonePosition: function(element, source) {\n    var options = Object.extend({\n      setLeft:    true,\n      setTop:     true,\n      setWidth:   true,\n      setHeight:  true,\n      offsetTop:  0,\n      offsetLeft: 0\n    }, arguments[2] || { });\n\n    // find page position of source\n    source = $(source);\n    var p = source.viewportOffset();\n\n    // find coordinate system to use\n    element = $(element);\n    var delta = [0, 0];\n    var parent = null;\n    // delta [0,0] will do fine with position: fixed elements,\n    // position:absolute needs offsetParent deltas\n    if (Element.getStyle(element, 'position') == 'absolute') {\n      parent = element.getOffsetParent();\n      delta = parent.viewportOffset();\n    }\n\n    // correct by body offsets (fixes Safari)\n    if (parent == document.body) {\n      delta[0] -= document.body.offsetLeft;\n      delta[1] -= document.body.offsetTop;\n    }\n\n    // set position\n    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\n    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\n    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';\n    if (options.setHeight) element.style.height = source.offsetHeight + 'px';\n    return element;\n  }\n};\n\nElement.Methods.identify.counter = 1;\n\nObject.extend(Element.Methods, {\n  getElementsBySelector: Element.Methods.select,\n  childElements: Element.Methods.immediateDescendants\n});\n\nElement._attributeTranslations = {\n  write: {\n    names: {\n      className: 'class',\n      htmlFor:   'for'\n    },\n    values: { }\n  }\n};\n\nif (Prototype.Browser.Opera) {\n  Element.Methods.getStyle = Element.Methods.getStyle.wrap(\n    function(proceed, element, style) {\n      switch (style) {\n        case 'left': case 'top': case 'right': case 'bottom':\n          if (proceed(element, 'position') === 'static') return null;\n        case 'height': case 'width':\n          // returns '0px' for hidden elements; we want it to return null\n          if (!Element.visible(element)) return null;\n\n          // returns the border-box dimensions rather than the content-box\n          // dimensions, so we subtract padding and borders from the value\n          var dim = parseInt(proceed(element, style), 10);\n\n          if (dim !== element['offset' + style.capitalize()])\n            return dim + 'px';\n\n          var properties;\n          if (style === 'height') {\n            properties = ['border-top-width', 'padding-top',\n             'padding-bottom', 'border-bottom-width'];\n          }\n          else {\n            properties = ['border-left-width', 'padding-left',\n             'padding-right', 'border-right-width'];\n          }\n          return properties.inject(dim, function(memo, property) {\n            var val = proceed(element, property);\n            return val === null ? memo : memo - parseInt(val, 10);\n          }) + 'px';\n        default: return proceed(element, style);\n      }\n    }\n  );\n\n  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(\n    function(proceed, element, attribute) {\n      if (attribute === 'title') return element.title;\n      return proceed(element, attribute);\n    }\n  );\n}\n\nelse if (Prototype.Browser.IE) {\n  // IE doesn't report offsets correctly for static elements, so we change them\n  // to \"relative\" to get the values, then change them back.\n  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(\n    function(proceed, element) {\n      element = $(element);\n      // IE throws an error if element is not in document\n      try { element.offsetParent }\n      catch(e) { return $(document.body) }\n      var position = element.getStyle('position');\n      if (position !== 'static') return proceed(element);\n      element.setStyle({ position: 'relative' });\n      var value = proceed(element);\n      element.setStyle({ position: position });\n      return value;\n    }\n  );\n\n  $w('positionedOffset viewportOffset').each(function(method) {\n    Element.Methods[method] = Element.Methods[method].wrap(\n      function(proceed, element) {\n        element = $(element);\n        try { element.offsetParent }\n        catch(e) { return Element._returnOffset(0,0) }\n        var position = element.getStyle('position');\n        if (position !== 'static') return proceed(element);\n        // Trigger hasLayout on the offset parent so that IE6 reports\n        // accurate offsetTop and offsetLeft values for position: fixed.\n        var offsetParent = element.getOffsetParent();\n        if (offsetParent && offsetParent.getStyle('position') === 'fixed')\n          offsetParent.setStyle({ zoom: 1 });\n        element.setStyle({ position: 'relative' });\n        var value = proceed(element);\n        element.setStyle({ position: position });\n        return value;\n      }\n    );\n  });\n\n  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(\n    function(proceed, element) {\n      try { element.offsetParent }\n      catch(e) { return Element._returnOffset(0,0) }\n      return proceed(element);\n    }\n  );\n\n  Element.Methods.getStyle = function(element, style) {\n    element = $(element);\n    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();\n    var value = element.style[style];\n    if (!value && element.currentStyle) value = element.currentStyle[style];\n\n    if (style == 'opacity') {\n      if (value = (element.getStyle('filter') || '').match(/alpha\\(opacity=(.*)\\)/))\n        if (value[1]) return parseFloat(value[1]) / 100;\n      return 1.0;\n    }\n\n    if (value == 'auto') {\n      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))\n        return element['offset' + style.capitalize()] + 'px';\n      return null;\n    }\n    return value;\n  };\n\n  Element.Methods.setOpacity = function(element, value) {\n    function stripAlpha(filter){\n      return filter.replace(/alpha\\([^\\)]*\\)/gi,'');\n    }\n    element = $(element);\n    var currentStyle = element.currentStyle;\n    if ((currentStyle && !currentStyle.hasLayout) ||\n      (!currentStyle && element.style.zoom == 'normal'))\n        element.style.zoom = 1;\n\n    var filter = element.getStyle('filter'), style = element.style;\n    if (value == 1 || value === '') {\n      (filter = stripAlpha(filter)) ?\n        style.filter = filter : style.removeAttribute('filter');\n      return element;\n    } else if (value < 0.00001) value = 0;\n    style.filter = stripAlpha(filter) +\n      'alpha(opacity=' + (value * 100) + ')';\n    return element;\n  };\n\n  Element._attributeTranslations = {\n    read: {\n      names: {\n        'class': 'className',\n        'for':   'htmlFor'\n      },\n      values: {\n        _getAttr: function(element, attribute) {\n          return element.getAttribute(attribute, 2);\n        },\n        _getAttrNode: function(element, attribute) {\n          var node = element.getAttributeNode(attribute);\n          return node ? node.value : \"\";\n        },\n        _getEv: function(element, attribute) {\n          attribute = element.getAttribute(attribute);\n          return attribute ? attribute.toString().slice(23, -2) : null;\n        },\n        _flag: function(element, attribute) {\n          return $(element).hasAttribute(attribute) ? attribute : null;\n        },\n        style: function(element) {\n          return element.style.cssText.toLowerCase();\n        },\n        title: function(element) {\n          return element.title;\n        }\n      }\n    }\n  };\n\n  Element._attributeTranslations.write = {\n    names: Object.extend({\n      cellpadding: 'cellPadding',\n      cellspacing: 'cellSpacing'\n    }, Element._attributeTranslations.read.names),\n    values: {\n      checked: function(element, value) {\n        element.checked = !!value;\n      },\n\n      style: function(element, value) {\n        element.style.cssText = value ? value : '';\n      }\n    }\n  };\n\n  Element._attributeTranslations.has = {};\n\n  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +\n      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {\n    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;\n    Element._attributeTranslations.has[attr.toLowerCase()] = attr;\n  });\n\n  (function(v) {\n    Object.extend(v, {\n      href:        v._getAttr,\n      src:         v._getAttr,\n      type:        v._getAttr,\n      action:      v._getAttrNode,\n      disabled:    v._flag,\n      checked:     v._flag,\n      readonly:    v._flag,\n      multiple:    v._flag,\n      onload:      v._getEv,\n      onunload:    v._getEv,\n      onclick:     v._getEv,\n      ondblclick:  v._getEv,\n      onmousedown: v._getEv,\n      onmouseup:   v._getEv,\n      onmouseover: v._getEv,\n      onmousemove: v._getEv,\n      onmouseout:  v._getEv,\n      onfocus:     v._getEv,\n      onblur:      v._getEv,\n      onkeypress:  v._getEv,\n      onkeydown:   v._getEv,\n      onkeyup:     v._getEv,\n      onsubmit:    v._getEv,\n      onreset:     v._getEv,\n      onselect:    v._getEv,\n      onchange:    v._getEv\n    });\n  })(Element._attributeTranslations.read.values);\n}\n\nelse if (Prototype.Browser.Gecko && /rv:1\\.8\\.0/.test(navigator.userAgent)) {\n  Element.Methods.setOpacity = function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1) ? 0.999999 :\n      (value === '') ? '' : (value < 0.00001) ? 0 : value;\n    return element;\n  };\n}\n\nelse if (Prototype.Browser.WebKit) {\n  Element.Methods.setOpacity = function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1 || value === '') ? '' :\n      (value < 0.00001) ? 0 : value;\n\n    if (value == 1)\n      if(element.tagName.toUpperCase() == 'IMG' && element.width) {\n        element.width++; element.width--;\n      } else try {\n        var n = document.createTextNode(' ');\n        element.appendChild(n);\n        element.removeChild(n);\n      } catch (e) { }\n\n    return element;\n  };\n\n  // Safari returns margins on body which is incorrect if the child is absolutely\n  // positioned.  For performance reasons, redefine Element#cumulativeOffset for\n  // KHTML/WebKit only.\n  Element.Methods.cumulativeOffset = function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      if (element.offsetParent == document.body)\n        if (Element.getStyle(element, 'position') == 'absolute') break;\n\n      element = element.offsetParent;\n    } while (element);\n\n    return Element._returnOffset(valueL, valueT);\n  };\n}\n\nif (Prototype.Browser.IE || Prototype.Browser.Opera) {\n  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements\n  Element.Methods.update = function(element, content) {\n    element = $(element);\n\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) return element.update().insert(content);\n\n    content = Object.toHTML(content);\n    var tagName = element.tagName.toUpperCase();\n\n    if (tagName in Element._insertionTranslations.tags) {\n      $A(element.childNodes).each(function(node) { element.removeChild(node) });\n      Element._getContentFromAnonymousElement(tagName, content.stripScripts())\n        .each(function(node) { element.appendChild(node) });\n    }\n    else element.innerHTML = content.stripScripts();\n\n    content.evalScripts.bind(content).defer();\n    return element;\n  };\n}\n\nif ('outerHTML' in document.createElement('div')) {\n  Element.Methods.replace = function(element, content) {\n    element = $(element);\n\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) {\n      element.parentNode.replaceChild(content, element);\n      return element;\n    }\n\n    content = Object.toHTML(content);\n    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();\n\n    if (Element._insertionTranslations.tags[tagName]) {\n      var nextSibling = element.next();\n      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\n      parent.removeChild(element);\n      if (nextSibling)\n        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });\n      else\n        fragments.each(function(node) { parent.appendChild(node) });\n    }\n    else element.outerHTML = content.stripScripts();\n\n    content.evalScripts.bind(content).defer();\n    return element;\n  };\n}\n\nElement._returnOffset = function(l, t) {\n  var result = [l, t];\n  result.left = l;\n  result.top = t;\n  return result;\n};\n\nElement._getContentFromAnonymousElement = function(tagName, html) {\n  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];\n  if (t) {\n    div.innerHTML = t[0] + html + t[1];\n    t[2].times(function() { div = div.firstChild });\n  } else div.innerHTML = html;\n  return $A(div.childNodes);\n};\n\nElement._insertionTranslations = {\n  before: function(element, node) {\n    element.parentNode.insertBefore(node, element);\n  },\n  top: function(element, node) {\n    element.insertBefore(node, element.firstChild);\n  },\n  bottom: function(element, node) {\n    element.appendChild(node);\n  },\n  after: function(element, node) {\n    element.parentNode.insertBefore(node, element.nextSibling);\n  },\n  tags: {\n    TABLE:  ['<table>',                '</table>',                   1],\n    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],\n    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],\n    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],\n    SELECT: ['<select>',               '</select>',                  1]\n  }\n};\n\n(function() {\n  Object.extend(this.tags, {\n    THEAD: this.tags.TBODY,\n    TFOOT: this.tags.TBODY,\n    TH:    this.tags.TD\n  });\n}).call(Element._insertionTranslations);\n\nElement.Methods.Simulated = {\n  hasAttribute: function(element, attribute) {\n    attribute = Element._attributeTranslations.has[attribute] || attribute;\n    var node = $(element).getAttributeNode(attribute);\n    return !!(node && node.specified);\n  }\n};\n\nElement.Methods.ByTag = { };\n\nObject.extend(Element, Element.Methods);\n\nif (!Prototype.BrowserFeatures.ElementExtensions &&\n    document.createElement('div')['__proto__']) {\n  window.HTMLElement = { };\n  window.HTMLElement.prototype = document.createElement('div')['__proto__'];\n  Prototype.BrowserFeatures.ElementExtensions = true;\n}\n\nElement.extend = (function() {\n  if (Prototype.BrowserFeatures.SpecificElementExtensions)\n    return Prototype.K;\n\n  var Methods = { }, ByTag = Element.Methods.ByTag;\n\n  var extend = Object.extend(function(element) {\n    if (!element || element._extendedByPrototype ||\n        element.nodeType != 1 || element == window) return element;\n\n    var methods = Object.clone(Methods),\n      tagName = element.tagName.toUpperCase(), property, value;\n\n    // extend methods for specific tags\n    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);\n\n    for (property in methods) {\n      value = methods[property];\n      if (Object.isFunction(value) && !(property in element))\n        element[property] = value.methodize();\n    }\n\n    element._extendedByPrototype = Prototype.emptyFunction;\n    return element;\n\n  }, {\n    refresh: function() {\n      // extend methods for all tags (Safari doesn't need this)\n      if (!Prototype.BrowserFeatures.ElementExtensions) {\n        Object.extend(Methods, Element.Methods);\n        Object.extend(Methods, Element.Methods.Simulated);\n      }\n    }\n  });\n\n  extend.refresh();\n  return extend;\n})();\n\nElement.hasAttribute = function(element, attribute) {\n  if (element.hasAttribute) return element.hasAttribute(attribute);\n  return Element.Methods.Simulated.hasAttribute(element, attribute);\n};\n\nElement.addMethods = function(methods) {\n  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;\n\n  if (!methods) {\n    Object.extend(Form, Form.Methods);\n    Object.extend(Form.Element, Form.Element.Methods);\n    Object.extend(Element.Methods.ByTag, {\n      \"FORM\":     Object.clone(Form.Methods),\n      \"INPUT\":    Object.clone(Form.Element.Methods),\n      \"SELECT\":   Object.clone(Form.Element.Methods),\n      \"TEXTAREA\": Object.clone(Form.Element.Methods)\n    });\n  }\n\n  if (arguments.length == 2) {\n    var tagName = methods;\n    methods = arguments[1];\n  }\n\n  if (!tagName) Object.extend(Element.Methods, methods || { });\n  else {\n    if (Object.isArray(tagName)) tagName.each(extend);\n    else extend(tagName);\n  }\n\n  function extend(tagName) {\n    tagName = tagName.toUpperCase();\n    if (!Element.Methods.ByTag[tagName])\n      Element.Methods.ByTag[tagName] = { };\n    Object.extend(Element.Methods.ByTag[tagName], methods);\n  }\n\n  function copy(methods, destination, onlyIfAbsent) {\n    onlyIfAbsent = onlyIfAbsent || false;\n    for (var property in methods) {\n      var value = methods[property];\n      if (!Object.isFunction(value)) continue;\n      if (!onlyIfAbsent || !(property in destination))\n        destination[property] = value.methodize();\n    }\n  }\n\n  function findDOMClass(tagName) {\n    var klass;\n    var trans = {\n      \"OPTGROUP\": \"OptGroup\", \"TEXTAREA\": \"TextArea\", \"P\": \"Paragraph\",\n      \"FIELDSET\": \"FieldSet\", \"UL\": \"UList\", \"OL\": \"OList\", \"DL\": \"DList\",\n      \"DIR\": \"Directory\", \"H1\": \"Heading\", \"H2\": \"Heading\", \"H3\": \"Heading\",\n      \"H4\": \"Heading\", \"H5\": \"Heading\", \"H6\": \"Heading\", \"Q\": \"Quote\",\n      \"INS\": \"Mod\", \"DEL\": \"Mod\", \"A\": \"Anchor\", \"IMG\": \"Image\", \"CAPTION\":\n      \"TableCaption\", \"COL\": \"TableCol\", \"COLGROUP\": \"TableCol\", \"THEAD\":\n      \"TableSection\", \"TFOOT\": \"TableSection\", \"TBODY\": \"TableSection\", \"TR\":\n      \"TableRow\", \"TH\": \"TableCell\", \"TD\": \"TableCell\", \"FRAMESET\":\n      \"FrameSet\", \"IFRAME\": \"IFrame\"\n    };\n    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';\n    if (window[klass]) return window[klass];\n    klass = 'HTML' + tagName + 'Element';\n    if (window[klass]) return window[klass];\n    klass = 'HTML' + tagName.capitalize() + 'Element';\n    if (window[klass]) return window[klass];\n\n    window[klass] = { };\n    window[klass].prototype = document.createElement(tagName)['__proto__'];\n    return window[klass];\n  }\n\n  if (F.ElementExtensions) {\n    copy(Element.Methods, HTMLElement.prototype);\n    copy(Element.Methods.Simulated, HTMLElement.prototype, true);\n  }\n\n  if (F.SpecificElementExtensions) {\n    for (var tag in Element.Methods.ByTag) {\n      var klass = findDOMClass(tag);\n      if (Object.isUndefined(klass)) continue;\n      copy(T[tag], klass.prototype);\n    }\n  }\n\n  Object.extend(Element, Element.Methods);\n  delete Element.ByTag;\n\n  if (Element.extend.refresh) Element.extend.refresh();\n  Element.cache = { };\n};\n\ndocument.viewport = {\n  getDimensions: function() {\n    var dimensions = { }, B = Prototype.Browser;\n    $w('width height').each(function(d) {\n      var D = d.capitalize();\n      if (B.WebKit && !document.evaluate) {\n        // Safari <3.0 needs self.innerWidth/Height\n        dimensions[d] = self['inner' + D];\n      } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {\n        // Opera <9.5 needs document.body.clientWidth/Height\n        dimensions[d] = document.body['client' + D]\n      } else {\n        dimensions[d] = document.documentElement['client' + D];\n      }\n    });\n    return dimensions;\n  },\n\n  getWidth: function() {\n    return this.getDimensions().width;\n  },\n\n  getHeight: function() {\n    return this.getDimensions().height;\n  },\n\n  getScrollOffsets: function() {\n    return Element._returnOffset(\n      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,\n      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);\n  }\n};\n/* Portions of the Selector class are derived from Jack Slocum's DomQuery,\n * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style\n * license.  Please see http://www.yui-ext.com/ for more information. */\n\nvar Selector = Class.create({\n  initialize: function(expression) {\n    this.expression = expression.strip();\n\n    if (this.shouldUseSelectorsAPI()) {\n      this.mode = 'selectorsAPI';\n    } else if (this.shouldUseXPath()) {\n      this.mode = 'xpath';\n      this.compileXPathMatcher();\n    } else {\n      this.mode = \"normal\";\n      this.compileMatcher();\n    }\n\n  },\n\n  shouldUseXPath: function() {\n    if (!Prototype.BrowserFeatures.XPath) return false;\n\n    var e = this.expression;\n\n    // Safari 3 chokes on :*-of-type and :empty\n    if (Prototype.Browser.WebKit &&\n     (e.include(\"-of-type\") || e.include(\":empty\")))\n      return false;\n\n    // XPath can't do namespaced attributes, nor can it read\n    // the \"checked\" property from DOM nodes\n    if ((/(\\[[\\w-]*?:|:checked)/).test(e))\n      return false;\n\n    return true;\n  },\n\n  shouldUseSelectorsAPI: function() {\n    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;\n\n    if (!Selector._div) Selector._div = new Element('div');\n\n    // Make sure the browser treats the selector as valid. Test on an\n    // isolated element to minimize cost of this check.\n    try {\n      Selector._div.querySelector(this.expression);\n    } catch(e) {\n      return false;\n    }\n\n    return true;\n  },\n\n  compileMatcher: function() {\n    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,\n        c = Selector.criteria, le, p, m;\n\n    if (Selector._cache[e]) {\n      this.matcher = Selector._cache[e];\n      return;\n    }\n\n    this.matcher = [\"this.matcher = function(root) {\",\n                    \"var r = root, h = Selector.handlers, c = false, n;\"];\n\n    while (e && le != e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        p = ps[i];\n        if (m = e.match(p)) {\n          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :\n            new Template(c[i]).evaluate(m));\n          e = e.replace(m[0], '');\n          break;\n        }\n      }\n    }\n\n    this.matcher.push(\"return h.unique(n);\\n}\");\n    eval(this.matcher.join('\\n'));\n    Selector._cache[this.expression] = this.matcher;\n  },\n\n  compileXPathMatcher: function() {\n    var e = this.expression, ps = Selector.patterns,\n        x = Selector.xpath, le, m;\n\n    if (Selector._cache[e]) {\n      this.xpath = Selector._cache[e]; return;\n    }\n\n    this.matcher = ['.//*'];\n    while (e && le != e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        if (m = e.match(ps[i])) {\n          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :\n            new Template(x[i]).evaluate(m));\n          e = e.replace(m[0], '');\n          break;\n        }\n      }\n    }\n\n    this.xpath = this.matcher.join('');\n    Selector._cache[this.expression] = this.xpath;\n  },\n\n  findElements: function(root) {\n    root = root || document;\n    var e = this.expression, results;\n\n    switch (this.mode) {\n      case 'selectorsAPI':\n        // querySelectorAll queries document-wide, then filters to descendants\n        // of the context element. That's not what we want.\n        // Add an explicit context to the selector if necessary.\n        if (root !== document) {\n          var oldId = root.id, id = $(root).identify();\n          e = \"#\" + id + \" \" + e;\n        }\n\n        results = $A(root.querySelectorAll(e)).map(Element.extend);\n        root.id = oldId;\n\n        return results;\n      case 'xpath':\n        return document._getElementsByXPath(this.xpath, root);\n      default:\n       return this.matcher(root);\n    }\n  },\n\n  match: function(element) {\n    this.tokens = [];\n\n    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;\n    var le, p, m;\n\n    while (e && le !== e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        p = ps[i];\n        if (m = e.match(p)) {\n          // use the Selector.assertions methods unless the selector\n          // is too complex.\n          if (as[i]) {\n            this.tokens.push([i, Object.clone(m)]);\n            e = e.replace(m[0], '');\n          } else {\n            // reluctantly do a document-wide search\n            // and look for a match in the array\n            return this.findElements(document).include(element);\n          }\n        }\n      }\n    }\n\n    var match = true, name, matches;\n    for (var i = 0, token; token = this.tokens[i]; i++) {\n      name = token[0], matches = token[1];\n      if (!Selector.assertions[name](element, matches)) {\n        match = false; break;\n      }\n    }\n\n    return match;\n  },\n\n  toString: function() {\n    return this.expression;\n  },\n\n  inspect: function() {\n    return \"#<Selector:\" + this.expression.inspect() + \">\";\n  }\n});\n\nObject.extend(Selector, {\n  _cache: { },\n\n  xpath: {\n    descendant:   \"//*\",\n    child:        \"/*\",\n    adjacent:     \"/following-sibling::*[1]\",\n    laterSibling: '/following-sibling::*',\n    tagName:      function(m) {\n      if (m[1] == '*') return '';\n      return \"[local-name()='\" + m[1].toLowerCase() +\n             \"' or local-name()='\" + m[1].toUpperCase() + \"']\";\n    },\n    className:    \"[contains(concat(' ', @class, ' '), ' #{1} ')]\",\n    id:           \"[@id='#{1}']\",\n    attrPresence: function(m) {\n      m[1] = m[1].toLowerCase();\n      return new Template(\"[@#{1}]\").evaluate(m);\n    },\n    attr: function(m) {\n      m[1] = m[1].toLowerCase();\n      m[3] = m[5] || m[6];\n      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);\n    },\n    pseudo: function(m) {\n      var h = Selector.xpath.pseudos[m[1]];\n      if (!h) return '';\n      if (Object.isFunction(h)) return h(m);\n      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);\n    },\n    operators: {\n      '=':  \"[@#{1}='#{3}']\",\n      '!=': \"[@#{1}!='#{3}']\",\n      '^=': \"[starts-with(@#{1}, '#{3}')]\",\n      '$=': \"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']\",\n      '*=': \"[contains(@#{1}, '#{3}')]\",\n      '~=': \"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]\",\n      '|=': \"[contains(concat('-', @#{1}, '-'), '-#{3}-')]\"\n    },\n    pseudos: {\n      'first-child': '[not(preceding-sibling::*)]',\n      'last-child':  '[not(following-sibling::*)]',\n      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',\n      'empty':       \"[count(*) = 0 and (count(text()) = 0)]\",\n      'checked':     \"[@checked]\",\n      'disabled':    \"[(@disabled) and (@type!='hidden')]\",\n      'enabled':     \"[not(@disabled) and (@type!='hidden')]\",\n      'not': function(m) {\n        var e = m[6], p = Selector.patterns,\n            x = Selector.xpath, le, v;\n\n        var exclusion = [];\n        while (e && le != e && (/\\S/).test(e)) {\n          le = e;\n          for (var i in p) {\n            if (m = e.match(p[i])) {\n              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);\n              exclusion.push(\"(\" + v.substring(1, v.length - 1) + \")\");\n              e = e.replace(m[0], '');\n              break;\n            }\n          }\n        }\n        return \"[not(\" + exclusion.join(\" and \") + \")]\";\n      },\n      'nth-child':      function(m) {\n        return Selector.xpath.pseudos.nth(\"(count(./preceding-sibling::*) + 1) \", m);\n      },\n      'nth-last-child': function(m) {\n        return Selector.xpath.pseudos.nth(\"(count(./following-sibling::*) + 1) \", m);\n      },\n      'nth-of-type':    function(m) {\n        return Selector.xpath.pseudos.nth(\"position() \", m);\n      },\n      'nth-last-of-type': function(m) {\n        return Selector.xpath.pseudos.nth(\"(last() + 1 - position()) \", m);\n      },\n      'first-of-type':  function(m) {\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-of-type'](m);\n      },\n      'last-of-type':   function(m) {\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-last-of-type'](m);\n      },\n      'only-of-type':   function(m) {\n        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);\n      },\n      nth: function(fragment, m) {\n        var mm, formula = m[6], predicate;\n        if (formula == 'even') formula = '2n+0';\n        if (formula == 'odd')  formula = '2n+1';\n        if (mm = formula.match(/^(\\d+)$/)) // digit only\n          return '[' + fragment + \"= \" + mm[1] + ']';\n        if (mm = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\n          if (mm[1] == \"-\") mm[1] = -1;\n          var a = mm[1] ? Number(mm[1]) : 1;\n          var b = mm[2] ? Number(mm[2]) : 0;\n          predicate = \"[((#{fragment} - #{b}) mod #{a} = 0) and \" +\n          \"((#{fragment} - #{b}) div #{a} >= 0)]\";\n          return new Template(predicate).evaluate({\n            fragment: fragment, a: a, b: b });\n        }\n      }\n    }\n  },\n\n  criteria: {\n    tagName:      'n = h.tagName(n, r, \"#{1}\", c);      c = false;',\n    className:    'n = h.className(n, r, \"#{1}\", c);    c = false;',\n    id:           'n = h.id(n, r, \"#{1}\", c);           c = false;',\n    attrPresence: 'n = h.attrPresence(n, r, \"#{1}\", c); c = false;',\n    attr: function(m) {\n      m[3] = (m[5] || m[6]);\n      return new Template('n = h.attr(n, r, \"#{1}\", \"#{3}\", \"#{2}\", c); c = false;').evaluate(m);\n    },\n    pseudo: function(m) {\n      if (m[6]) m[6] = m[6].replace(/\"/g, '\\\\\"');\n      return new Template('n = h.pseudo(n, \"#{1}\", \"#{6}\", r, c); c = false;').evaluate(m);\n    },\n    descendant:   'c = \"descendant\";',\n    child:        'c = \"child\";',\n    adjacent:     'c = \"adjacent\";',\n    laterSibling: 'c = \"laterSibling\";'\n  },\n\n  patterns: {\n    // combinators must be listed first\n    // (and descendant needs to be last combinator)\n    laterSibling: /^\\s*~\\s*/,\n    child:        /^\\s*>\\s*/,\n    adjacent:     /^\\s*\\+\\s*/,\n    descendant:   /^\\s/,\n\n    // selectors follow\n    tagName:      /^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,\n    id:           /^#([\\w\\-\\*]+)(\\b|$)/,\n    className:    /^\\.([\\w\\-\\*]+)(\\b|$)/,\n    pseudo:\n/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,\n    attrPresence: /^\\[((?:[\\w]+:)?[\\w]+)\\]/,\n    attr:         /\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*((['\"])([^\\4]*?)\\4|([^'\"][^\\]]*?)))?\\]/\n  },\n\n  // for Selector.match and Element#match\n  assertions: {\n    tagName: function(element, matches) {\n      return matches[1].toUpperCase() == element.tagName.toUpperCase();\n    },\n\n    className: function(element, matches) {\n      return Element.hasClassName(element, matches[1]);\n    },\n\n    id: function(element, matches) {\n      return element.id === matches[1];\n    },\n\n    attrPresence: function(element, matches) {\n      return Element.hasAttribute(element, matches[1]);\n    },\n\n    attr: function(element, matches) {\n      var nodeValue = Element.readAttribute(element, matches[1]);\n      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);\n    }\n  },\n\n  handlers: {\n    // UTILITY FUNCTIONS\n    // joins two collections\n    concat: function(a, b) {\n      for (var i = 0, node; node = b[i]; i++)\n        a.push(node);\n      return a;\n    },\n\n    // marks an array of nodes for counting\n    mark: function(nodes) {\n      var _true = Prototype.emptyFunction;\n      for (var i = 0, node; node = nodes[i]; i++)\n        node._countedByPrototype = _true;\n      return nodes;\n    },\n\n    unmark: function(nodes) {\n      for (var i = 0, node; node = nodes[i]; i++)\n        node._countedByPrototype = undefined;\n      return nodes;\n    },\n\n    // mark each child node with its position (for nth calls)\n    // \"ofType\" flag indicates whether we're indexing for nth-of-type\n    // rather than nth-child\n    index: function(parentNode, reverse, ofType) {\n      parentNode._countedByPrototype = Prototype.emptyFunction;\n      if (reverse) {\n        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {\n          var node = nodes[i];\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\n        }\n      } else {\n        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\n      }\n    },\n\n    // filters out duplicates and extends all nodes\n    unique: function(nodes) {\n      if (nodes.length == 0) return nodes;\n      var results = [], n;\n      for (var i = 0, l = nodes.length; i < l; i++)\n        if (!(n = nodes[i])._countedByPrototype) {\n          n._countedByPrototype = Prototype.emptyFunction;\n          results.push(Element.extend(n));\n        }\n      return Selector.handlers.unmark(results);\n    },\n\n    // COMBINATOR FUNCTIONS\n    descendant: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        h.concat(results, node.getElementsByTagName('*'));\n      return results;\n    },\n\n    child: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        for (var j = 0, child; child = node.childNodes[j]; j++)\n          if (child.nodeType == 1 && child.tagName != '!') results.push(child);\n      }\n      return results;\n    },\n\n    adjacent: function(nodes) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        var next = this.nextElementSibling(node);\n        if (next) results.push(next);\n      }\n      return results;\n    },\n\n    laterSibling: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        h.concat(results, Element.nextSiblings(node));\n      return results;\n    },\n\n    nextElementSibling: function(node) {\n      while (node = node.nextSibling)\n        if (node.nodeType == 1) return node;\n      return null;\n    },\n\n    previousElementSibling: function(node) {\n      while (node = node.previousSibling)\n        if (node.nodeType == 1) return node;\n      return null;\n    },\n\n    // TOKEN FUNCTIONS\n    tagName: function(nodes, root, tagName, combinator) {\n      var uTagName = tagName.toUpperCase();\n      var results = [], h = Selector.handlers;\n      if (nodes) {\n        if (combinator) {\n          // fastlane for ordinary descendant combinators\n          if (combinator == \"descendant\") {\n            for (var i = 0, node; node = nodes[i]; i++)\n              h.concat(results, node.getElementsByTagName(tagName));\n            return results;\n          } else nodes = this[combinator](nodes);\n          if (tagName == \"*\") return nodes;\n        }\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node.tagName.toUpperCase() === uTagName) results.push(node);\n        return results;\n      } else return root.getElementsByTagName(tagName);\n    },\n\n    id: function(nodes, root, id, combinator) {\n      var targetNode = $(id), h = Selector.handlers;\n      if (!targetNode) return [];\n      if (!nodes && root == document) return [targetNode];\n      if (nodes) {\n        if (combinator) {\n          if (combinator == 'child') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (targetNode.parentNode == node) return [targetNode];\n          } else if (combinator == 'descendant') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (Element.descendantOf(targetNode, node)) return [targetNode];\n          } else if (combinator == 'adjacent') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (Selector.handlers.previousElementSibling(targetNode) == node)\n                return [targetNode];\n          } else nodes = h[combinator](nodes);\n        }\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node == targetNode) return [targetNode];\n        return [];\n      }\n      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];\n    },\n\n    className: function(nodes, root, className, combinator) {\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      return Selector.handlers.byClassName(nodes, root, className);\n    },\n\n    byClassName: function(nodes, root, className) {\n      if (!nodes) nodes = Selector.handlers.descendant([root]);\n      var needle = ' ' + className + ' ';\n      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {\n        nodeClassName = node.className;\n        if (nodeClassName.length == 0) continue;\n        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))\n          results.push(node);\n      }\n      return results;\n    },\n\n    attrPresence: function(nodes, root, attr, combinator) {\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      var results = [];\n      for (var i = 0, node; node = nodes[i]; i++)\n        if (Element.hasAttribute(node, attr)) results.push(node);\n      return results;\n    },\n\n    attr: function(nodes, root, attr, value, operator, combinator) {\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      var handler = Selector.operators[operator], results = [];\n      for (var i = 0, node; node = nodes[i]; i++) {\n        var nodeValue = Element.readAttribute(node, attr);\n        if (nodeValue === null) continue;\n        if (handler(nodeValue, value)) results.push(node);\n      }\n      return results;\n    },\n\n    pseudo: function(nodes, name, value, root, combinator) {\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      return Selector.pseudos[name](nodes, value, root);\n    }\n  },\n\n  pseudos: {\n    'first-child': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        if (Selector.handlers.previousElementSibling(node)) continue;\n          results.push(node);\n      }\n      return results;\n    },\n    'last-child': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        if (Selector.handlers.nextElementSibling(node)) continue;\n          results.push(node);\n      }\n      return results;\n    },\n    'only-child': function(nodes, value, root) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))\n          results.push(node);\n      return results;\n    },\n    'nth-child':        function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root);\n    },\n    'nth-last-child':   function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, true);\n    },\n    'nth-of-type':      function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, false, true);\n    },\n    'nth-last-of-type': function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, true, true);\n    },\n    'first-of-type':    function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, \"1\", root, false, true);\n    },\n    'last-of-type':     function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, \"1\", root, true, true);\n    },\n    'only-of-type':     function(nodes, formula, root) {\n      var p = Selector.pseudos;\n      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);\n    },\n\n    // handles the an+b logic\n    getIndices: function(a, b, total) {\n      if (a == 0) return b > 0 ? [b] : [];\n      return $R(1, total).inject([], function(memo, i) {\n        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);\n        return memo;\n      });\n    },\n\n    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type\n    nth: function(nodes, formula, root, reverse, ofType) {\n      if (nodes.length == 0) return [];\n      if (formula == 'even') formula = '2n+0';\n      if (formula == 'odd')  formula = '2n+1';\n      var h = Selector.handlers, results = [], indexed = [], m;\n      h.mark(nodes);\n      for (var i = 0, node; node = nodes[i]; i++) {\n        if (!node.parentNode._countedByPrototype) {\n          h.index(node.parentNode, reverse, ofType);\n          indexed.push(node.parentNode);\n        }\n      }\n      if (formula.match(/^\\d+$/)) { // just a number\n        formula = Number(formula);\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node.nodeIndex == formula) results.push(node);\n      } else if (m = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\n        if (m[1] == \"-\") m[1] = -1;\n        var a = m[1] ? Number(m[1]) : 1;\n        var b = m[2] ? Number(m[2]) : 0;\n        var indices = Selector.pseudos.getIndices(a, b, nodes.length);\n        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {\n          for (var j = 0; j < l; j++)\n            if (node.nodeIndex == indices[j]) results.push(node);\n        }\n      }\n      h.unmark(nodes);\n      h.unmark(indexed);\n      return results;\n    },\n\n    'empty': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        // IE treats comments as element nodes\n        if (node.tagName == '!' || node.firstChild) continue;\n        results.push(node);\n      }\n      return results;\n    },\n\n    'not': function(nodes, selector, root) {\n      var h = Selector.handlers, selectorType, m;\n      var exclusions = new Selector(selector).findElements(root);\n      h.mark(exclusions);\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!node._countedByPrototype) results.push(node);\n      h.unmark(exclusions);\n      return results;\n    },\n\n    'enabled': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!node.disabled && (!node.type || node.type !== 'hidden'))\n          results.push(node);\n      return results;\n    },\n\n    'disabled': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (node.disabled) results.push(node);\n      return results;\n    },\n\n    'checked': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (node.checked) results.push(node);\n      return results;\n    }\n  },\n\n  operators: {\n    '=':  function(nv, v) { return nv == v; },\n    '!=': function(nv, v) { return nv != v; },\n    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },\n    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },\n    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },\n    '$=': function(nv, v) { return nv.endsWith(v); },\n    '*=': function(nv, v) { return nv.include(v); },\n    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },\n    '|=': function(nv, v) { return ('-' + (nv || \"\").toUpperCase() +\n     '-').include('-' + (v || \"\").toUpperCase() + '-'); }\n  },\n\n  split: function(expression) {\n    var expressions = [];\n    expression.scan(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/, function(m) {\n      expressions.push(m[1].strip());\n    });\n    return expressions;\n  },\n\n  matchElements: function(elements, expression) {\n    var matches = $$(expression), h = Selector.handlers;\n    h.mark(matches);\n    for (var i = 0, results = [], element; element = elements[i]; i++)\n      if (element._countedByPrototype) results.push(element);\n    h.unmark(matches);\n    return results;\n  },\n\n  findElement: function(elements, expression, index) {\n    if (Object.isNumber(expression)) {\n      index = expression; expression = false;\n    }\n    return Selector.matchElements(elements, expression || '*')[index || 0];\n  },\n\n  findChildElements: function(element, expressions) {\n    expressions = Selector.split(expressions.join(','));\n    var results = [], h = Selector.handlers;\n    for (var i = 0, l = expressions.length, selector; i < l; i++) {\n      selector = new Selector(expressions[i].strip());\n      h.concat(results, selector.findElements(element));\n    }\n    return (l > 1) ? h.unique(results) : results;\n  }\n});\n\nif (Prototype.Browser.IE) {\n  Object.extend(Selector.handlers, {\n    // IE returns comment nodes on getElementsByTagName(\"*\").\n    // Filter them out.\n    concat: function(a, b) {\n      for (var i = 0, node; node = b[i]; i++)\n        if (node.tagName !== \"!\") a.push(node);\n      return a;\n    },\n\n    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.\n    unmark: function(nodes) {\n      for (var i = 0, node; node = nodes[i]; i++)\n        node.removeAttribute('_countedByPrototype');\n      return nodes;\n    }\n  });\n}\n\nfunction $$() {\n  return Selector.findChildElements(document, $A(arguments));\n}\nvar Form = {\n  reset: function(form) {\n    $(form).reset();\n    return form;\n  },\n\n  serializeElements: function(elements, options) {\n    if (typeof options != 'object') options = { hash: !!options };\n    else if (Object.isUndefined(options.hash)) options.hash = true;\n    var key, value, submitted = false, submit = options.submit;\n\n    var data = elements.inject({ }, function(result, element) {\n      if (!element.disabled && element.name) {\n        key = element.name; value = $(element).getValue();\n        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&\n            submit !== false && (!submit || key == submit) && (submitted = true)))) {\n          if (key in result) {\n            // a key is already present; construct an array of values\n            if (!Object.isArray(result[key])) result[key] = [result[key]];\n            result[key].push(value);\n          }\n          else result[key] = value;\n        }\n      }\n      return result;\n    });\n\n    return options.hash ? data : Object.toQueryString(data);\n  }\n};\n\nForm.Methods = {\n  serialize: function(form, options) {\n    return Form.serializeElements(Form.getElements(form), options);\n  },\n\n  getElements: function(form) {\n    return $A($(form).getElementsByTagName('*')).inject([],\n      function(elements, child) {\n        if (Form.Element.Serializers[child.tagName.toLowerCase()])\n          elements.push(Element.extend(child));\n        return elements;\n      }\n    );\n  },\n\n  getInputs: function(form, typeName, name) {\n    form = $(form);\n    var inputs = form.getElementsByTagName('input');\n\n    if (!typeName && !name) return $A(inputs).map(Element.extend);\n\n    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {\n      var input = inputs[i];\n      if ((typeName && input.type != typeName) || (name && input.name != name))\n        continue;\n      matchingInputs.push(Element.extend(input));\n    }\n\n    return matchingInputs;\n  },\n\n  disable: function(form) {\n    form = $(form);\n    Form.getElements(form).invoke('disable');\n    return form;\n  },\n\n  enable: function(form) {\n    form = $(form);\n    Form.getElements(form).invoke('enable');\n    return form;\n  },\n\n  findFirstElement: function(form) {\n    var elements = $(form).getElements().findAll(function(element) {\n      return 'hidden' != element.type && !element.disabled;\n    });\n    var firstByIndex = elements.findAll(function(element) {\n      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;\n    }).sortBy(function(element) { return element.tabIndex }).first();\n\n    return firstByIndex ? firstByIndex : elements.find(function(element) {\n      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\n    });\n  },\n\n  focusFirstElement: function(form) {\n    form = $(form);\n    form.findFirstElement().activate();\n    return form;\n  },\n\n  request: function(form, options) {\n    form = $(form), options = Object.clone(options || { });\n\n    var params = options.parameters, action = form.readAttribute('action') || '';\n    if (action.blank()) action = window.location.href;\n    options.parameters = form.serialize(true);\n\n    if (params) {\n      if (Object.isString(params)) params = params.toQueryParams();\n      Object.extend(options.parameters, params);\n    }\n\n    if (form.hasAttribute('method') && !options.method)\n      options.method = form.method;\n\n    return new Ajax.Request(action, options);\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nForm.Element = {\n  focus: function(element) {\n    $(element).focus();\n    return element;\n  },\n\n  select: function(element) {\n    $(element).select();\n    return element;\n  }\n};\n\nForm.Element.Methods = {\n  serialize: function(element) {\n    element = $(element);\n    if (!element.disabled && element.name) {\n      var value = element.getValue();\n      if (value != undefined) {\n        var pair = { };\n        pair[element.name] = value;\n        return Object.toQueryString(pair);\n      }\n    }\n    return '';\n  },\n\n  getValue: function(element) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    return Form.Element.Serializers[method](element);\n  },\n\n  setValue: function(element, value) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    Form.Element.Serializers[method](element, value);\n    return element;\n  },\n\n  clear: function(element) {\n    $(element).value = '';\n    return element;\n  },\n\n  present: function(element) {\n    return $(element).value != '';\n  },\n\n  activate: function(element) {\n    element = $(element);\n    try {\n      element.focus();\n      if (element.select && (element.tagName.toLowerCase() != 'input' ||\n          !['button', 'reset', 'submit'].include(element.type)))\n        element.select();\n    } catch (e) { }\n    return element;\n  },\n\n  disable: function(element) {\n    element = $(element);\n    element.disabled = true;\n    return element;\n  },\n\n  enable: function(element) {\n    element = $(element);\n    element.disabled = false;\n    return element;\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar Field = Form.Element;\nvar $F = Form.Element.Methods.getValue;\n\n/*--------------------------------------------------------------------------*/\n\nForm.Element.Serializers = {\n  input: function(element, value) {\n    switch (element.type.toLowerCase()) {\n      case 'checkbox':\n      case 'radio':\n        return Form.Element.Serializers.inputSelector(element, value);\n      default:\n        return Form.Element.Serializers.textarea(element, value);\n    }\n  },\n\n  inputSelector: function(element, value) {\n    if (Object.isUndefined(value)) return element.checked ? element.value : null;\n    else element.checked = !!value;\n  },\n\n  textarea: function(element, value) {\n    if (Object.isUndefined(value)) return element.value;\n    else element.value = value;\n  },\n\n  select: function(element, value) {\n    if (Object.isUndefined(value))\n      return this[element.type == 'select-one' ?\n        'selectOne' : 'selectMany'](element);\n    else {\n      var opt, currentValue, single = !Object.isArray(value);\n      for (var i = 0, length = element.length; i < length; i++) {\n        opt = element.options[i];\n        currentValue = this.optionValue(opt);\n        if (single) {\n          if (currentValue == value) {\n            opt.selected = true;\n            return;\n          }\n        }\n        else opt.selected = value.include(currentValue);\n      }\n    }\n  },\n\n  selectOne: function(element) {\n    var index = element.selectedIndex;\n    return index >= 0 ? this.optionValue(element.options[index]) : null;\n  },\n\n  selectMany: function(element) {\n    var values, length = element.length;\n    if (!length) return null;\n\n    for (var i = 0, values = []; i < length; i++) {\n      var opt = element.options[i];\n      if (opt.selected) values.push(this.optionValue(opt));\n    }\n    return values;\n  },\n\n  optionValue: function(opt) {\n    // extend element because hasAttribute may not be native\n    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.TimedObserver = Class.create(PeriodicalExecuter, {\n  initialize: function($super, element, frequency, callback) {\n    $super(callback, frequency);\n    this.element   = $(element);\n    this.lastValue = this.getValue();\n  },\n\n  execute: function() {\n    var value = this.getValue();\n    if (Object.isString(this.lastValue) && Object.isString(value) ?\n        this.lastValue != value : String(this.lastValue) != String(value)) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  }\n});\n\nForm.Element.Observer = Class.create(Abstract.TimedObserver, {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.Observer = Class.create(Abstract.TimedObserver, {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.EventObserver = Class.create({\n  initialize: function(element, callback) {\n    this.element  = $(element);\n    this.callback = callback;\n\n    this.lastValue = this.getValue();\n    if (this.element.tagName.toLowerCase() == 'form')\n      this.registerFormCallbacks();\n    else\n      this.registerCallback(this.element);\n  },\n\n  onElementEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  },\n\n  registerFormCallbacks: function() {\n    Form.getElements(this.element).each(this.registerCallback, this);\n  },\n\n  registerCallback: function(element) {\n    if (element.type) {\n      switch (element.type.toLowerCase()) {\n        case 'checkbox':\n        case 'radio':\n          Event.observe(element, 'click', this.onElementEvent.bind(this));\n          break;\n        default:\n          Event.observe(element, 'change', this.onElementEvent.bind(this));\n          break;\n      }\n    }\n  }\n});\n\nForm.Element.EventObserver = Class.create(Abstract.EventObserver, {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.EventObserver = Class.create(Abstract.EventObserver, {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\nif (!window.Event) var Event = { };\n\nObject.extend(Event, {\n  KEY_BACKSPACE: 8,\n  KEY_TAB:       9,\n  KEY_RETURN:   13,\n  KEY_ESC:      27,\n  KEY_LEFT:     37,\n  KEY_UP:       38,\n  KEY_RIGHT:    39,\n  KEY_DOWN:     40,\n  KEY_DELETE:   46,\n  KEY_HOME:     36,\n  KEY_END:      35,\n  KEY_PAGEUP:   33,\n  KEY_PAGEDOWN: 34,\n  KEY_INSERT:   45,\n\n  cache: { },\n\n  relatedTarget: function(event) {\n    var element;\n    switch(event.type) {\n      case 'mouseover': element = event.fromElement; break;\n      case 'mouseout':  element = event.toElement;   break;\n      default: return null;\n    }\n    return Element.extend(element);\n  }\n});\n\nEvent.Methods = (function() {\n  var isButton;\n\n  if (Prototype.Browser.IE) {\n    var buttonMap = { 0: 1, 1: 4, 2: 2 };\n    isButton = function(event, code) {\n      return event.button == buttonMap[code];\n    };\n\n  } else if (Prototype.Browser.WebKit) {\n    isButton = function(event, code) {\n      switch (code) {\n        case 0: return event.which == 1 && !event.metaKey;\n        case 1: return event.which == 1 && event.metaKey;\n        default: return false;\n      }\n    };\n\n  } else {\n    isButton = function(event, code) {\n      return event.which ? (event.which === code + 1) : (event.button === code);\n    };\n  }\n\n  return {\n    isLeftClick:   function(event) { return isButton(event, 0) },\n    isMiddleClick: function(event) { return isButton(event, 1) },\n    isRightClick:  function(event) { return isButton(event, 2) },\n\n    element: function(event) {\n      event = Event.extend(event);\n\n      var node          = event.target,\n          type          = event.type,\n          currentTarget = event.currentTarget;\n\n      if (currentTarget && currentTarget.tagName) {\n        // Firefox screws up the \"click\" event when moving between radio buttons\n        // via arrow keys. It also screws up the \"load\" and \"error\" events on images,\n        // reporting the document as the target instead of the original image.\n        if (type === 'load' || type === 'error' ||\n          (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'\n            && currentTarget.type === 'radio'))\n              node = currentTarget;\n      }\n      if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;\n      return Element.extend(node);\n    },\n\n    findElement: function(event, expression) {\n      var element = Event.element(event);\n      if (!expression) return element;\n      var elements = [element].concat(element.ancestors());\n      return Selector.findElement(elements, expression, 0);\n    },\n\n    pointer: function(event) {\n      var docElement = document.documentElement,\n      body = document.body || { scrollLeft: 0, scrollTop: 0 };\n      return {\n        x: event.pageX || (event.clientX +\n          (docElement.scrollLeft || body.scrollLeft) -\n          (docElement.clientLeft || 0)),\n        y: event.pageY || (event.clientY +\n          (docElement.scrollTop || body.scrollTop) -\n          (docElement.clientTop || 0))\n      };\n    },\n\n    pointerX: function(event) { return Event.pointer(event).x },\n    pointerY: function(event) { return Event.pointer(event).y },\n\n    stop: function(event) {\n      Event.extend(event);\n      event.preventDefault();\n      event.stopPropagation();\n      event.stopped = true;\n    }\n  };\n})();\n\nEvent.extend = (function() {\n  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {\n    m[name] = Event.Methods[name].methodize();\n    return m;\n  });\n\n  if (Prototype.Browser.IE) {\n    Object.extend(methods, {\n      stopPropagation: function() { this.cancelBubble = true },\n      preventDefault:  function() { this.returnValue = false },\n      inspect: function() { return \"[object Event]\" }\n    });\n\n    return function(event) {\n      if (!event) return false;\n      if (event._extendedByPrototype) return event;\n\n      event._extendedByPrototype = Prototype.emptyFunction;\n      var pointer = Event.pointer(event);\n      Object.extend(event, {\n        target: event.srcElement,\n        relatedTarget: Event.relatedTarget(event),\n        pageX:  pointer.x,\n        pageY:  pointer.y\n      });\n      return Object.extend(event, methods);\n    };\n\n  } else {\n    Event.prototype = Event.prototype || document.createEvent(\"HTMLEvents\")['__proto__'];\n    Object.extend(Event.prototype, methods);\n    return Prototype.K;\n  }\n})();\n\nObject.extend(Event, (function() {\n  var cache = Event.cache;\n\n  function getEventID(element) {\n    if (element._prototypeEventID) return element._prototypeEventID[0];\n    arguments.callee.id = arguments.callee.id || 1;\n    return element._prototypeEventID = [++arguments.callee.id];\n  }\n\n  function getDOMEventName(eventName) {\n    if (eventName && eventName.include(':')) return \"dataavailable\";\n    return eventName;\n  }\n\n  function getCacheForID(id) {\n    return cache[id] = cache[id] || { };\n  }\n\n  function getWrappersForEventName(id, eventName) {\n    var c = getCacheForID(id);\n    return c[eventName] = c[eventName] || [];\n  }\n\n  function createWrapper(element, eventName, handler) {\n    var id = getEventID(element);\n    var c = getWrappersForEventName(id, eventName);\n    if (c.pluck(\"handler\").include(handler)) return false;\n\n    var wrapper = function(event) {\n      if (!Event || !Event.extend ||\n        (event.eventName && event.eventName != eventName))\n          return false;\n\n      Event.extend(event);\n      handler.call(element, event);\n    };\n\n    wrapper.handler = handler;\n    c.push(wrapper);\n    return wrapper;\n  }\n\n  function findWrapper(id, eventName, handler) {\n    var c = getWrappersForEventName(id, eventName);\n    return c.find(function(wrapper) { return wrapper.handler == handler });\n  }\n\n  function destroyWrapper(id, eventName, handler) {\n    var c = getCacheForID(id);\n    if (!c[eventName]) return false;\n    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));\n  }\n\n  function destroyCache() {\n    for (var id in cache)\n      for (var eventName in cache[id])\n        cache[id][eventName] = null;\n  }\n\n\n  // Internet Explorer needs to remove event handlers on page unload\n  // in order to avoid memory leaks.\n  if (window.attachEvent) {\n    window.attachEvent(\"onunload\", destroyCache);\n  }\n\n  // Safari has a dummy event handler on page unload so that it won't\n  // use its bfcache. Safari <= 3.1 has an issue with restoring the \"document\"\n  // object when page is returned to via the back button using its bfcache.\n  if (Prototype.Browser.WebKit) {\n    window.addEventListener('unload', Prototype.emptyFunction, false);\n  }\n\n  return {\n    observe: function(element, eventName, handler) {\n      element = $(element);\n      var name = getDOMEventName(eventName);\n\n      var wrapper = createWrapper(element, eventName, handler);\n      if (!wrapper) return element;\n\n      if (element.addEventListener) {\n        element.addEventListener(name, wrapper, false);\n      } else {\n        element.attachEvent(\"on\" + name, wrapper);\n      }\n\n      return element;\n    },\n\n    stopObserving: function(element, eventName, handler) {\n      element = $(element);\n      var id = getEventID(element), name = getDOMEventName(eventName);\n\n      if (!handler && eventName) {\n        getWrappersForEventName(id, eventName).each(function(wrapper) {\n          element.stopObserving(eventName, wrapper.handler);\n        });\n        return element;\n\n      } else if (!eventName) {\n        Object.keys(getCacheForID(id)).each(function(eventName) {\n          element.stopObserving(eventName);\n        });\n        return element;\n      }\n\n      var wrapper = findWrapper(id, eventName, handler);\n      if (!wrapper) return element;\n\n      if (element.removeEventListener) {\n        element.removeEventListener(name, wrapper, false);\n      } else {\n        element.detachEvent(\"on\" + name, wrapper);\n      }\n\n      destroyWrapper(id, eventName, handler);\n\n      return element;\n    },\n\n    fire: function(element, eventName, memo) {\n      element = $(element);\n      if (element == document && document.createEvent && !element.dispatchEvent)\n        element = document.documentElement;\n\n      var event;\n      if (document.createEvent) {\n        event = document.createEvent(\"HTMLEvents\");\n        event.initEvent(\"dataavailable\", true, true);\n      } else {\n        event = document.createEventObject();\n        event.eventType = \"ondataavailable\";\n      }\n\n      event.eventName = eventName;\n      event.memo = memo || { };\n\n      if (document.createEvent) {\n        element.dispatchEvent(event);\n      } else {\n        element.fireEvent(event.eventType, event);\n      }\n\n      return Event.extend(event);\n    }\n  };\n})());\n\nObject.extend(Event, Event.Methods);\n\nElement.addMethods({\n  fire:          Event.fire,\n  observe:       Event.observe,\n  stopObserving: Event.stopObserving\n});\n\nObject.extend(document, {\n  fire:          Element.Methods.fire.methodize(),\n  observe:       Element.Methods.observe.methodize(),\n  stopObserving: Element.Methods.stopObserving.methodize(),\n  loaded:        false\n});\n\n(function() {\n  /* Support for the DOMContentLoaded event is based on work by Dan Webb,\n     Matthias Miller, Dean Edwards and John Resig. */\n\n  var timer;\n\n  function fireContentLoadedEvent() {\n    if (document.loaded) return;\n    if (timer) window.clearInterval(timer);\n    document.fire(\"dom:loaded\");\n    document.loaded = true;\n  }\n\n  if (document.addEventListener) {\n    if (Prototype.Browser.WebKit) {\n      timer = window.setInterval(function() {\n        if (/loaded|complete/.test(document.readyState))\n          fireContentLoadedEvent();\n      }, 0);\n\n      Event.observe(window, \"load\", fireContentLoadedEvent);\n\n    } else {\n      document.addEventListener(\"DOMContentLoaded\",\n        fireContentLoadedEvent, false);\n    }\n\n  } else {\n    document.write(\"<script id=__onDOMContentLoaded defer src=//:><\\/script>\");\n    $(\"__onDOMContentLoaded\").onreadystatechange = function() {\n      if (this.readyState == \"complete\") {\n        this.onreadystatechange = null;\n        fireContentLoadedEvent();\n      }\n    };\n  }\n})();\n/*------------------------------- DEPRECATED -------------------------------*/\n\nHash.toQueryString = Object.toQueryString;\n\nvar Toggle = { display: Element.toggle };\n\nElement.Methods.childOf = Element.Methods.descendantOf;\n\nvar Insertion = {\n  Before: function(element, content) {\n    return Element.insert(element, {before:content});\n  },\n\n  Top: function(element, content) {\n    return Element.insert(element, {top:content});\n  },\n\n  Bottom: function(element, content) {\n    return Element.insert(element, {bottom:content});\n  },\n\n  After: function(element, content) {\n    return Element.insert(element, {after:content});\n  }\n};\n\nvar $continue = new Error('\"throw $continue\" is deprecated, use \"return\" instead');\n\n// This should be moved to script.aculo.us; notice the deprecated methods\n// further below, that map to the newer Element methods.\nvar Position = {\n  // set to true if needed, warning: firefox performance problems\n  // NOT neeeded for page scrolling, only if draggable contained in\n  // scrollable elements\n  includeScrollOffsets: false,\n\n  // must be called before calling withinIncludingScrolloffset, every time the\n  // page is scrolled\n  prepare: function() {\n    this.deltaX =  window.pageXOffset\n                || document.documentElement.scrollLeft\n                || document.body.scrollLeft\n                || 0;\n    this.deltaY =  window.pageYOffset\n                || document.documentElement.scrollTop\n                || document.body.scrollTop\n                || 0;\n  },\n\n  // caches x/y coordinate pair to use with overlap\n  within: function(element, x, y) {\n    if (this.includeScrollOffsets)\n      return this.withinIncludingScrolloffsets(element, x, y);\n    this.xcomp = x;\n    this.ycomp = y;\n    this.offset = Element.cumulativeOffset(element);\n\n    return (y >= this.offset[1] &&\n            y <  this.offset[1] + element.offsetHeight &&\n            x >= this.offset[0] &&\n            x <  this.offset[0] + element.offsetWidth);\n  },\n\n  withinIncludingScrolloffsets: function(element, x, y) {\n    var offsetcache = Element.cumulativeScrollOffset(element);\n\n    this.xcomp = x + offsetcache[0] - this.deltaX;\n    this.ycomp = y + offsetcache[1] - this.deltaY;\n    this.offset = Element.cumulativeOffset(element);\n\n    return (this.ycomp >= this.offset[1] &&\n            this.ycomp <  this.offset[1] + element.offsetHeight &&\n            this.xcomp >= this.offset[0] &&\n            this.xcomp <  this.offset[0] + element.offsetWidth);\n  },\n\n  // within must be called directly before\n  overlap: function(mode, element) {\n    if (!mode) return 0;\n    if (mode == 'vertical')\n      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /\n        element.offsetHeight;\n    if (mode == 'horizontal')\n      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /\n        element.offsetWidth;\n  },\n\n  // Deprecation layer -- use newer Element methods now (1.5.2).\n\n  cumulativeOffset: Element.Methods.cumulativeOffset,\n\n  positionedOffset: Element.Methods.positionedOffset,\n\n  absolutize: function(element) {\n    Position.prepare();\n    return Element.absolutize(element);\n  },\n\n  relativize: function(element) {\n    Position.prepare();\n    return Element.relativize(element);\n  },\n\n  realOffset: Element.Methods.cumulativeScrollOffset,\n\n  offsetParent: Element.Methods.getOffsetParent,\n\n  page: Element.Methods.viewportOffset,\n\n  clone: function(source, target, options) {\n    options = options || { };\n    return Element.clonePosition(target, source, options);\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nif (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){\n  function iter(name) {\n    return name.blank() ? null : \"[contains(concat(' ', @class, ' '), ' \" + name + \" ')]\";\n  }\n\n  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?\n  function(element, className) {\n    className = className.toString().strip();\n    var cond = /\\s/.test(className) ? $w(className).map(iter).join('') : iter(className);\n    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];\n  } : function(element, className) {\n    className = className.toString().strip();\n    var elements = [], classNames = (/\\s/.test(className) ? $w(className) : null);\n    if (!classNames && !className) return elements;\n\n    var nodes = $(element).getElementsByTagName('*');\n    className = ' ' + className + ' ';\n\n    for (var i = 0, child, cn; child = nodes[i]; i++) {\n      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||\n          (classNames && classNames.all(function(name) {\n            return !name.toString().blank() && cn.include(' ' + name + ' ');\n          }))))\n        elements.push(Element.extend(child));\n    }\n    return elements;\n  };\n\n  return function(className, parentElement) {\n    return $(parentElement || document.body).getElementsByClassName(className);\n  };\n}(Element.Methods);\n\n/*--------------------------------------------------------------------------*/\n\nElement.ClassNames = Class.create();\nElement.ClassNames.prototype = {\n  initialize: function(element) {\n    this.element = $(element);\n  },\n\n  _each: function(iterator) {\n    this.element.className.split(/\\s+/).select(function(name) {\n      return name.length > 0;\n    })._each(iterator);\n  },\n\n  set: function(className) {\n    this.element.className = className;\n  },\n\n  add: function(classNameToAdd) {\n    if (this.include(classNameToAdd)) return;\n    this.set($A(this).concat(classNameToAdd).join(' '));\n  },\n\n  remove: function(classNameToRemove) {\n    if (!this.include(classNameToRemove)) return;\n    this.set($A(this).without(classNameToRemove).join(' '));\n  },\n\n  toString: function() {\n    return $A(this).join(' ');\n  }\n};\n\nObject.extend(Element.ClassNames.prototype, Enumerable);\n\n/*--------------------------------------------------------------------------*/\n\nElement.addMethods();"
  }
]