onComplete: function() { if (this.cancelAllUploads) { this.cancelAllUploads = false; return; } var _self = this; var file = this.currentFile; //var path = file.targetFolder.getAttribute("path"); this.totalNumUploads--; apf.xmldb.setAttribute(file.queueNode, "progress", "100"); apf.xmldb.setAttribute(file.treeNode, "type", "file"); if (_self.openOnUpload) { if (file.size < MAX_OPENFILE_SIZE) ide.dispatchEvent("openfile", {doc: ide.createDocument(file.treeNode)}); } setTimeout(function() { if (!_self.lockHideQueue && file.queueNode) apf.xmldb.removeNode(file.queueNode); else _self.lockHideQueueItems.push(file); }, 1000); this.addNextFileToQueue(); return _self.uploadNextFile(); },
lstOpenFiles.addEventListener("afterselect", this.$afterselect = function(e) { var node = this.selected; if (!node || this.selection.length > 1) return; ide.dispatchEvent("openfile", { doc: ide.createDocument(node) }); });
trFiles.addEventListener("afterchoose", this.$afterselect = function(e) { var node = this.selected; if (!node || node.tagName != "file" || this.selection.length > 1 || !ide.onLine && !ide.offlineFileSystemSupport) //ide.onLine can be removed after update apf return; ide.dispatchEvent("openfile", {doc: ide.createDocument(node)}); });
lstOpenFiles.addEventListener("afterselect", function(e) { var node = this.selected; if (!node || this.selection.length > 1) return; editors.gotoDocument({ doc: ide.createDocument(node), origin: "openfiles" }); });
onclick : function(){ var node = apf.getXml("<file />"); node.setAttribute("name", def.caption); node.setAttribute("path", def.value); editors.gotoDocument({doc: ide.createDocument(node)}); }
fs.webdav.exec("readdir", [path], function(data) { if (!data || data instanceof Error) { // @todo: should we display the error message in the Error object too? util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); return next(); } // parse xml var filesInDirXml = apf.getXml(data); // we expect the new created file in the directory listing var fullFilePath = path + "/" + filename; file = filesInDirXml.selectSingleNode("//file[@path='" + fullFilePath + "']"); // not found? display an error if (!file) { util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); return next(); } var oXml = apf.xmldb.appendChild(node, file); trFiles.select(oXml); if (file.size < MAX_OPENFILE_SIZE) ide.dispatchEvent("openfile", {doc: ide.createDocument(oXml)}); next(); });
editAutoRunPattern : function(){ var node = apf.n("<file />") .attr("name", "Pattern.js") .attr("path", "/workspace/.c9.test.pattern") .attr("changed", "1") .attr("newfile", "1") .node(); var pattern = this.getPattern(); var doc = ide.createDocument(node); doc.cachedValue = pattern; editors.gotoDocument({doc: doc, node: node, origin: "testpanel"}); ide.addEventListener("beforefilesave", function(e){ if (e.node == node) { var value = doc.getValue(); settings.model.setQueryValue("auto/testpanel/pattern/text()", value); node.removeAttribute("changed"); node.removeAttribute("newfile"); var page = tabEditors.getPage("/workspace/.c9.test.pattern"); tabEditors.remove(page); ide.removeEventListener("beforefilesave", arguments.callee); return false; } }); },
onclick : function(){ var node = apf.getXml("<file />"); node.setAttribute("name", def.caption); node.setAttribute("path", def.value); ide.dispatchEvent("openfile", {doc: ide.createDocument(node)}); }
var test = function(exists) { if (exists) { filename = prefix + "." + index++; _self.exists(path + "/" + filename, test); } else { if (!newFile) { var file var both = 0; function done(){ if (both == 2) { file = apf.xmldb.appendChild(node, file); trFiles.select(file); trFiles.startRename(); trFiles.slideOpen(null, node, true); } } trFiles.slideOpen(null, node, true, function(){ both++; done(); }); _self.webdav.exec("create", [path, filename], function(data) { _self.webdav.exec("readdir", [path], function(data) { if (!data || data instanceof Error) { // @todo: should we display the error message in the Error object too? return util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); } // parse xml var filesInDirXml = apf.getXml(data); // we expect the new created file in the directory listing var fullFilePath = path + "/" + filename; var nodes = filesInDirXml.selectNodes("//file[@path='" + fullFilePath + "']"); // not found? display an error if (nodes.length === 0) { return util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); } file = nodes[0]; both++; done(); }); }); } else { node.setAttribute("name", filename); node.setAttribute("path", path + "/" + filename); ide.dispatchEvent("openfile", {doc: ide.createDocument(node), type:"newfile"}); } } };
jump : function(options) { var row = options.row; var column = options.column || 0; var text = options.text; var page = options.page; var hasData; if (!options.doc) { var node = options.node; var path = node.getAttribute("path"); var tabs = tabEditors; hasData = page && (tabs.getPage(path) || { }).$doc ? true : false; } var _self = this; if (row !== undefined) { var jumpTo = function(){ var f; setTimeout(f = function() { // TODO move this to the editor var editor = _self.currentEditor.amlEditor; editor.$editor.gotoLine(row, column, options.animate !== false); if (text) editor.$editor.session.highlight(text); editor.focus(); ide.dispatchEvent("aftereditorfocus"); }, 1); }; if (hasData) { tabs.set(path); jumpTo(); } else ide.addEventListener("afteropenfile", function(e) { var node = e.doc.getNode(); if (node.getAttribute("path") == path) { ide.removeEventListener("afteropenfile", arguments.callee); jumpTo(); } }); } if (!hasData) { options.origin = "jump"; if (!options.doc) options.doc = ide.createDocument(options.node); var extraOptions = this.openEditor(options.doc, options.init, options.active, options.forceOpen); ide.dispatchEvent("openfile", apf.extend(options, extraOptions)); } else tabs.set(path); },
handleMessage : function(event) { if (event.message.type === "remotecontrol") { if (event.message.action === "openfile") { // Generic case: hide sidebar (do this first, it's a little slow) if (event.message.args.options.name === "generic") { require("ext/panels/panels").deactivate(null, false); } // Brand new file: create a dummy file that, when saved, becomes real (can be generic or workspace) if (event.message.args.options.noexist === true) { var node = fs.createFileNodeFromPath( event.message.args.path); node.setAttribute("newfile", "1"); node.setAttribute("cli", "1"); // blocks Save As dialog var doc = ide.createDocument(node); doc.cachedValue = ""; ide.dispatchEvent("openfile", {doc: doc, node: node}); } else {// Generic and Workspace case: open a single file editors.gotoDocument({path: event.message.args.path}); // Workspace case: the file is found in tree, expand it if (event.message.args.options.name !== "generic") { var node = fs.createFileNodeFromPath(event.message.args.path); tabbehaviors.revealInTree(node); } } } else if (event.message.action === "opendir") { var node = fs.model.queryNode("//folder[@path='" + event.message.args.path + "']"); if (!node) { node = fs.createFolderNodeFromPath(event.message.args.path); } tabbehaviors.revealInTree(node); } else if (event.message.action === "notify") { var eventName = event.message.args.event.name; if (eventName === "internet-available") { var state = event.message.args.event.value; if (state === false) ide.dispatchEvent("localOffline", event); else ide.dispatchEvent("localOnline", event); } else if (eventName === "c9local-update") { ide.dispatchEvent("localUpdateAvailable", event); } else if (eventName === "workspace-deleted") { winWSDeleted.show(); } } } },
dbg.main.loadSource(script, function(source) { var doc = ide.createDocument(node, source); editors.jump({ node : node, row : row, column : column, text : text, doc : doc }); });
ide.addEventListener("extload", function(){ // you can load a file from the hash tag, if that succeeded then return var loadFileFromHash = (_self.loadFileFromHash(window.location.hash, checkExpand)); if (loadFileFromHash) { window.location.hash = loadFileFromHash; // update hash return; } // otherwise, restore state from the .config file var active = model.queryValue("auto/files/@active"); var nodes = model.queryNodes("auto/files/file"); for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; var state = node.getAttribute("state"); var doc = ide.createDocument(node); // for some reason c9local can aggresively cache open files; this prevents // open files from one workspace appearing in another if (ide.local) { if (node.getAttribute("path").split("/")[2] !== ide.workspaceId) continue; } try { if (state) doc.state = JSON.parse(state); } catch (ex) {} // node.firstChild is not always present (why?) if ((node.getAttribute("changed") == 1) && node.firstChild) { doc.cachedValue = node.firstChild.nodeValue .replace(/\n]\n]/g, "]]") .replace(/\\r/g, "\r") .replace(/\\n/g, "\n"); } _self.gotoDocument({ doc : doc, init : true, type : doc.state && doc.state.type, forceOpen: true, active : active ? active == node.getAttribute("path") : i == l - 1, origin: "settings" }); if (doc.state && doc.state.type != "nofile") checkExpand(node.getAttribute("path"), doc); } _self.loadedSettings = true; });
ide.addEventListener("extload", function(){ var active = model.queryValue("auto/files/@active"); var nodes = model.queryNodes("auto/files/file"); for (var i = 0, l = nodes.length; i < l; i++) { ide.dispatchEvent("openfile", { doc : ide.createDocument(nodes[i]), init : true, active : active ? active == nodes[i].getAttribute("path") : i == l - 1 }); } });
var test = function(exists) { if (exists) { filename = prefix + "." + index++; _self.exists(path + "/" + filename, test); } else { if (!newFile) { var file var both = 0; function done(){ if (both == 2) { file = apf.xmldb.appendChild(node, file); trFiles.select(file); trFiles.startRename(); } } trFiles.slideOpen(null, node, true, function(){ both++; done(); }); _self.webdav.exec("create", [path, filename], function(data) { _self.webdav.exec("readdir", [path], function(data) { if (data instanceof Error) { // @todo: should we display the error message in the Error object too? return util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); } var m = data.match(new RegExp(("(<file path='" + path + "/" + filename + "'.*?>)").replace(/\//g, "\\/"))) if (!m) { return util.alert("Error", "File '" + filename + "' could not be created", "An error occurred while creating a new file, please try again."); } file = apf.getXml(m[1]); both++; done(); }); }); } else { node.setAttribute("name", filename); node.setAttribute("path", path + "/" + filename); ide.dispatchEvent("openfile", {doc: ide.createDocument(node), type:"newfile"}); } } };
filesystem.exists(path, function(exists){ if (exists) { editors.showFile(path); } else { var node = editors.createFileNodeFromPath(path); node.setAttribute("newfile", "1"); node.setAttribute("changed", "1"); node.setAttribute("cli", "1"); // blocks Save As dialog var doc = ide.createDocument(node); doc.cachedValue = ""; ide.dispatchEvent("openfile", {doc: doc, node: node}); } });
newfile: function(type, value, path) { if (ide.readonly) return; if (!type) type = ""; var node = apf.getXml("<file />"); if (!path && self.trFiles) { var sel = trFiles.selected; if (!sel) { trFiles.select(trFiles.$model.queryNode('folder')); sel = trFiles.selected; } if (sel) { path = sel.getAttribute("path"); if (trFiles.selected.getAttribute("type") == "file" || trFiles.selected.tagName == "file") path = path.replace(/\/[^\/]*$/, "/"); else path = path + "/"; } } if (!path) path = ide.davPrefix + "/"; var name = "Untitled", count = 1; while (tabEditors.getPage(path + name + count + type)) count++; node.setAttribute("name", name + count + type); node.setAttribute("path", path + name + count + type); node.setAttribute("changed", "1"); node.setAttribute("newfile", "1"); var doc = ide.createDocument(node); if (value) doc.cachedValue = value; require("ext/editors/editors").gotoDocument({ doc: doc, type: "newfile", origin: "newfile" }); ide.dispatchEvent("track_action", {type: "template", template: type}); },
fs.webdav.exec("readdir", [path], function(data) { if (data instanceof Error) { // @todo: in case of error, show nice alert dialog. return next(); } var strXml = data.match(new RegExp(("(<file path='" + path + "/" + filename + "'.*?>)").replace(/\//g, "\\/")))[1]; var oXml = apf.xmldb.appendChild(node, apf.getXml(strXml)); trFiles.select(oXml); if (file.size < MAX_OPENFILE_SIZE) ide.dispatchEvent("openfile", {doc: ide.createDocument(oXml)}); next(); });
ide.addEventListener("extload", function(){ // you can load a file from the hash tag, if that succeeded then return var loadFileFromHash = (_self.loadFileFromHash(window.location.hash, checkExpand)); if (loadFileFromHash) { window.location.hash = loadFileFromHash; // update hash return; } // otherwise, restore state from the .config file var active = model.queryValue("auto/files/@active"); var nodes = model.queryNodes("auto/files/file"); for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; var state = node.getAttribute("state"); var doc = ide.createDocument(node); try { if (state) doc.state = JSON.parse(state); } catch (ex) {} // node.firstChild is not always present (why?) if ((node.getAttribute("changed") == 1) && node.firstChild) { doc.cachedValue = node.firstChild.nodeValue .replace(/\n]\n]/g, "]]") .replace(/\\r/g, "\r") .replace(/\\n/g, "\n"); } ide.dispatchEvent("openfile", { doc : doc, init : true, forceOpen: true, active : active ? active == node.getAttribute("path") : i == l - 1 }); checkExpand(node.getAttribute("path"), doc); } _self.loadedSettings = true; });
var test = function(exists) { if (exists) { filename = prefix + "." + index++; _self.exists(path + "/" + filename, test); } else { if(!newFile) { var file, both = 0; function done(){ if (both == 2) { file = apf.xmldb.appendChild(node, file); trFiles.select(file); trFiles.startRename(); } } trFiles.slideOpen(null, node, true, function(){ both++; done(); }); _self.webdav.exec("create", [path, filename], function(data) { _self.webdav.exec("readdir", [path], function(data) { // @todo: in case of error, show nice alert dialog if (data instanceof Error) throw Error; var strXml = data.match(new RegExp(("(<file path='" + path + "/" + filename + "'.*?>)").replace(/\//g, "\\/")))[1]; file = apf.getXml(strXml); both++; done(); }); }); } else { node.setAttribute('name', filename); node.setAttribute('path', path + '/' + filename); ide.dispatchEvent("openfile", {doc: ide.createDocument(node), type:'newfile'}); } } };
loadFileFromHash : function (hash, checkExpand) { // an initial state can be sent in the hash // match 'openfile-', // match any character except :& or end of file // optional: match : digit - digit // [1] is filename, [2] is starting line number, [3] is ending line number var editorInitialStatePattern = /openfile-(.[^:&$]*)(?:\:(\d+)-(\d+))?/; var rawState = hash.match(editorInitialStatePattern); if (rawState) { // build the real path, as the one in the hash is relative var path = ide.davPrefix.replace(/\/$/, "") + "/" + rawState[1]; // require here is necessary for c9local, please do not change var doc = ide.createDocument(require("ext/filesystem/filesystem").createFileNodeFromPath(path)); // if selection information was added, add that to the state if (rawState[2] && rawState[3]) { doc.state = { scrollleft: 0, scrolltop: 0, selection: { start: { row: parseInt(rawState[2] || 0, 10) - 1, column: 0 }, end: { row: parseInt(rawState[3] || 0, 10), column: 0 } // plus 1 to capture whole previous line } }; } // send it to the dispatcher this.gotoDocument({ doc : doc, active : true, origin : "hash" }); // and expand the tree checkExpand(path, doc); // return the new hash return hash.replace(editorInitialStatePattern, ""); } return null; },
filesystem.exists(path, function(exists){ if (exists) { editors.gotoDocument({path: path}); } else { var node = filesystem.createFileNodeFromPath(path); node.setAttribute("newfile", "1"); node.setAttribute("changed", "1"); node.setAttribute("cli", "1"); // blocks Save As dialog var doc = ide.createDocument(node); doc.cachedValue = ""; editors.gotoDocument({ doc: doc, type: "newfile", origin: "newfile" }); } });
jump : function(fileEl, row, column, text, doc, page) { var path = fileEl.getAttribute("path"); var tabs = tabEditors; var hasData = page && (tabs.getPage(path) || { }).$doc ? true : false; var _self = this; if (row !== undefined) { var editor = _self.currentEditor.amlEditor; var jumpTo = function(){ var f; setTimeout(f = function() { // TODO move this to the editor editor.$editor.gotoLine(row, column, false); if (text) editor.$editor.find(text, null, false); editor.focus(); }, 100); }; if (hasData) { tabs.set(path); jumpTo(); } else ide.addEventListener("afteropenfile", function(e) { var node = e.doc.getNode(); if (node.getAttribute("path") == path) { ide.removeEventListener("afteropenfile", arguments.callee); jumpTo(); } }); } if (!hasData) ide.dispatchEvent("openfile", { doc: doc || ide.createDocument(fileEl) }); else tabs.set(path); },
newfile: function(type, value) { if (!type) type = ""; var node = apf.getXml("<file />"); var path = "/workspace/"; var sel = trFiles.selected; if (!sel) { trFiles.select(trFiles.$model.queryNode('folder')); sel = trFiles.selected; } if (!sel) return; path = sel.getAttribute("path"); if (trFiles.selected.getAttribute("type") == "file" || trFiles.selected.tagName == "file") path = path.replace(/\/[^\/]*$/, "/"); else path = path + "/"; var name = "Untitled", count = 1; while (tabEditors.getPage(path + name + count + type)) count++; node.setAttribute("name", name + count + type); node.setAttribute("path", path + name + count + type); node.setAttribute("changed", "1"); node.setAttribute("newfile", "1"); var doc = ide.createDocument(node); if (value) doc.cachedValue = value; ide.dispatchEvent("openfile", { doc: doc, type: "newfile" }); },
openSessionFiles : function(name) { var active = settings.model.queryValue("auto/sessions/session[@name=\"" + name + "\"]/files/@active"); var nodes = settings.model.queryNodes("auto/sessions/session[@name=\"" + name + "\"]/files/file"); var sessionfiles = settings.model.queryNode("auto/sessions/session[@name=\"" + name + "\"]/files"); if (!sessionfiles) return; // or display error for (var doc, i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; if (node.getAttribute("newfile") != "1") node.removeAttribute("changed"); doc = ide.createDocument(node); doc.parentNode = {}; var state = node.getAttribute("state"); if (state) { try { doc.state = JSON.parse(state); } catch(e) {} } editors.gotoDocument({ doc : doc, init : true, active : active ? active == node.getAttribute("path") : i == l - 1, origin: "tabsessions" }); } var oldfiles = settings.model.queryNode("auto/files"); if (oldfiles) settings.model.removeXml("auto/files"); settings.model.appendXml(sessionfiles.cloneNode(true), "auto"); settings.save(); },
jump : function(fileEl, row, column, text, doc, page) { var path = fileEl.getAttribute("path"); var hasData = page && tabEditors.getPage(path).$doc ? true : false; if (row !== undefined) { var jumpTo = function(){ setTimeout(function() { // TODO move this to the editor ceEditor.$editor.gotoLine(row, column); if (text) ceEditor.$editor.find(text); ceEditor.focus(); }, 100); }; if (hasData) { tabEditors.set(path); jumpTo(); } else ide.addEventListener("afteropenfile", function(e) { var node = e.doc.getNode(); if (node.getAttribute("path") == path) { ide.removeEventListener("afteropenfile", arguments.callee); jumpTo(); } }); } if (!hasData && !page) ide.dispatchEvent("openfile", { doc: doc || ide.createDocument(fileEl) }); else tabEditors.set(path); },
jumpToFileAndLineNumber: function(path, lineNo) { var name; // This is ok if there is no / because then lastIndexOf returns -1 // so we get the whole string. name = path.slice(path.lastIndexOf("/") + 1) // Remove any leading /s and prepend the davPrefix. var fullPath = path; fullPath = fullPath.replace(/^(\/)*/, ""); fullPath = ide.davPrefix + "/" + fullPath; var node = apf.n("<file />") .attr("name", name) .attr("contenttype", util.getContentType(name)) .attr("path", fullPath) .node(); ide.addEventListener("afteropenfile", function(e) { ceEditor.$editor.gotoLine(lineNo); ide.removeEventListener("afteropenfile", arguments.callee); }) ide.dispatchEvent("openfile", { doc: ide.createDocument(node) }); },
dgTestProject.addEventListener("afterchoose", function(e){ var node = this.selected; if (!node || this.selection.length > 1) return; //Open if (altKey) { if (node.tagName != "file" || !ide.onLine && !ide.offlineFileSystemSupport) return; editors.gotoDocument({doc: ide.createDocument(node), origin: "testpanel"}); //@todo choose a test or an assert should select that code // inside ace. } //Run else { if ("file|test|repo".indexOf(node.tagName) == -1 || !ide.onLine) return; _self.run([node]); } });
dbg.loadScript(script, function(source) { var doc = ide.createDocument(node, source); editors.jump(node, row, column, text, doc); });
execFind: function() { var _self = this; // Determine the scope of the search var path; if (grpSFScope.value == "projects") { path = ide.davPrefix; } else if (!trFiles) { path = settings.model.queryValue("auto/tree_selection/@path"); if (!path) return; var p; if ((name = (p = path.split("/")).pop()).indexOf(".") > -1) name = p.pop(); } if (!path) { var node = this.getSelectedTreeNode(); path = node.getAttribute("path"); } var options = this.getOptions(); var query = txtSFFind.getValue(); options.query = query.replace(/\n/g, "\\n"); // even if there's text in the "replace" field, don't send it when not replacing if (!this.replaceAll) options.replacement = ""; // prepare new Ace document to handle search results var node = apf.n("<file/>") .attr("name", "Search Results") .attr("path", this.searchFilePath) .attr("customtype", util.getContentType(this.searchContentType)) .attr("tooltip", "Search Results") .attr("newfile", "0") .attr("ignore", "1") .attr("saving", "1") .node(); var doc = ide.createDocument(node); // arrange beginning message var messageHeader = this.messageHeader(path, options); if (chkSFConsole.checked) { // show the console; require here is necessary for c9local, please do not change require("ext/console/console").show(); this.makeSearchResultsPanel(); // the search results already exist if (_self.consoleacedoc) { _self.appendLines(_self.consoleacedoc, messageHeader); } else { _self.searchConsole.$editor.setSession(new EditSession(new Document(messageHeader), "ace/mode/c9search")); _self.consoleacedoc = _self.searchConsole.$editor.session.doc; // store a reference to the doc _self.consoleacedoc.ace = _self.searchConsole.$editor; // set tab editor commands here _self.searchConsole.$editor.commands._defaultHandlers = commands._defaultHandlers; _self.searchConsole.$editor.commands.commands = commands.commands; _self.searchConsole.$editor.commands.commandKeyBinding = commands.commandKeyBinding; _self.searchConsole.$editor.getSession().setUndoManager(new UndoManager()); } _self.setHighlight(_self.searchConsole.$editor.getSession(), options.query); } else { if (_self.searchPage === null) { // the results are not open, create a new page doc.cachedValue = messageHeader; editors.gotoDocument({ doc : doc, node : node, forceOpen : true }); _self.searchPage = ide.getActivePage(); _self.searcheditor = _self.searchPage.$editor.amlEditor.$editor; _self.apfeditor = _self.searchPage.$editor.amlEditor; _self.tabacedoc = _self.searchPage.$doc.acedoc; _self.tabacedoc.node = node; apf.setStyleClass(_self.apfeditor.$ext, "aceSearchResults"); _self.apfeditor.$editor.renderer.scroller.addEventListener("dblclick", function() { _self.launchFileFromSearch(_self.apfeditor.$editor); }); } else { _self.appendLines(_self.tabacedoc, messageHeader); tabEditors.set(tabEditors.getPages().indexOf(_self.searchPage) + 1); } _self.setHighlight(_self.searcheditor.getSession(), options.query); } if (options.query.length == 0) return; _self.toggleDialog(-1, null, true); this.firstRun = true; if (!this.$onMessage) { this.$onMessage = this.onMessage.bind(this) ide.addEventListener("socketMessage", this.$onMessage); } if (path.indexOf(ide.davPrefix) == 0) path = path.slice(ide.davPrefix.length).replace(/^\//,""); options.command = "codesearch"; options.path = path; ide.send(options); this.saveHistory(options.query, "searchfiles"); this.position = 0; ide.dispatchEvent("track_action", {type: "searchinfiles"}); },