/** * Sets the time in milliseconds of the last activity related to this <tt>Conference</tt> to the * current system time. */ public void touch() { long now = System.currentTimeMillis(); synchronized (this) { if (getLastActivityTime() < now) lastActivityTime = now; } }
/** Updates Jitsi icon notification to reflect current global status. */ public void updateJitsiIconNotification() { String status; if (getGlobalStatus().isOnline()) { // At least one provider is online status = JitsiApplication.getResString(R.string.service_gui_ONLINE); } else { // There are no active providers so we consider to be in // the offline state status = JitsiApplication.getResString(R.string.service_gui_OFFLINE); } int notificationID = OSGiService.getGeneralNotificationId(); if (notificationID == -1) { logger.debug( "Not displaying status notification because" + " there's no global notification icon available."); return; } AndroidUtils.updateGeneralNotification( JitsiApplication.getGlobalContext(), notificationID, JitsiApplication.getResString(R.string.app_name), status, System.currentTimeMillis()); }
/** Cancel all active downloads. */ public void cancelActiveDownloads() { for (Component c : this.monitorPanel.getComponents()) { if (c instanceof DownloadMonitorPanel) { if (((DownloadMonitorPanel) c).thread.isAlive()) { DownloadMonitorPanel panel = (DownloadMonitorPanel) c; panel.cancelButtonActionPerformed(null); try { // Wait for thread to die before moving on long t0 = System.currentTimeMillis(); while (panel.thread.isAlive() && System.currentTimeMillis() - t0 < 500) { Thread.sleep(10); } } catch (Exception ignore) { } } } } }
public void manageThreads() { try { DDTP request = new DDTP(); request.setRequestID(String.valueOf(System.currentTimeMillis())); DDTP response = channel.sendRequest("ThreadProcessor", "manageThreadsLoad", request); if (response != null) { DialogThreadManager dlg = new DialogThreadManager(this, channel, response.getVector("vtTableData")); dlg.setComboStartupType(response.getVector("vtStartupType"), ""); WindowManager.centeredWindow(dlg); } } catch (Exception e) { e.printStackTrace(); MessageBox.showMessageDialog(this, e, Global.APP_NAME, MessageBox.ERROR_MESSAGE); } }
//////////////////////////////////////////////////////// // Purpose: send message stop server // Author: TrungDD // Date: 10/2003 //////////////////////////////////////////////////////// public void stopServer() { if (MessageBox.showConfirmDialog( this, MonitorDictionary.getString("Confirm.Shutdown"), Global.APP_NAME, MessageBox.YES_NO_OPTION) == MessageBox.NO_OPTION) return; try { DDTP request = new DDTP(); request.setRequestID(String.valueOf(System.currentTimeMillis())); channel.sendRequest("ThreadProcessor", "closeServer", request); } catch (Exception e) { e.printStackTrace(); MessageBox.showMessageDialog(this, e, Global.APP_NAME, MessageBox.ERROR_MESSAGE); } }
public boolean startDownload(final FrostDownloadItem dlItem) { if (dlItem == null || dlItem.getState() != FrostDownloadItem.STATE_WAITING) { return false; } dlItem.setDownloadStartedTime(System.currentTimeMillis()); dlItem.setState(FrostDownloadItem.STATE_PROGRESS); final String gqid = dlItem.getGqIdentifier(); final File targetFile = new File(dlItem.getDownloadFilename()); boolean isDda = fcpTools.startPersistentGet(dlItem.getKey(), gqid, targetFile, dlItem.getPriority()); dlItem.setDirect(!isDda); return true; }
// Called on EDT public void propertyChange(PropertyChangeEvent ev) { String prop = ev.getPropertyName(); if (prop == JConsoleContext.CONNECTION_STATE_PROPERTY) { ConnectionState newState = (ConnectionState) ev.getNewValue(); switch (newState) { case DISCONNECTED: synchronized (this) { long time = System.currentTimeMillis(); times.add(time); for (Sequence seq : seqs) { seq.add(Long.MIN_VALUE); } } break; } } }
public boolean startUpload(final FrostUploadItem ulItem) { if (ulItem == null || ulItem.getState() != FrostUploadItem.STATE_WAITING) { return false; } ulItem.setUploadStartedMillis(System.currentTimeMillis()); ulItem.setState(FrostUploadItem.STATE_PROGRESS); // start the upload final boolean doMime; final boolean setTargetFileName; if (ulItem.isSharedFile()) { doMime = false; setTargetFileName = false; } else { doMime = true; setTargetFileName = true; } // try to start using DDA boolean isDda = fcpTools.startPersistentPutUsingDda( ulItem.getGqIdentifier(), ulItem.getFile(), ulItem.getFileName(), doMime, setTargetFileName, ulItem.getCompress(), ulItem.getFreenetCompatibilityMode(), ulItem.getPriority()); if (!isDda) { // upload was not startet because DDA is not allowed... // if UploadManager selected this file then it is not already in progress! directTransferQueue.appendItemToQueue(ulItem); } return true; }
public boolean writeSequence(NoteList noteList) { this.noteList = noteList; toneMap = toneMapFrame.getToneMap(); timeSet = toneMap.getTimeSet(); pitchSet = toneMap.getPitchSet(); timeRange = timeSet.getRange(); pitchRange = pitchSet.getRange(); if (!buildNoteSequence()) return false; try { sequence = new Sequence(Sequence.PPQ, 10); } catch (Exception ex) { ex.printStackTrace(); return false; } track = sequence.createTrack(); startTime = System.currentTimeMillis(); // add a program change right at the beginning of // the track for the current instrument createEvent(PROGRAM, cc.program + 1, 1); for (int i = 0; i < noteSequence.size(); i++) { noteSequenceElement = noteSequence.get(i); if (noteSequenceElement.state == ON) if (!createEvent(NOTEON, noteSequenceElement.note, noteSequenceElement.tick)) return false; if (noteSequenceElement.state == OFF) if (!createEvent(NOTEOFF, noteSequenceElement.note, noteSequenceElement.tick)) return false; } return true; }
public void login() { mbAutoLogIn = false; while (!mbAutoLogIn) { try { // Confirm logout if (isOpen()) { if (MessageBox.showConfirmDialog( this, MonitorDictionary.getString("Confirm.Exit"), Global.APP_NAME, MessageBox.YES_NO_OPTION) == MessageBox.NO_OPTION) return; // Disconnect from server disconnect(); } // Login DialogLogin dlgLogin = new DialogLogin(this); WindowManager.centeredWindow(dlgLogin); if (dlgLogin.miReturn == JOptionPane.OK_OPTION) { // Update UI SwingUtilities.updateComponentTreeUI(pnlUser); SwingUtilities.updateComponentTreeUI(pnlThread); // Request to connect Socket sck = new Socket(dlgLogin.mstrHost, Integer.parseInt(dlgLogin.mstrPort)); sck.setSoLinger(true, 0); // Start up a channel thread that reads messages from the server channel = new SocketTransmitter(sck) { public void close() { if (msckMain != null) { super.close(); closeAll(); if (mbAutoLogIn) login(); } } }; channel.setUserName(dlgLogin.mstrUserName); channel.setPackage("com.fss.thread."); channel.start(); // Request to Server DDTP request = new DDTP(); request.setRequestID(String.valueOf(System.currentTimeMillis())); request.setString("UserName", dlgLogin.mstrUserName); request.setString("Password", dlgLogin.mstrPassword); // Response from Server DDTP response = channel.sendRequest("ThreadProcessor", "login", request); mstrThreadAppName = response.getString("strThreadAppName"); mstrThreadAppVersion = response.getString("strThreadAppVersion"); mstrAppName = response.getString("strAppName"); mstrAppVersion = response.getString("strAppVersion"); if (response != null) { if (response.getString("PasswordExpired") != null) { DialogChangePassword frm = new DialogChangePassword(this, channel); WindowManager.centeredWindow(frm); if (frm.miReturnValue != JOptionPane.OK_OPTION) throw new AppException("FSS-10003"); } String strLog = StringUtil.nvl(response.getString("strLog"), ""); showResult(txtBoard, strLog); Vector vtThread = response.getVector("vtThread"); updateTabBar(vtThread); mstrChannel = response.getString("strChannel"); if (mstrChannel != null) removeUser(mstrChannel); } btnRefresh.doClick(); pnlThread.setVisible(true); pnlUser.setVisible(true); setResizeWeight(1); setDividerLocation((int) (getSize().getHeight() - 160)); } mbAutoLogIn = true; updateLanguage(); } catch (Exception e) { e.printStackTrace(); MessageBox.showMessageDialog(this, e, Global.APP_NAME, MessageBox.ERROR_MESSAGE); // Disconnect from server mstrChannel = null; disconnect(); } } }
@Override public void paintComponent(Graphics g) { super.paintComponent(g); int width = getWidth() - rightMargin - leftMargin - 10; int height = getHeight() - topMargin - bottomMargin; if (width <= 0 || height <= 0) { // not enough room to paint anything return; } Color oldColor = g.getColor(); Font oldFont = g.getFont(); Color fg = getForeground(); Color bg = getBackground(); boolean bgIsLight = (bg.getRed() > 200 && bg.getGreen() > 200 && bg.getBlue() > 200); ((Graphics2D) g) .setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (smallFont == null) { smallFont = oldFont.deriveFont(9.0F); } r.x = leftMargin - 5; r.y = topMargin - 8; r.width = getWidth() - leftMargin - rightMargin; r.height = getHeight() - topMargin - bottomMargin + 16; if (border == null) { // By setting colors here, we avoid recalculating them // over and over. border = new BevelBorder( BevelBorder.LOWERED, getBackground().brighter().brighter(), getBackground().brighter(), getBackground().darker().darker(), getBackground().darker()); } border.paintBorder(this, g, r.x, r.y, r.width, r.height); // Fill background color g.setColor(bgColor); g.fillRect(r.x + 2, r.y + 2, r.width - 4, r.height - 4); g.setColor(oldColor); long tMin = Long.MAX_VALUE; long tMax = Long.MIN_VALUE; long vMin = Long.MAX_VALUE; long vMax = 1; int w = getWidth() - rightMargin - leftMargin - 10; int h = getHeight() - topMargin - bottomMargin; if (times.size > 1) { tMin = Math.min(tMin, times.time(0)); tMax = Math.max(tMax, times.time(times.size - 1)); } long viewRangeMS; if (viewRange > 0) { viewRangeMS = viewRange * MINUTE; } else { // Display full time range, but no less than a minute viewRangeMS = Math.max(tMax - tMin, 1 * MINUTE); } // Calculate min/max values for (Sequence seq : seqs) { if (seq.size > 0) { for (int i = 0; i < seq.size; i++) { if (seq.size == 1 || times.time(i) >= tMax - viewRangeMS) { long val = seq.value(i); if (val > Long.MIN_VALUE) { vMax = Math.max(vMax, val); vMin = Math.min(vMin, val); } } } } else { vMin = 0L; } if (unit == Unit.BYTES || !seq.isPlotted) { // We'll scale only to the first (main) value set. // TODO: Use a separate property for this. break; } } // Normalize scale vMax = normalizeMax(vMax); if (vMin > 0) { if (vMax / vMin > 4) { vMin = 0; } else { vMin = normalizeMin(vMin); } } g.setColor(fg); // Axes // Draw vertical axis int x = leftMargin - 18; int y = topMargin; FontMetrics fm = g.getFontMetrics(); g.drawLine(x, y, x, y + h); int n = 5; if (("" + vMax).startsWith("2")) { n = 4; } else if (("" + vMax).startsWith("3")) { n = 6; } else if (("" + vMax).startsWith("4")) { n = 4; } else if (("" + vMax).startsWith("6")) { n = 6; } else if (("" + vMax).startsWith("7")) { n = 7; } else if (("" + vMax).startsWith("8")) { n = 8; } else if (("" + vMax).startsWith("9")) { n = 3; } // Ticks ArrayList<Long> tickValues = new ArrayList<Long>(); tickValues.add(vMin); for (int i = 0; i < n; i++) { long v = i * vMax / n; if (v > vMin) { tickValues.add(v); } } tickValues.add(vMax); n = tickValues.size(); String[] tickStrings = new String[n]; for (int i = 0; i < n; i++) { long v = tickValues.get(i); tickStrings[i] = getSizeString(v, vMax); } // Trim trailing decimal zeroes. if (decimals > 0) { boolean trimLast = true; boolean removedDecimalPoint = false; do { for (String str : tickStrings) { if (!(str.endsWith("0") || str.endsWith("."))) { trimLast = false; break; } } if (trimLast) { if (tickStrings[0].endsWith(".")) { removedDecimalPoint = true; } for (int i = 0; i < n; i++) { String str = tickStrings[i]; tickStrings[i] = str.substring(0, str.length() - 1); } } } while (trimLast && !removedDecimalPoint); } // Draw ticks int lastY = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { long v = tickValues.get(i); y = topMargin + h - (int) (h * (v - vMin) / (vMax - vMin)); g.drawLine(x - 2, y, x + 2, y); String s = tickStrings[i]; if (unit == Unit.PERCENT) { s += "%"; } int sx = x - 6 - fm.stringWidth(s); if (y < lastY - 13) { if (checkLeftMargin(sx)) { // Wait for next repaint return; } g.drawString(s, sx, y + 4); } // Draw horizontal grid line g.setColor(Color.lightGray); g.drawLine(r.x + 4, y, r.x + r.width - 4, y); g.setColor(fg); lastY = y; } // Draw horizontal axis x = leftMargin; y = topMargin + h + 15; g.drawLine(x, y, x + w, y); long t1 = tMax; if (t1 <= 0L) { // No data yet, so draw current time t1 = System.currentTimeMillis(); } long tz = timeDF.getTimeZone().getOffset(t1); long tickInterval = calculateTickInterval(w, 40, viewRangeMS); if (tickInterval > 3 * HOUR) { tickInterval = calculateTickInterval(w, 80, viewRangeMS); } long t0 = tickInterval - (t1 - viewRangeMS + tz) % tickInterval; while (t0 < viewRangeMS) { x = leftMargin + (int) (w * t0 / viewRangeMS); g.drawLine(x, y - 2, x, y + 2); long t = t1 - viewRangeMS + t0; String str = formatClockTime(t); g.drawString(str, x, y + 16); // if (tickInterval > (1 * HOUR) && t % (1 * DAY) == 0) { if ((t + tz) % (1 * DAY) == 0) { str = formatDate(t); g.drawString(str, x, y + 27); } // Draw vertical grid line g.setColor(Color.lightGray); g.drawLine(x, topMargin, x, topMargin + h); g.setColor(fg); t0 += tickInterval; } // Plot values int start = 0; int nValues = 0; int nLists = seqs.size(); if (nLists > 0) { nValues = seqs.get(0).size; } if (nValues == 0) { g.setColor(oldColor); return; } else { Sequence seq = seqs.get(0); // Find starting point for (int p = 0; p < seq.size; p++) { if (times.time(p) >= tMax - viewRangeMS) { start = p; break; } } } // Optimization: collapse plot of more than four values per pixel int pointsPerPixel = (nValues - start) / w; if (pointsPerPixel < 4) { pointsPerPixel = 1; } // Draw graphs // Loop backwards over sequences because the first needs to be painted on top for (int i = nLists - 1; i >= 0; i--) { int x0 = leftMargin; int y0 = topMargin + h + 1; Sequence seq = seqs.get(i); if (seq.isPlotted && seq.size > 0) { // Paint twice, with white and with color for (int pass = 0; pass < 2; pass++) { g.setColor((pass == 0) ? Color.white : seq.color); int x1 = -1; long v1 = -1; for (int p = start; p < nValues; p += pointsPerPixel) { // Make sure we get the last value if (pointsPerPixel > 1 && p >= nValues - pointsPerPixel) { p = nValues - 1; } int x2 = (int) (w * (times.time(p) - (t1 - viewRangeMS)) / viewRangeMS); long v2 = seq.value(p); if (v2 >= vMin && v2 <= vMax) { int y2 = (int) (h * (v2 - vMin) / (vMax - vMin)); if (x1 >= 0 && v1 >= vMin && v1 <= vMax) { int y1 = (int) (h * (v1 - vMin) / (vMax - vMin)); if (y1 == y2) { // fillrect is much faster g.fillRect(x0 + x1, y0 - y1 - pass, x2 - x1, 1); } else { Graphics2D g2d = (Graphics2D) g; Stroke oldStroke = null; if (seq.transitionStroke != null) { oldStroke = g2d.getStroke(); g2d.setStroke(seq.transitionStroke); } g.drawLine(x0 + x1, y0 - y1 - pass, x0 + x2, y0 - y2 - pass); if (oldStroke != null) { g2d.setStroke(oldStroke); } } } } x1 = x2; v1 = v2; } } // Current value long v = seq.value(seq.size - 1); if (v >= vMin && v <= vMax) { if (bgIsLight) { g.setColor(seq.color); } else { g.setColor(fg); } x = r.x + r.width + 2; y = topMargin + h - (int) (h * (v - vMin) / (vMax - vMin)); // a small triangle/arrow g.fillPolygon(new int[] {x + 2, x + 6, x + 6}, new int[] {y, y + 3, y - 3}, 3); } g.setColor(fg); } } int[] valueStringSlots = new int[nLists]; for (int i = 0; i < nLists; i++) valueStringSlots[i] = -1; for (int i = 0; i < nLists; i++) { Sequence seq = seqs.get(i); if (seq.isPlotted && seq.size > 0) { // Draw current value // TODO: collapse values if pointsPerPixel >= 4 long v = seq.value(seq.size - 1); if (v >= vMin && v <= vMax) { x = r.x + r.width + 2; y = topMargin + h - (int) (h * (v - vMin) / (vMax - vMin)); int y2 = getValueStringSlot(valueStringSlots, y, 2 * 10, i); g.setFont(smallFont); if (bgIsLight) { g.setColor(seq.color); } else { g.setColor(fg); } String curValue = getFormattedValue(v, true); if (unit == Unit.PERCENT) { curValue += "%"; } int valWidth = fm.stringWidth(curValue); String legend = (displayLegend ? seq.name : ""); int legendWidth = fm.stringWidth(legend); if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) { // Wait for next repaint return; } g.drawString(legend, x + 17, Math.min(topMargin + h, y2 + 3 - 10)); g.drawString(curValue, x + 17, Math.min(topMargin + h + 10, y2 + 3)); // Maybe draw a short line to value if (y2 > y + 3) { g.drawLine(x + 9, y + 2, x + 14, y2); } else if (y2 < y - 3) { g.drawLine(x + 9, y - 2, x + 14, y2); } } g.setFont(oldFont); g.setColor(fg); } } g.setColor(oldColor); }
/** Standard Thread.run(). */ public /*final*/ void run() { if (Thread.currentThread() != this) { throw new WorkerThreadException( "not run() by the owning thread. Current thread:" + Thread.currentThread() + "---owning thread:" + this); } try { if (aruntime.debug && aruntime.isDebugEnabledAt(ARuntime.Debug_THREAD)) aruntime.println(ARuntime.Debug_THREAD, this, "THREAD STARTS"); for (; ; ) { // Note: // getTask() and recycle() must happen atomically because // during the time after this thread cannot get more tasks // from runtime.getTask() and before it goes to recycle() to // return workforce, another thread may produce a new task in // the ready queue (without this thread knowing it) and that // thread goes to the waiting state. Due to this racing, // the simulation could be stalled as no thread is actively // running to execute the new task in the ready queue. synchronized (aruntime) { if (mainContext == null || mainContext == DUMMY_CONTEXT) { // grab a task from worker pool nextTask = GETTING_TASK; // XXX: temporary for debug nextTask = aruntime.getTask(mainContext == null); if (nextTask != null) { // so null wont override DUMMY_CONTEXT mainContext = nextTask; nextTask = null; } else { setState(State_RECYCLING); sleepOn = this; aruntime.recycle(this); // return workforce in recycle() } } } if (state == State_RECYCLING) { setState(State_INACTIVE); // BOOKMARK1: // At this point, other threads may assign a new task // to this thread and start this thread, so check if // mainContext is being assigned within // the following synchronized claus synchronized (this) { if (mainContext == DUMMY_CONTEXT) mainContext = null; if (mainContext == null) { __sleepOn(this, State_INACTIVE, State_INACTIVE); continue; } else sleepOn = null; } } if (runtime.resetting) { throw new WorkerThreadInterruptedException(); } else if (aruntime.isSuspend()) { // go into sleep if runtime is suspended synchronized (this) { __sleepOn(this, State_PREACTIVE, State_ACTIVE); } } if (mainContext.threadGroup != null) { if (mainContext instanceof TaskNotify) { // mainContext is TaskNotify: // the object to be notified on is in "data" synchronized (mainContext.data) { if (aruntime.debug && aruntime.isDebugEnabledAt(ARuntime.Debug_THREAD)) aruntime.println( ARuntime.Debug_THREAD, this, "EXECUTING notify:" + mainContext.data + "," + System.currentTimeMillis()); mainContext.data.notify(); aruntime.nthreadsWaiting--; } mainContext = null; // workforce transfered to the waked up thread continue; } else if (getThreadGroup() != mainContext.threadGroup) { aruntime.immediatelyStart(mainContext); mainContext = null; // workforce transfered to new thread continue; } } if (aruntime.debug && aruntime.isDebugEnabledAt(ARuntime.Debug_THREAD)) aruntime.println(ARuntime.Debug_THREAD, this, "EXECUTING:" + mainContext); setState(State_ACTIVE); // runtime.runCheck(this); String method_ = "process()"; currentContext = mainContext; returnPort = currentContext.returnPort; // from server port, new context try { mainContext.execute(this); } catch (NullPointerException e_) { if (runtime == null) return; e_.printStackTrace(); drcl.Debug.error(info()); } catch (Exception e_) { e_.printStackTrace(); drcl.Debug.error(info()); } catch (SendReceiveException e_) { e_.printStackTrace(); drcl.Debug.error(info()); } currentContext.port = null; currentContext.data = null; finishing(); mainContext = DUMMY_CONTEXT; // to maintain the ownership of workforce if (!RECYCLING) { aruntime.remove(this); break; } if (nextTask != null) { // error checking if (mainContext != null && mainContext != DUMMY_CONTEXT) drcl.Debug.systemFatalError("task assigned to occupied thread:" + this); mainContext = nextTask; nextTask = null; } } // for(;;) drcl.Debug.systemFatalError("Unexpected finish at " + this); } catch (WorkerThreadInterruptedException e_) { // if (!runtime.resetting) { // e_.printStackTrace(); // drcl.Debug.systemFatalError( // "AWorkerThread terminates abnormally, " + this // + "\nManager: " + runtime.diag()); // } // Will releaseAllLocks()/cancelAllWaits() clean up the lock // structure in components? // Not if the thread comes across multiple components... if (mainContext != null && mainContext.port != null) releaseAllLocks(mainContext.port.host); aruntime.remove(this); } catch (NullPointerException e_) { if (runtime != null) { e_.printStackTrace(); drcl.Debug.error(info()); } } runtime = null; // become an orphan aruntime = null; }
/* * Main task. Executed in background thread. */ @Override public String doInBackground() throws Exception { if (myTaskName.equals("Get DownloadFile Info")) { if (!isCancelled()) { getFileInfo(); } } if (myTaskName.equals("Download Remote")) { if (!isCancelled()) { long theFileSize = getFileSize(); if (theFileSize != -1) { sendDownloadMessage(); int thePollInterval = Integer.parseInt(myProperties.getProperty("POLLINTERVAL")); long theCurrentTime = System.currentTimeMillis(); while (getStatus(theFileSize) && !isCancelled()) { if ((System.currentTimeMillis() - theCurrentTime) < thePollInterval * 1000) { Thread.sleep(thePollInterval * 1000 - System.currentTimeMillis() + theCurrentTime); } theCurrentTime = System.currentTimeMillis(); } } } } if (myTaskName.equals("Download Local Base")) { if (!isCancelled()) { downloadFileFromBase(); } } if (myTaskName.equals("Clean Remote Temp")) { if (!isCancelled()) { CleanRemoteTempDir(); } } if (myTaskName.equals("Clean Remote Base")) { if (!isCancelled()) { CleanRemoteBaseDir(); } } if (myTaskName.equals("Split Remote")) { if (!isCancelled()) { splitFileFromBase(); } } if (myTaskName.equals("Email Remote")) { if (!isCancelled()) { emailFileFromBase(); } } if (myTaskName.equals("Join Local")) { if (!isCancelled()) { joinFileFromLocalBase(); } } /** if(!isCancelled()) { CleanRemoteTempDir(); }* */ /** if(!isCancelled()) { getFileList(); }* */ /** if(!isCancelled()) { verifyAndSync(); }* */ return "Done"; }