| I l@ve RuBoard |
11.4 The PyMailGui Email ClientAs a finale for this chapter's email tools coverage, this section presents PyMailGui -- a Python/Tkinter program that implements a client-side email processing user interface. It is presented both as an instance of Python Internet scripting and as an example that ties together other tools we've already seen, such as threads and Tkinter GUIs. Like the pymail program we wrote earlier, PyMailGui runs entirely on your local computer. Your email is fetched from and sent to remote mail servers over sockets, but the program and its user interface run locally. Because of that, PyMailGui is called an email client : it employs Python's client-side tools to talk to mail servers from the local machine. In fact, in some ways, PyMailGui builds on top of pymail to add a GUI. Unlike pymail, though, PyMailGui is a fairly full-featured user interface: email operations are performed with point-and-click operations. 11.4.1 Why PyMailGui?Like many examples presented in this text, PyMailGui is also a practical, useful program. In fact, I run it on all kinds of machines to check my email while traveling around the world teaching Python classes (it's another workaround for Telnet-challenged ISPs). Although PyMailGui won't put Microsoft Outlook out of business anytime soon, I like it for two reasons:
It's also worth mentioning that PyMailGui achieves this portability and scriptability, and implements a full-featured email interface along the way, in roughly 500 lines of program code. It doesn't have as many bells and whistles as commercial products, but the fact that it gets as close as it does in so few lines of code is a testament to the power of both the Python language and its libraries. 11.4.2 Running PyMailGuiOf course, to script PyMailGui on your own, you'll need to be able to run it. PyMailGui only requires a computer with some sort of Internet connectivity (a PC with a dialup account and modem will do) and an installed Python with the Tkinter extension enabled. The Windows port of Python has this capability, so Windows PC users should be able to run this program immediately by clicking its icon (the Windows port self-installer is on this book's CD (see http://examples.oreilly.com/python2) and also at http://www.python.org). You'll also want to change the file mailconfig.py in the email examples directory to reflect your account's parameters; more on this as we interact with the system. 11.4.3 Presentation StrategyPyMailGui is easily one of the longest programs in this book (its main script is some 500 lines long, counting blank lines and comments), but it doesn't introduce many library interfaces that we haven't already seen in this book. For instance:
We're also going to reuse the TextEditor object we wrote in Chapter 9, to view and compose messages, the simple pymail module's tools we wrote earlier in this chapter to load and delete mail from the server, and the mailconfig module of this chapter to fetch email parameters. PyMailGui is largely an exercise in combining existing tools. On the other hand, because this program is so long, we won't exhaustively document all of its code. Instead, we'll begin by describing how PyMailGui works from an end-user's perspective. After that, we'll list the system's new source code modules without any additional comments, for further study. Like most longer case studies in this book, this section assumes that you already know enough Python to make sense of the code on your own. If you've been reading this book linearly, you should also know enough about Tkinter, threads, and mail interfaces to understand the library tools applied here. If you get stuck, you may wish to brush-up on the presentation of these topics earlier in the book. 11.4.4 Interacting with PyMailGuiTo make this case study easier to understand, let's begin by seeing what PyMailGui actually does -- its user interaction and email processing functionality -- before jumping into the Python code that implements that behavior. As you read this part, feel free to jump ahead to the code listings that appear after the screen shots, but be sure to read this section, too; this is where I will explain all the subtleties of PyMailGui's design. After this section, you are invited to study the system's Python source code listings on your own for a better and more complete explanation than can be crafted in English. <IP_ADDRESS> Getting startedPyMailGui is a Python/Tkinter program, run by executing its top-level script file, PyMailGui.py. Like other Python programs, PyMailGui can be started from the system command line, by clicking on its filename icon in a file explorer interface, or by pressing its button in the PyDemos or PyGadgets launcher bars. However it is started, the first window PyMailGui presents is shown in Figure 11-10. Figure 11-10. PyMailGui main window startThis is the PyMailGui main window -- every operation starts here. It consists of:
In normal operation, users load their email, select an email from the list area by clicking on it, and press a button at the bottom to process it. No mail messages are shown initially; we need to first load them, as we'll see in a moment. Before we do, though, let's press the blue help bar at the top to see what sort of help is available; Figure 11-11 shows the help window pop-up that appears. Figure 11-11. PyMailGui help pop-upThe main part of this window is simply a block of text in a scrolled-text widget, along with two buttons at the bottom. The entire help text is coded as a single triple-quoted string in the Python program. We could get more fancy and spawn a web browser to view HTML-formatted help, but simple text does the job here.[11] The Cancel button makes this nonmodal (i.e., nonblocking) window go away; more interestingly, the Source button pops up a viewer window with the source code of PyMailGui's main script, as shown in Figure 11-12.
Figure 11-12. PyMailGui source code viewer windowNot every program shows you its source code, but PyMailGui follows Python's open source motif. Politics aside, the main point of interest here is that this source viewer window is the same as PyMailGui's email viewer window. All the information here comes from PyMailGui internally; but this same window is used to display and edit mail shipped across the Net, so let's look at its format here:
For instance, if we pick the Tools menu of the text portion of this window, and select its Info entry, we get the standard PyEdit TextEditor object's file text statistics box -- the exact same pop-up we'd get in the standalone PyEdit text editor, and the PyView image view programs we wrote in Chapter 9 (see Figure 11-13). In fact, this is the third reuse of TextEditor in this book: PyEdit, PyView, and now PyMaiGui all present the same text editing interface to users, simply because they all use the same TextEditor object. For purposes of showing source code, we could also simply spawn the PyEdit program with the source file's name as a command-line argument (see PyEdit earlier in the text for more details). PyMailGui attaches an instance instead. Figure 11-13. PyMailGui attached TextEditor info boxTo display email, PyMailGui inserts its text into an attached TextEditor object; to compose mail, PyMailGui presents a TextEditor and later fetches all its text out to ship over the Net. Besides the obvious simplification here, this code reuse also makes it easy to pick up improvements and fixes -- any changes in the TextEditor object are automatically inherited by PyMailGui, PyView, and PyEdit. <IP_ADDRESS> Loading mailNow, let's go back to the PyMailGui main window, and click the Load button to retrieve incoming email over the POP protocol. Like pymail, PyMailGui's load function gets account parameters from the mailconfig module listed in Example 11-15, so be sure to change this file to reflect your email account parameters (i.e., server names and usernames) if you wish to use PyMailGui to read your own email. The account password parameter merits a few extra words. In PyMailGui, it may come from one of two places:
Figure 11-1 shows the password input prompt you get if you haven't stored your password in a local file. Note that the password you type is not shown -- a show='*' option for the Entry field used in this pop-up tells Tkinter to echo typed characters as stars (this option is similar in spirit to both the getpass console input module we met earlier in this chapter, and an HTML type=password option we'll meet in a later chapter). Once entered, the password lives only in memory on your machine; PyMailGui itself doesn't store it anywhere in a permanent way. Also notice that the local file password option requires you to store your password unencrypted in a file on the local client computer. This is convenient (you don't need to retype a password every time you check email), but not generally a good idea on a machine you share with others; leave this setting blank in mailconfig if you prefer to always enter your password in a pop-up. Figure 11-14. PyMailGui password input dialogOnce PyMailGui fetches your mail parameters and somehow obtains your password, it will next attempt to pull down all your incoming email from your POP server. PyMailGui reuses the load-mail tools in the pymail module listed in Example 11-18, which in turn uses Python's standard poplib module to retrieve your email. <IP_ADDRESS> Threading long-running email transfersUltimately, though, the load function must download your email over a socket. If you get as much email as I do, this can take awhile. Rather than blocking the GUI while the load is in progress, PyMailGui spawns a thread to do the mail download operation in parallel with the rest of the program. The main program continues responding to window events (e.g., redrawing the display after another window has been moved over it) while your email is being downloaded. To let you know that a download is in progress in the background, PyMailGui pops up the wait dialog box shown in Figure 11-15. Figure 11-15. PyMailGui load mail wait box (thread running)This dialog grabs focus and thus effectively disables the rest of the GUI's buttons while a download is in progress. It stays up for the duration of the download, and goes away automatically when the download is complete. Similar wait pop-ups appear during other long-running socket operations (email send and delete operations), but the GUI itself stays alive because the operations run in a thread. On systems without threads, PyMailGui instead goes into a blocked state during such long-running operations (it stubs out the thread spawn operation to perform a simple function call). Because the GUI is essentially dead without threads, covering and uncovering the GUI during a mail load on such platforms will erase or otherwise distort its contents.[12] Threads are enabled by default on most platforms that Python runs on (including Windows), so you probably won't see such oddness on your machine.
One note here: as mentioned when we met the FTP GUIs earlier in this chapter, on MS Windows, only the thread that creates windows can process them. Because of that, PyMailGui takes care to not do anything related to the user interface within threads that load, send, or delete email. Instead, the main program continues responding to user interface events and updates, and watches for a global "I'm finished" flag to be set by the email transfer threads. Recall that threads share global (i.e., module) memory; since there is at most only two threads active in PyMailGui at once -- the main program and an email transfer thread -- a single global flag is all the cross-thread communication mechanism we need. <IP_ADDRESS> Load server interfaceBecause the load operation is really a socket operation, PyMailGui will automatically connect to your email server using whatever connectivity exists on the machine on which it is run. For instance, if you connect to the Net over a modem, and you're not already connected, Windows automatically pops up the standard connection dialog; Figure 11-16 shows the one I get on my laptop. If PyMailGui runs on a machine with a dedicated Internet link, it uses that instead. Figure 11-16. PyMailGui connection dialog (Windows)After PyMailGui finishes loading your email, it populates the main window's list box with all of the messages on your email server, and scrolls to the most recently received. Figure 11-17 shows what the main windows looks like on my machine. Figure 11-17. PyMailGui main window after loadTechnically, the Load button fetches all your mail the first time it is pressed, but fetches only newly arrived email on later presses. PyMailGui keeps track of the last email loaded, and requests only higher email numbers on later loads. Already-loaded mail is kept in memory, in a Python list, to avoid the cost of downloading it again. Like the simple pymail command-line interface shown earlier, PyMailGui does not delete email from your server when it is loaded; if you really want to not see an email on a later load, you must explicitly delete it (more on this later). Like most GUIs in this book, the main window can be resized; Figure 11-18 shows what it looks like when stretched to reveal more email details. Entries in the main list show just enough to give the user an idea of what the message contains -- each entry gives the concatenation of portions of the message's "Subject:", "From:", and "Date:" header lines, separated by | characters, and prefixed with the message's POP number (e.g., there are 91 emails in this list). The columns don't always line up neatly (some headers are shorter than others), but it's enough to hint at the message's contents. Figure 11-18. PyMailGui main window resizedAs we've seen, much magic happens when downloading email -- the client (the machine on which PyMailGui runs) must connect to the server (your email account machine) over a socket, and transfer bytes over arbitrary Internet links. If things go wrong, PyMailGui pops up standard error dialog boxes to let you know what happened. For example, if PyMailGui cannot establish a connection at all, you'll get a window like that shown in Figure 11-19. Figure 11-19. PyMailGui connection error boxThe details displayed here are just the Python exception type and exception data. If you typed an incorrect username or password for your account (in the mailconfig module or in the password pop-up), you'll see the message in Figure 11-20. Figure 11-20. PyMailGui invalid password error boxThis box shows the exception raised by the Python poplib module. If PyMailGui cannot contact your server (e.g., it's down, or you listed its name wrong in mailconfig), you'll get the pop-up shown in Figure 11-21. Figure 11-21. PyMailGui invalid or down server error box<IP_ADDRESS> Sending emailOnce we've loaded email, we can process our messages with buttons on the main window. We can, however, send new emails at any time, even before a load. Pressing the Write button on the main window generates a mail composition window; one has been captured in Figure 11-22. Figure 11-22. PyMailGui write mail compose windowThis window is just like the help source code viewer we saw a moment ago -- it has fields for entering header line details, and an attached TextEditor object for writing the body of the new email. For write operations, PyMailGui automatically fills the "From" line and inserts a signature text line (" -- Mark..."), from your mailconfig module settings. You can change these to any text you like, but the defaults are filled in automatically from your mailconfig. There is also a new "Send" button here: when pressed, the text you typed into the the body of this window is mailed to the addresses you typed into the "To" and "Cc" lines, using Python's smtplib module. PyMailGui adds the header fields you type as mail header lines in the sent message. To send to more than one address, separate them with a ";" in the "To" and "Cc" lines (we'll see an example of this in a moment). In this mail, I fill in the "To" header with my own email address, to send the message to myself for illustration purposes. As we've seen, smtplib ultimately sends bytes to a server over a socket. Since this can be a long-running operation, PyMailGui delegates this operation to a spawned thread, too. While the send thread runs, the wait window in Figure 11-23 appears, and the entire GUI stays alive; redraw and move events are handled in the main program thread, while the send thread talks to the SMTP server. Figure 11-23. PyMailGui send mail wait box (thread running)You'll get an error pop-up if Python cannot send a message to any of the target recipients, for any reason. If you don't get an error pop-up, everything worked correctly, and your mail will show up in the recipients' mailboxes on their email servers. Since I sent the message above to myself, it shows up in mine the next time I press the main window's Load button, as we see in Figure 11-24. Figure 11-24. PyMailGui main window after sends, loadIf you look back to the last main window shot, you'll notice that there are only two new emails now -- numbers 92 (from Python-Help) and 93 (the one I just wrote); PyMailGui is smart enough to download only the two new massages, and tack them onto the end of the loaded email list. <IP_ADDRESS> Viewing emailNow, let's view the mail message that was sent and received. PyMailGui lets us view email in formatted or raw modes. First, highlight (single-click) the mail you want to see in the main window, and press the View button. A formatted mail viewer window like that shown in Figure 11-25 appears. Figure 11-25. PyMailGui view incoming mail windowThis is the exact same window we saw displaying source code earlier, only now all the information is filled in by extracting bits of the selected email message. Python's rfc822 module is used to parse out header lines from the raw text of the email message; their text is placed into the fields in the top right of the window. After headers are parsed, the message's body text is left behind (in a StringIO file-like string wrapper), and is read and stuffed into a new TextEditor object for display (the white part in the middle of the window). Besides the nicely formatted view window, PyMailGui also lets us see the raw text of a mail message. Double-click on a message's entry in the main window's list to bring up a simple unformatted display of the mail's text. The raw version of the mail I sent to myself is shown in Figure 11-26. Figure 11-26. PyMailGui raw mail text view windowThis raw text display can be useful to see special mail headers not shown in the formatted view. For instance, the optional "X-Mailer:" header in the raw text display identifies the program that transmitted a message; PyMailGui adds it automatically, along with standard headers like "From:" and "To:". Other headers are added as the mail is transmitted: the "Received:" headers name machines that the message was routed through on its way to our email server. And really, the raw text form is all there is to an email message -- it's what is transferred from machine to machine when mail is sent. The nicely formatted display simply parses out pieces of the mail's raw text with standard Python tools and places them in associated fields of the display of Figure 11-25. <IP_ADDRESS> Email replies and forwardsBesides allowing reading and writing email, PyMailGui also lets users forward and reply to incoming email sent from others. To reply to an email, select its entry in the main window's list and click the Reply button. If I reply to the mail I just sent to myself (arguably narcissistic, but demonstrative), the mail composition window shown in Figure 11-27 appears. Figure 11-27. PyMailGui reply compose windowThis window is identical in format to the one we saw for the "Write" operation, except that PyMailGui fills in some parts automatically:
Luckily, all of this is much easier than it may sound. Python's standard rfc822 module is used to extract all the original message's header lines, and a single string.replace call does the work of adding the > quotes to the original message body. I simply type what I wish to say in reply (the initial paragraph in the mail's text area), and press the Send button to route the reply message to the mailbox on my mail server again. Physically sending the reply works the same as sending a brand new message -- the mail is routed to your SMTP server in a spawned send mail thread, and the send mail wait pop-up appears. Forwarding a message is similar to replying: select the message in the main window, press the "Fwd" button, and fill in the fields and text area of the popped-up composition window. Figure 11-28 shows the window created to forward the mail we originally wrote and received. Figure 11-28. PyMailGui forward compose windowMuch like replies, "From" is filled from mailconfig, the original text is automatically quoted in the message body again, and the subject line is preset to the original message's subject prepended with the string "Fwd:". I have to fill in the "To" line manually, though, because this is not a direct reply (it doesn't necessarily go back to the original sender). Notice that I'm forwarding this message to two different addresses; multiple recipient addresses are separated with a ";" character in "To" and "Cc" header fields. The Send button in this window fires the forward message off to all addresses listed in "To" and "Cc". Figure 11-29. PyMailGui mail list after sends and loadOkay, I've now written a new message, and replied to and forwarded it. The reply and forward were sent to my email address, too; if we press the main window's Load button again, the reply and forward messages should show up in the main window's list. In Figure 11-29, they appear as messages 94 and 95. Keep in mind that PyMailGui runs on the local computer, but the messages you see in the main window's list actually live in a mailbox on your email server machine. Every time we press Load, PyMailGui downloads but does not delete newly arrived email from the server to your computer. The three messages we just wrote (93-95) will also appear in any other email program you use on your account (e.g., in Outlook). PyMailGui does not delete messages as they are downloaded, but simply stores them in your computer's memory for processing. If we now select message 95 and press View, we see the forward message we sent, as in Figure 11-30. Really, this message went from my machine to a remote email server, and was downloaded from there into a Python list from which it is displayed. Figure 11-30. PyMailGui view forwarded mailFigure 11-31 shows what the forward message's raw text looks like; again, double-click on a main window's entry to display this form. The formatted display in Figure 11-30 simply extracts bits and pieces out of the text shown in the raw display form. Figure 11-31. PyMailGui view forwarded mail, raw<IP_ADDRESS> Saving and deleting emailSo far, we've covered everything except two of the main window's processing buttons and the All checkbox. PyMailGui lets us save mail messages in local text files, and delete messages from the server permanently, such that we won't see them the next time we access our account. Moreover, we can save and delete a single mail at a time, or all mails displayed in the main windows list:
Delete operations are kicked off the same way, but press the Del button instead. In typical operation, I eventually delete email I'm not interested in, and save and delete emails that are important. Save operations write the raw text of one or more emails to a local text file you pick in the pop-up dialog shown in Figure 11-32. Figure 11-32. PyMailGui save mail dialogTechnically, saves always append raw message text to the chosen file; the file is opened in 'a' mode, which creates the file if needed, and writes at its end.  Delete operations can also be applied to one or all messages. Unlike other operations, though, delete requests are simply queued up for later action. Messages are actually deleted from your mail server only as PyMailGui is exiting. For instance, if we've selected some messages for deletion and press the main window's Quit button, a standard verification dialog appears (Figure 11-33). Figure 11-33. PyMailGui quit verificationIf we then verify the quit request, a second dialog appears (Figure 11-34), asking us to verify deletion of the queued up messages. If we press No here, no deletes happen, and PyMailGui silently exits. If we select Yes, PyMailGui spawns one last thread to send deletion requests to the email server for all the emails selected for deletion during the session. Another wait-state pop-up appears while the delete thread is running; when that thread is finished, PyMailGui exits as well. Figure 11-34. PyMailGui delete verification on quitBy default and design, no mail is ever removed: you will see the same messages the next time PyMailGui runs. It deletes mail from your server only when you ask it to, deletes messages only on exit, and then only if verified in the last pop-up shown (this is your last chance to prevent permanent mail removal). <IP_ADDRESS> POP message numbersThis may seem a roundabout way to delete mail, but it accommodates a property of the POP interface. POP assigns each message a sequential number, starting from 1, and these numbers are passed to the server to fetch and delete messages. It's okay if new mail arrives while we're displaying the result of a prior download -- the new mail is assigned higher numbers, beyond what is displayed on the client. But if we delete a message in the middle of a mailbox, the numbers of all messages after the one deleted change (they are decremented by one). That means that some message numbers may be no longer valid if deletions are made while viewing previously loaded email (deleting by some number N may really delete message N+1!). PyMailGui could adjust all the displayed numbers to work around this. To keep things simple, though, it postpones deletions instead. Notice that if you run multiple instances of PyMailGui at once, you shouldn't delete in one and then another because message numbers may become confused. You also may not be happy with the results of running something like Outlook at the same time as a PyMailGui session, but the net effect of such a combination depends on how another mail client handles deletions. In principle, PyMailGui could be extended to prevent other instances from running at the same time, but we leave that as an exercise. <IP_ADDRESS> Windows and status messagesBefore we close this section, I want to point out that PyMailGui is really meant to be a multiple-window interface -- something not made obvious by the earlier screen shots. For example, Figure 11-35 shows PyMailGui with a main list box, help, and three mail view windows. All these windows are nonmodal; that is, they are all active and independent, and do not block other windows from being selected. This interface all looks slightly different on Linux, but has the same functionality. Figure 11-35. PyMailGui multiple windows and text editorsIn general, you can have any number of mail view or compose windows up at once, and cut and paste between them. This matters, because PyMailGui must take care to make sure that each window has a distinct text editor object. If the text editor object was a global, or used globals internally, you'd likely see the same text in each window (and the send operations might wind up sending text from another window). To avoid this, PyMailGui creates and attaches a new TextEditor instance to each view and compose window it creates, and associates the new editor with the Send button's callback handler to make sure we get the right text. Finally, PyMailGui prints a variety of status messages as it runs, but you see them only if you launch the program from the system command line (e.g., a DOS box on Windows or an xterm on Linux), or by double-clicking on its filename icon (its main script is a .py, not a .pyw). On Windows, you won't see these message when it is started from another program, such as the PyDemos or PyGadgets launcher bar GUIs. These status messages print server information, show mail loading status, and trace the load, store, and delete threads that are spawned along the way. If you want PyMailGui to be more verbose, launch it from a command line and watch: C:\...\PP2E\Internet\Email>python PyMailGui.py load start Connecting... +OK Cubic Circle's v1.31 1998/05/13 POP3 ready <594100005a655e39@chevalier> ('+OK 5 messages (8470 octets)', ['1 709', '2 1136', '3 998', '4 2679', '5 2948'], 38) There are 5 mail messages in 8470 bytes Retrieving: 1 2 3 4 5 load exit thread exit caught send start Connecting to mail<EMAIL_ADDRESS>send exit thread exit caught You can also double-click on the PyMailGui.py filename in your file explorer GUI and monitor the popped-up DOS console box on Windows; Figure 11-36 captures this window in action. Figure 11-36. PyMailGui console status message windowPyMailGui status messages display the mail currently being downloaded (i.e., the "Retrieving:" lines are appended with a new mail number as each message is downloaded), and so give a more informative download status indicator than the wait pop-up window. 11.4.5 Implementing PyMailGuiLast but not least, we get to the code. There are really only two new modules here: one where the help text is stored and another that implements the system. In fact, PyMailGui gets a lot of mileage out of reusing modules we wrote earlier and won't repeat here: pymail for mail load and delete operations, mailconfig for mail parameters, the GUI section's TextEditor for displaying and editing mail message text, and so on. In addition, standard Python modules used here such as poplib, smtplib, and rfc822 hide most of the details of pushing bytes around the Net and extracting message components. Tkinter implements GUI components in a portable fashion. <IP_ADDRESS> Help text moduleThe net effect of all this reuse is that PyMailGui implements a fairly feature-rich email program in roughly 500 lines of code, plus one support module. Example 11-22 shows the support module -- used only to define the help text string, to avoid cluttering the main script file. Example 11-22. PP2E\Internet\Email\PyMailGuiHelp.py##################################################################### # PyMailGui help text string, in this seperate module only to avoid # distracting from executable code. As coded, we throw up this text # in a simple scrollable text box; in the future, we might instead # use an HTML file opened under a web browser (e.g., run a "netscape # help.html" or DOS "start help.html" command using os.system call ##################################################################### # must be narrow for Linux info box popups; # now uses scrolledtext with buttons instead; helptext = """ PyMail, version 1.0 February, 2000 Programming Python, 2nd Edition O'Reilly & Associates Click main window buttons to process email: - Load:\t fetch all (or newly arrived) POP mail from server - View:\t display selected message nicely formatted - Save:\t write selected (or all) emails to a chosen file - Del:\t mark selected (or all) email to be deleted on exit - Write:\t compose a new email message, send it by SMTP - Reply:\t compose a reply to selected email, send it by SMTP - Fwd:\t compose a forward of selected email, send by SMTP - Quit:\t exit PyMail, delete any marked emails from server Click an email in the main window's listbox to select it. Click the "All" checkbox to apply Save or Del buttons to all retrieved emails in the list. Double-click on an email in the main window's listbox to view the mail's raw text, including mail headers not shown by the View button. Mail is removed from POP servers on exit only, and only mails marked for deletion with the Del button are removed, if and only if you verify the deletion in a confirmation popup. Change the mailconfig.py module file on your own machine to reflect your email server names, user name, email address, and optional mail signature line added to all composed mails. Miscellaneous hints: - Passwords are requested if needed, and not stored by PyMail. - You may put your password in a file named in mailconfig.py. - Use ';' between multiple addresses in "To" and "Cc" headers. - Reply and Fwd automatically quote the original mail text. - Save pops up a dialog for selecting a file to hold saved mails. - Load only fetches newly-arrived email after the first load. This client-side program currently requires Python and Tkinter. It uses Python threads, if installed, to avoid blocking the GUI. Sending and loading email requires an Internet connection. """ if __name__ == '__main__': print helptext # to stdout if run alone raw_input('Press Enter key') # pause in DOS console popups <IP_ADDRESS> Main moduleAnd finally, here is the main PyMailGui script -- the file run to start the system (see Example 11-23). I've already told what it does and why, so studying this listing's code and its comments for a deeper look is left as a suggested exercise. Python is so close to pseudocode already, that additional narrative here would probably be redundant. Although I use this example on a daily basis as is, it is also prime for extension. For instance:
And so on; because this software is open source, it is also necessarily open-ended. Suggested exercises in this category are delegated to your imagination. Example 11-23. PP2E\Internet\Email\PyMailGui.py###################################################### # PyMailGui 1.0 - A Python/Tkinter email client. # Adds a Tkinter-based GUI interface to the pymail # script's functionality. Works for POP/SMTP based # email accounts using sockets on the machine on # which this script is run. Uses threads if # installed to run loads, sends, and deletes with # no blocking; threads are standard on Windows. # GUI updates done in main thread only (Windows). # Reuses and attaches TextEditor class object. # Run from command-line to see status messages. # See use notes in help text in PyMailGuiHelp.py. # To do: support attachments, shade deletions. ###################################################### # get services import pymail, mailconfig import rfc822, StringIO, string, sys from Tkinter import * from tkFileDialog import asksaveasfilename, SaveAs from tkMessageBox import showinfo, showerror, askyesno from PP2E.Gui.TextEditor.textEditor import TextEditorComponentMinimal # run if no threads try: # raise ImportError to import thread # run with gui blocking except ImportError: # no wait popups appear class fakeThread: def start_new_thread(self, func, args): apply(func, args) thread = fakeThread() # init global/module vars msgList = [] # list of retrieved emails text toDelete = [] # msgnums to be deleted on exit listBox = None # main window's scrolled msg list rootWin = None # the main window of this program allModeVar = None # for All mode checkbox value threadExitVar = 0 # used to signal child thread exit debugme = 0 # enable extra status messages mailserver = mailconfig.popservername # where to read pop email from mailuser = mailconfig.popusername # smtp server in mailconfig too mailpswd = None # pop passwd via file or popup here #mailfile = mailconfig.savemailfile # from a file select dialog here def fillIndex(msgList): # fill all of main listbox listBox.delete(0, END) count = 1 for msg in msgList: hdrs = rfc822.Message(StringIO.StringIO(msg)) msginfo = '%02d' % count for key in ('Subject', 'From', 'Date'): if hdrs.has_key(key): msginfo = msginfo + ' | ' + hdrs[key][:30] listBox.insert(END, msginfo) count = count+1 listBox.see(END) # show most recent mail=last line def selectedMsg(): # get msg selected in main listbox # print listBox.curselection() if listBox.curselection() == (): return 0 # empty tuple:no selection else: # else zero-based index return eval(listBox.curselection()[0]) + 1 # in a 1-item tuple of str def waitForThreadExit(win): import time global threadExitVar # in main thread, watch shared global var delay = 0.0 # 0.0=no sleep needed on Win98 (but hogs cpu) while not threadExitVar: win.update() # dispatch any new GUI events during wait time.sleep(delay) # if needed, sleep so other thread can run threadExitVar = 0 # at most one child thread active at once def busyInfoBoxWait(message): # popup wait message box, wait for a thread exit # main gui event thread stays alive during wait # as coded returns only after thread has finished # popup.wait_variable(threadExitVar) may work too popup = Toplevel() popup.title('PyMail Wait') popup.protocol('WM_DELETE_WINDOW', lambda:0) # ignore deletes label = Label(popup, text=message+'...') label.config(height=10, width=40, cursor='watch') # busy cursor label.pack() popup.focus_set() # grab application popup.grab_set() # wait for thread exit waitForThreadExit(popup) # gui alive during wait print 'thread exit caught' popup.destroy() def loadMailThread(): # load mail while main thread handles gui events global msgList, errInfo, threadExitVar print 'load start' errInfo = '' try: nextnum = len(msgList) + 1 newmail = pymail.loadmessages(mailserver, mailuser, mailpswd, nextnum) msgList = msgList + newmail except: exc_type, exc_value = sys.exc_info()[:2] # thread exc errInfo = '\n' + str(exc_type) + '\n' + str(exc_value) print 'load exit' threadExitVar = 1 # signal main thread def onLoadMail(): # load all (or new) pop email getpassword() thread.start_new_thread(loadMailThread, ()) busyInfoBoxWait('Retrieving mail') if errInfo: global mailpswd # zap pswd so can reinput mailpswd = None showerror('PyMail', 'Error loading mail\n' + errInfo) fillIndex(msgList) def onViewRawMail(): # view selected message - raw mail text with header lines msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') else: text = msgList[msgnum-1] # put in ScrolledText from ScrolledText import ScrolledText window = Toplevel() window.title('PyMail raw message viewer #' + str(msgnum)) browser = ScrolledText(window) browser.insert('0.0', text) browser.pack(expand=YES, fill=BOTH) def onViewFormatMail(): # view selected message - popup formatted display msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') else: mailtext = msgList[msgnum-1] # put in a TextEditor form textfile = StringIO.StringIO(mailtext) headers = rfc822.Message(textfile) # strips header lines bodytext = textfile.read() # rest is message body editmail('View #%d' % msgnum, headers.get('From', '?'), headers.get('To', '?'), headers.get('Subject', '?'), bodytext, headers.get('Cc', '?')) # use objects that retain prior directory for the next # select, instead of simple asksaveasfilename() dialog saveOneDialog = saveAllDialog = None def myasksaveasfilename_one(): global saveOneDialog if not saveOneDialog: saveOneDialog = SaveAs(title='PyMail Save File') return saveOneDialog.show() def myasksaveasfilename_all(): global saveAllDialog if not saveAllDialog: saveAllDialog = SaveAs(title='PyMail Save All File') return saveAllDialog.show() def onSaveMail(): # save selected message in file if allModeVar.get(): mailfile = myasksaveasfilename_all() if mailfile: try: # maybe this should be a thread for i in range(1, len(msgList)+1): pymail.savemessage(i, mailfile, msgList) except: showerror('PyMail', 'Error during save') else: msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') else: mailfile = myasksaveasfilename_one() if mailfile: try: pymail.savemessage(msgnum, mailfile, msgList) except: showerror('PyMail', 'Error during save') def onDeleteMail(): # mark selected message for deletion on exit global toDelete if allModeVar.get(): toDelete = range(1, len(msgList)+1) else: msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') elif msgnum not in toDelete: toDelete.append(msgnum) # fails if in list twice def sendMailThread(From, To, Cc, Subj, text): # send mail while main thread handles gui events global errInfo, threadExitVar import smtplib, time from mailconfig import smtpservername print 'send start' date = time.ctime(time.time()) Cchdr = (Cc and 'Cc: %s\n' % Cc) or '' hdrs = ('From: %s\nTo: %s\n%sDate: %s\nSubject: %s\n' % (From, To, Cchdr, date, Subj)) hdrs = hdrs + 'X-Mailer: PyMailGui Version 1.0 (Python)\n' Ccs = (Cc and string.split(Cc, ';')) or [] # some servers reject [''] Tos = string.split(To, ';') + Ccs # cc: hdr line, and To list Tos = map(string.strip, Tos) # some addrs can have ','s print 'Connecting to mail...', Tos # strip spaces around addrs errInfo = '' failed = {} # smtplib may raise except try: # or return failed Tos dict server = smtplib.SMTP(smtpservername) failed = server.sendmail(From, Tos, hdrs + text) server.quit() except: exc_type, exc_value = sys.exc_info()[:2] # thread exc excinfo = '\n' + str(exc_type) + '\n' + str(exc_value) errInfo = 'Error sending mail\n' + excinfo else: if failed: errInfo = 'Failed recipients:\n' + str(failed) print 'send exit' threadExitVar = 1 # signal main thread def sendMail(From, To, Cc, Subj, text): # send completed email thread.start_new_thread(sendMailThread, (From, To, Cc, Subj, text)) busyInfoBoxWait('Sending mail') if errInfo: showerror('PyMail', errInfo) def onWriteReplyFwdSend(window, editor, hdrs): # mail edit window send button press From, To, Cc, Subj = hdrs sendtext = editor.getAllText() sendMail(From.get(), To.get(), Cc.get(), Subj.get(), sendtext) if not errInfo: window.destroy() # else keep to retry or save def editmail(mode, From, To='', Subj='', origtext='', Cc=''): # create a new mail edit/view window win = Toplevel() win.title('PyMail - '+ mode) win.iconname('PyMail') viewOnly = (mode[:4] == 'View') # header entry fields frm = Frame(win); frm.pack( side=TOP, fill=X) lfrm = Frame(frm); lfrm.pack(side=LEFT, expand=NO, fill=BOTH) mfrm = Frame(frm); mfrm.pack(side=LEFT, expand=NO, fill=NONE) rfrm = Frame(frm); rfrm.pack(side=RIGHT, expand=YES, fill=BOTH) hdrs = [] for (label, start) in [('From:', From), ('To:', To), # order matters on send ('Cc:', Cc), ('Subj:', Subj)]: lab = Label(mfrm, text=label, justify=LEFT) ent = Entry(rfrm) lab.pack(side=TOP, expand=YES, fill=X) ent.pack(side=TOP, expand=YES, fill=X) ent.insert('0', start) hdrs.append(ent) # send, cancel buttons (need new editor) editor = TextEditorComponentMinimal(win) sendit = (lambda w=win, e=editor, h=hdrs: onWriteReplyFwdSend(w, e, h)) for (label, callback) in [('Cancel', win.destroy), ('Send', sendit)]: if not (viewOnly and label == 'Send'): b = Button(lfrm, text=label, command=callback) b.config(bg='beige', relief=RIDGE, bd=2) b.pack(side=TOP, expand=YES, fill=BOTH) # body text editor: pack last=clip first editor.pack(side=BOTTOM) # may be multiple editors if (not viewOnly) and mailconfig.mysignature: # add auto signature text? origtext = ('\n%s\n' % mailconfig.mysignature) + origtext editor.setAllText(origtext) def onWriteMail(): # compose new email editmail('Write', From=mailconfig.myaddress) def quoteorigtext(msgnum): origtext = msgList[msgnum-1] textfile = StringIO.StringIO(origtext) headers = rfc822.Message(textfile) # strips header lines bodytext = textfile.read() # rest is message body quoted = '\n-----Original Message-----\n' for hdr in ('From', 'To', 'Subject', 'Date'): quoted = quoted + ( '%s: %s\n' % (hdr, headers.get(hdr, '?')) ) quoted = quoted + '\n' + bodytext quoted = '\n' + string.replace(quoted, '\n', '\n> ') return quoted def onReplyMail(): # reply to selected email msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') else: text = quoteorigtext(msgnum) hdrs = rfc822.Message(StringIO.StringIO(msgList[msgnum-1])) toname, toaddr = hdrs.getaddr('From') if toname and ',' in toname: toname = '"%s"' % toname To = '%s <%s>' % (toname, toaddr) From = mailconfig.myaddress or ('%s <%s>' % hdrs.getaddr('To')) Subj = 'Re: ' + hdrs.get('Subject', '(no subject)') editmail('Reply', From, To, Subj, text) def onFwdMail(): # forward selected email msgnum = selectedMsg() if not (1 <= msgnum <= len(msgList)): showerror('PyMail', 'No message selected') else: text = quoteorigtext(msgnum) hdrs = rfc822.Message(StringIO.StringIO(msgList[msgnum-1])) From = mailconfig.myaddress or ('%s <%s>' % hdrs.getaddr('To')) Subj = 'Fwd: ' + hdrs.get('Subject', '(no subject)') editmail('Forward', From, '', Subj, text) def deleteMailThread(toDelete): # delete mail while main thread handles gui events global errInfo, threadExitVar print 'delete start' try: pymail.deletemessages(mailserver, mailuser, mailpswd, toDelete, 0) except: exc_type, exc_value = sys.exc_info()[:2] errInfo = '\n' + str(exc_type) + '\n' + str(exc_value) else: errInfo = '' print 'delete exit' threadExitVar = 1 # signal main thread def onQuitMail(): # exit mail tool, delete now if askyesno('PyMail', 'Verify Quit?'): if toDelete and askyesno('PyMail', 'Really Delete Mail?'): getpassword() thread.start_new_thread(deleteMailThread, (toDelete,)) busyInfoBoxWait('Deleting mail') if errInfo: showerror('PyMail', 'Error while deleting:\n' + errInfo) else: showinfo('PyMail', 'Mail deleted from server') rootWin.quit() def askpassword(prompt, app='PyMail'): # getpass.getpass uses stdin, not GUI win = Toplevel() # tkSimpleDialog.askstring echos input win.title(app + ' Prompt') Label(win, text=prompt).pack(side=LEFT) entvar = StringVar() ent = Entry(win, textvariable=entvar, show='*') ent.pack(side=RIGHT, expand=YES, fill=X) ent.bind('<Return>', lambda event, savewin=win: savewin.destroy()) ent.focus_set(); win.grab_set(); win.wait_window() win.update() return entvar.get() # ent widget is now gone def getpassword(): # unless known, set global pop password # from client-side file or popup dialog global mailpswd if mailpswd: return else: try: localfile = open(mailconfig.poppasswdfile) mailpswd = localfile.readline()[:-1] if debugme: print 'local file password', repr(mailpswd) except: prompt = 'Password for %s on %s?' % (mailuser, mailserver) mailpswd = askpassword(prompt) if debugme: print 'user input password', repr(mailpswd) def decorate(rootWin): # window manager stuff for main window rootWin.title('PyMail 1.0') rootWin.iconname('PyMail') rootWin.protocol('WM_DELETE_WINDOW', onQuitMail) def makemainwindow(parent=None): # make the main window global rootWin, listBox, allModeVar if parent: rootWin = Frame(parent) # attach to a parent rootWin.pack(expand=YES, fill=BOTH) else: rootWin = Tk() # assume I'm standalone decorate(rootWin) # add main buttons at bottom frame1 = Frame(rootWin) frame1.pack(side=BOTTOM, fill=X) allModeVar = IntVar() Checkbutton(frame1, text="All", variable=allModeVar).pack(side=RIGHT) actions = [ ('Load', onLoadMail), ('View', onViewFormatMail), ('Save', onSaveMail), ('Del', onDeleteMail), ('Write', onWriteMail), ('Reply', onReplyMail), ('Fwd', onFwdMail), ('Quit', onQuitMail) ] for (title, callback) in actions: Button(frame1, text=title, command=callback).pack(side=LEFT, fill=X) # add main listbox and scrollbar frame2 = Frame(rootWin) vscroll = Scrollbar(frame2) fontsz = (sys.platform[:3] == 'win' and 8) or 10 listBox = Listbox(frame2, bg='white', font=('courier', fontsz)) # crosslink listbox and scrollbar vscroll.config(command=listBox.yview, relief=SUNKEN) listBox.config(yscrollcommand=vscroll.set, relief=SUNKEN, selectmode=SINGLE) listBox.bind('<Double-1>', lambda event: onViewRawMail()) frame2.pack(side=TOP, expand=YES, fill=BOTH) vscroll.pack(side=RIGHT, fill=BOTH) listBox.pack(side=LEFT, expand=YES, fill=BOTH) return rootWin # load text block string from PyMailGuiHelp import helptext def showhelp(helptext=helptext, appname='PyMail'): # show helptext in from ScrolledText import ScrolledText # a non-modal dialog new = Toplevel() # make new popup window bar = Frame(new) # pack first=clip last bar.pack(side=BOTTOM, fill=X) code = Button(bar, bg='beige', text="Source", command=showsource) quit = Button(bar, bg='beige', text="Cancel", command=new.destroy) code.pack(pady=1, side=LEFT) quit.pack(pady=1, side=LEFT) text = ScrolledText(new) # add Text + scrollbar text.config(font='system', width=70) # too big for showinfo text.config(bg='steelblue', fg='white') # erase on btn or return text.insert('0.0', helptext) text.pack(expand=YES, fill=BOTH) new.title(appname + " Help") new.bind("<Return>", (lambda event, new=new: new.destroy())) def showsource(): # tricky, but open try: # like web getfile.cgi source = open('PyMailGui.py').read() # in cwd or below it? except: try: # or use find.find(f)[0], import os # $PP2EHOME, guessLocation from PP2E.Launcher import findFirst # or spawn pyedit with arg here = os.curdir source = open(findFirst(here, 'PyMailGui.py')).read() except: source = 'Sorry - cannot find my source file' subject = 'Main script [see also: PyMailGuiHelp, pymail, mailconfig]' editmail('View Source Code', 'PyMailGui', 'User', subject, source) def container(): # use attachment to add help button # this is a bit easier with classes root = Tk() title = Button(root, text='PyMail - a Python/Tkinter email client') title.config(bg='steelblue', fg='white', relief=RIDGE) title.config(command=showhelp) title.pack(fill=X) decorate(root) return root if __name__ == '__main__': # run stand-alone or attach rootWin = makemainwindow(container()) # or makemainwindow() rootWin.mainloop() |
| I l@ve RuBoard |


OK – Sen. James M. Inhofe (R) and Sen. James Lankford (R)
Committees
James Lankford is the #16 Republican on the Senate Committee on Appropriations
HEP Grants
In the past 9 years, this state has received: 23 HEP grants, totalling $7,906,000
Year Institution Amount ($)
------ ------------------------- ------------
2019 Oklahoma State University 425,000
2019 University of Oklahoma 481,000
2018 Oklahoma State University 422,000
2018 University of Oklahoma 503,000
2017 Oklahoma State University 419,000
2017 University of Oklahoma 545,000
2016 Oklahoma State University 355,000
2016 University of Oklahoma 590,000
2015 Oklahoma State University 271,000
2015 University of Oklahoma 781,000
2014 University of Oklahoma 785,000
2013 Oklahoma State University 275,000
2013 University of Oklahoma 830,000
2012 Langston University 0
2012 Oklahoma State University 317,000
2012 University of Oklahoma 907,000
SC Contracts
In the past 9 years, this state has received: 4 Office of Science contracts, totalling $19,895
Year Vendor Amount ($) Item
------ ------------------------------------ ------------ --------------------------
2016 Society Of Exploration Geophysicists 5,792 Newspapers And Periodicals
2015 Society Of Exploration Geophysicists 5,519 Newspapers And Periodicals
2014 Society Of Exploration Geophysicists 4,425 Newspapers And Periodicals
2013 Society Of Exploration Geophysicists 4,159 Newspapers And Periodicals
NSF MPS Grants
In the past 9 years, this state has received: 166 NSF MPS grants, totalling $26,462,455
Institution Amount ($)
---------------------------------- ------------
University Of Oklahoma 16,379,425
Oklahoma State University 8,913,896
University Of Tulsa 1,027,163
Rogers State University Foundation 74,591
Tulsa Community College 67,380
SULI/CCI Interns
From 2014-2018, this state had 23 SULI/CCI interns
# Interns Program College
----------- --------- ------------------------------------------
13 SULI Farmingdale State College
6 SULI University of Oklahoma Norman Campus
2 SULI Oklahoma State University
1 SULI Tulsa Community College
1 SULI University of Science and Arts of Oklahoma
23 — — Back to top
OK-01 – Rep. Kevin Hern (R) – Wikipedia
HEP Grants
This district received no SC HEP grants from 2012-2020
SC Contracts
In the past 9 years, this district has received: 4 Office of Science contracts, totalling $19,895
Year Vendor Amount ($) Item
------ ------------------------------------ ------------ --------------------------
2016 Society Of Exploration Geophysicists 5,792 Newspapers And Periodicals
2015 Society Of Exploration Geophysicists 5,519 Newspapers And Periodicals
2014 Society Of Exploration Geophysicists 4,425 Newspapers And Periodicals
2013 Society Of Exploration Geophysicists 4,159 Newspapers And Periodicals
NSF MPS Grants
In the past 9 years, this district has received: $1,094,543 in NSF MPS grants.
Year Institution Amount ($)
------ ----------------------- ------------
2018 University Of Tulsa 509,815
2015 University Of Tulsa 227,348
2014 University Of Tulsa 90,000
2013 University Of Tulsa 90,000
2012 Tulsa Community College 67,380
2012 University Of Tulsa 110,000
SULI/CCI Interns
From 2014-2018, this district had 1 SULI/CCI intern
Term Name College Host Lab Program
----------- ---------- ----------------------- ----------------------------- ---------
Spring 2014 Mang Chang Tulsa Community College Oak Ridge National Laboratory SULI
OK-02 – Rep. Markwayne Mullin (R) – Wikipedia
Committees
Markwayne Mullin is the #19 Republican on the House Committee on Energy and Commerce
HEP Grants
This district received no SC HEP grants from 2012-2020
SC Contracts
This district received no SC contracts from 2012-2020
NSF MPS Grants
In the past 9 years, this district has received: $74,591 in NSF MPS grants.
Year Institution Amount ($)
------ ---------------------------------- ------------
2013 Rogers State University Foundation 74,591
SULI/CCI Interns
This district had no SULI/CCI interns from 2014-2018
OK-03 – Rep. Frank D. Lucas (R) – Wikipedia
Committees
Frank D. Lucas is the #1 Republican on the House Committee on Science, Space, and Technology
HEP Grants
In the past 9 years, this district has received: $2,484,000 in SC HEP grants.
Institution Amount ($) Start End Principal Investigator Project Title
------------------------- ------------ ------- ----- ------------------------ --------------------------------------------------------------------------------------
Oklahoma State University 1,386,000 2016 2020 Nandi, Satyanarayan Theoretical and Experimetal Research in Weak, Electromagnetic and Strong Interactions
Oklahoma State University 506,000 2015 2017 Nandi, Satyanarayan Theoretical And Experimental Research In Weak, Electromagnetic And Strong Interactions
Oklahoma State University 8,000 2013 2014 Babu International Symposium on Opportunities in Underground Physics, May 24-27, 2013
Oklahoma State University 267,000 2013 2014 Nandi Theoretical and Experimental Research in Weak, Electromagnetic and Strong Interactions
Langston University 0 2012 2013 Snow Langston University - High Energy Physics (LU-HEP)
Oklahoma State University 18,000 2012 2014 Khanov Search for New Physics with Top and Bottom Quarks with ATLAS
Oklahoma State University 299,000 2012 2013 Nandi Theoretical Research in Weak, Electromagnetic, and Strong Interactions
SC Contracts
This district received no SC contracts from 2012-2020
NSF MPS Grants
In the past 9 years, this district has received: $8,913,896 in NSF MPS grants.
Year Institution Amount ($)
------ ------------------------- ------------
2020 Oklahoma State University 49,809
2019 Oklahoma State University 952,980
2018 Oklahoma State University 1,203,275
2017 Oklahoma State University 693,077
2016 Oklahoma State University 1,752,536
2015 Oklahoma State University 1,096,746
2014 Oklahoma State University 1,086,723
2013 Oklahoma State University 998,396
2012 Oklahoma State University 1,080,354
SULI/CCI Interns
From 2014-2018, this district had 2 SULI/CCI interns
Term Name College Host Lab Program
----------- -------------- ------------------------- ----------------------------- ---------
Summer 2016 Timothy Alland Oklahoma State University Oak Ridge National Laboratory SULI
Summer 2015 Mang Chang Oklahoma State University Oak Ridge National Laboratory SULI
OK-04 – Rep. Tom Cole (R) – Wikipedia
Committees
Tom Cole is the #7 Republican on the House Committee on Appropriations
HEP Grants
In the past 9 years, this district has received: $5,422,000 in SC HEP grants.
Institution Amount ($) Start End Principal Investigator Project Title
---------------------- ------------ ------- ------- ------------------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------
University of Oklahoma 481,000 2019 2020 Gutierrez, Phillip Experimental Physics Investigations using the ATLAS Detector at the LHC and From
Colliders to Cosmology in the LHC Era
University of Oklahoma 80,000 2016 2017 Baer, Howard OU HEP theory group: From Colliders to Cosmology in the LHC Era
University of Oklahoma 3,124,000 2014 Ongoing Skubic, Patrick Experimental Physics Investigations using the ATLAS Detector at the LHC and From Colliders to Cosmology in the LHC Era
University of Oklahoma 830,000 2013 2014 Skubic Experimental Physics Investigations using Colliding Beam Detectors; Nonperturbative Quantum Field Theory, Particle Physics Beyond the Standard Model And Theoret
University of Oklahoma 0 2012 2013 Baron Spectroscopic Studies of SNe Ia: Finding the Right Model
University of Oklahoma 907,000 2012 2013 Skubic, Milton Experimental Physics Investigations Using Colliding Beam Detectors at Fermilab, Cornell & LHC; Nonperturbative Quantum Field Theory Beyond the...
SC Contracts
This district received no SC contracts from 2012-2020
NSF MPS Grants
In the past 9 years, this district has received: $16,379,425 in NSF MPS grants.
Year Institution Amount ($)
------ ---------------------- ------------
2020 University Of Oklahoma 1,760
2019 University Of Oklahoma 4,181,647
2018 University Of Oklahoma 1,733,810
2017 University Of Oklahoma 1,771,478
2016 University Of Oklahoma 2,724,226
2015 University Of Oklahoma 122,358
2014 University Of Oklahoma 1,485,539
2013 University Of Oklahoma 1,700,945
2012 University Of Oklahoma 2,657,662
SULI/CCI Interns
From 2014-2018, this district had 1 SULI/CCI intern
Term Name College Host Lab Program
----------- ----------- ------------------------------------------ ------------------------ ---------
Summer 2016 David Motes University of Science and Arts of Oklahoma Ames National Laboratory SULI
OK-05 – Rep. Kendra S. Horn (D) – Wikipedia
Committees
Kendra S. Horn is the #5 Democrat on the House Committee on Science, Space, and Technology; Subcommittee on Energy
Kendra S. Horn is the #9 Democrat on the House Committee on Science, Space, and Technology
HEP Grants
This district received no SC HEP grants from 2012-2020
SC Contracts
This district received no SC contracts from 2012-2020
NSF MPS Grants
This district received no NSF MPS grants from 2012-2020
SULI/CCI Interns
From 2014-2018, this district had 19 SULI/CCI interns
Term Name College Host Lab Program
----------- -------------------- ------------------------------------ ------------------------------------- ---------
Summer 2018 Erin Clare Leghart Farmingdale State College Pacific Northwest National Laboratory SULI
Summer 2018 Tunisia Solomon Farmingdale State College Brookhaven National Laboratory SULI
Summer 2018 Rachel Jean Bandy University of Oklahoma Norman Campus Oak Ridge National Laboratory SULI
Summer 2017 Austin Wu Farmingdale State College Brookhaven National Laboratory SULI
Summer 2017 Madelynn Whitney University of Oklahoma Norman Campus Pacific Northwest National Laboratory SULI
Summer 2017 Jenna Lynn Decordova Farmingdale State College Brookhaven National Laboratory SULI
Summer 2017 Theophilus Kwame Doe Farmingdale State College Brookhaven National Laboratory SULI
Summer 2017 David Joseph Livoti Farmingdale State College Brookhaven National Laboratory SULI
Summer 2017 Tunisia Solomon Farmingdale State College Brookhaven National Laboratory SULI
Summer 2016 Kourtney Ann Lewis University of Oklahoma Norman Campus Oak Ridge National Laboratory SULI
Summer 2016 Theophilus Kwame Doe Farmingdale State College Brookhaven National Laboratory SULI
Summer 2016 James Hugh Mcmanus Farmingdale State College Brookhaven National Laboratory SULI
Summer 2014 Eric McCafferty Farmingdale State College Brookhaven National Laboratory SULI
Summer 2014 Dominick Raimondi Farmingdale State College Brookhaven National Laboratory SULI
Summer 2014 Edwin Rosero Farmingdale State College Brookhaven National Laboratory SULI
Summer 2014 Allison Leigh Olin University of Oklahoma Norman Campus National Renewable Energy Laboratory SULI
Spring 2016 Kourtney Ann Lewis University of Oklahoma Norman Campus Oak Ridge National Laboratory SULI
Spring 2016 Kathleen Westervelt Farmingdale State College Lawrence Berkeley National Laboratory SULI
Fall 2018 Lauryn Nicole Carver University of Oklahoma Norman Campus Lawrence Berkeley National Laboratory SULI


Stock Market
Top 4 stock market investment myths
"Stock market is dangerous!"
How often have you heard this statement?...
Top 7 tips to invest in stock market for beginners
Are you willing to start investing in the stock market? Look no further. You have landed up on the right page!...
Read more4 Reasons you must start investing in stock market today
Before we get into other benefits, answer this question, "Why do you want to get into stock market...
Read more3 Common Stock Market Investment Mistakes You Must Avoid
There are many myths about stock markets spread across the world which we have covered
Read moreTop 5 Dos and Don'ts of Stock Market Investment
Are you willing to start investing in the stock market? Look no further. You have landed up on the right page!...
Read more6 Things to Consider Before Choosing a Stock Broker in India
How often have you heard this statement? When it comes to your Demat account, do not settle for less!...
Read more


A game about protecting humans (and a robot).
Just tap all the bombs before they hit the players. It's not as easy as it looks.
Available on iPhone and iPad.


"Not Alone" is a collaboration with The Monument Quilt.  Sections of this physical quilt will be witnessed across the United States through a tour, quilt making workshops, and a historic display in our nation’s capitol.
Some of the patches of this digital quilt are made up of digitized monument quilts, with audio added. Some are video clips of sexual assault survivors, and supports
this creates a living archive of voices around sexual assault.


Checklists can help you evaluate the nursing homes that you call or visit.
Use a new checklist for each home you call or visit. Then, compare the scores.
This will help you select a nursing home that is a good choice for you
or your relative.
-
Basic Information
- Is the facility Medicare certified?:____(yes) _____(no)
- Is the facility Medicaid certified?:____(yes) _____(no)
- Is this a skilled nursing facility?:____(yes) _____(no)
- Is the facility accepting new patients?:____(yes) _____(no)
- Is there a waiting period for admission?:____(yes) _____(no)
- Is a skilled bed available to you?:____(yes) _____(no)
Useful Tips
- Generally, skilled nursing care is available only for a short period
of time after a hospitalization. Custodial care is for a much
longer period of time. If a facility offers both types of care, learn
if residents may transfer between levels of care within the nursing
home without having to move from their old room or from the
nursing home.
- Nursing homes that only take Medicaid residents might offer
longer term but less intensive levels of care. Nursing Homes that
don't accept Medicaid payment may make a resident move when
Medicare or the resident’s own money runs out.
- An occupancy rate is the total number of residents currently living
in a nursing home divided by the home’s total number of beds.
Occupancy rates vary by area, depending on the overall number of
available nursing home beds.
-
Nursing Home Information:
- Is the home and the current administrator licensed?:____(yes)
_____(no)
- Does the home conduct background checks on all staff?:____(yes)
_____(no)
- Does the home have special services units?:____(yes) _____(no)
- Does the home have abuse prevention training?:____(yes) _____(no)
Useful Tips
- LICENSURE: The nursing home and its administrator should be
licensed by the State to operate.
- BACKGROUND CHECKS: Do the nursing home’s procedures to screen
potential employees for a history of abuse meet your State’s
requirements? Your State’s Ombudsman program might be able to
help you with this information.
- SPECIAL SERVICES: Some nursing homes have special service units
like rehabilitation, Alzheimer's, and hospice. Learn
if there are separate waiting periods or facility guidelines for when
residents would be moved on or off the special unit.
- STAFF TRAINING: Do the nursing home’s training programs educate
employees about how to recognize resident abuse and neglect,
how to deal with aggressive or difficult residents, and how to deal
with the stress of caring for so many needs? Are there clear
procedures to identify events or trends that might lead to abuse
and neglect, and on how to investigate, report, and resolve your
complaints?
- LOSS PREVENTION: Are there policies or procedures to safeguard
resident possessions?
For Sections III through VI, give the nursing home a grade from one to
five. One is worst, five is best.
- Quality of Life:
| |
Worst |
|
|
|
Best |
|
1. Residents can make choices about
their daily routine. Examples are
when to go to bed or get up, when to
bathe, or when to eat.
|
1 |
2 |
3 |
4 |
5 |
|
2. The interaction between staff and
patient is warm and respectful.
|
1 |
2 |
3 |
4 |
5 |
|
3. The home is easy to visit for
friends and family.
|
1 |
2 |
3 |
4 |
5 |
|
4. The nursing home meets your
cultural, religious, or language
needs.
|
1 |
2 |
3 |
4 |
5 |
|
5. The nursing home smells and
looks clean and has good lighting.
|
1 |
2 |
3 |
4 |
5 |
|
6. The home maintains comfortable
temperatures.
|
1 |
2 |
3 |
4 |
5 |
|
7. The resident rooms have personal
articles and furniture.
|
1 |
2 |
3 |
4 |
5 |
|
8. The public and resident rooms
have comfortable furniture.
|
1 |
2 |
3 |
4 |
5 |
|
9. The nursing home and its dining
room are generally quiet.
|
1 |
2 |
3 |
4 |
5 |
|
10. Residents may choose from a
variety of activities that they like.
|
1 |
2 |
3 |
4 |
5 |
|
11. The nursing home has outside
volunteer groups.
|
1 |
2 |
3 |
4 |
5 |
|
12. The nursing home has outdoor
areas for resident use and helps
residents to get outside.
|
1 |
2 |
3 |
4 |
5 |
TOTAL: _____________
(Best Possible Score: 60)
- Quality of Care:
| | Worst | | | | Best |
1. The facility corrected any Quality
of Care deficiencies that were in the
State inspection report. |
1 |
2 |
3 |
4 |
5 |
|
2. Residents may continue to see
their personal physician. |
1 |
2 |
3 |
4 |
5 |
|
3. Residents are clean, appropriately
dressed, and well groomed. |
1 |
2 |
3 |
4 |
5 |
|
4. Nursing Home staff respond
quickly to requests for help. |
1 |
2 |
3 |
4 |
5 |
|
5. The administrator and staff seem
comfortable with each other and with
the residents. |
1 |
2 |
3 |
4 |
5 |
|
6. Residents have the same care
givers on a daily basis. |
1 |
2 |
3 |
4 |
5 |
|
7. There are enough staff at night
and on week-ends or holidays to care
for each resident. |
1 |
2 |
3 |
4 |
5 |
|
8. The home has an arrangement for
emergency situations with a nearby
hospital. |
1 |
2 |
3 |
4 |
5 |
|
9. The family and residents councils
are independent from the nursing
home's management. |
1 |
2 |
3 |
4 |
5 |
|
10. Care plan meetings are held at
times that are easy for residents and
their family members to attend. |
1 |
2 |
3 |
4 |
5 |
TOTAL: _____________
(Best Possible Score: 50)
Useful Tips
- Good care plans are essential to good care. They should be put
together by a team of providers and family and updated as often
as necessary.
- Nutrition and Hydration (Diet and Fluids):
| | Worst | | | | Best |
|
1. The home corrected any
deficiencies in these areas that were
on the recent state inspection report. |
1 |
2 |
3 |
4 |
5 |
|
2. There are enough staff to assist
each resident who requires help with
eating. |
1 |
2 |
3 |
4 |
5 |
|
3. The food smells and looks good
and is served at proper
temperatures. |
1 |
2 |
3 |
4 |
5 |
|
4. Residents are offered choices of
food at mealtimes. |
1 |
2 |
3 |
4 |
5 |
|
5. Residents’ weight is routinely
monitored. |
1 |
2 |
3 |
4 |
5 |
|
6. There are water pitchers and
glasses on tables in the rooms. |
1 |
2 |
3 |
4 |
5 |
|
7. Staff help residents drink
if they are not able to do so on their
own. |
1 |
2 |
3 |
4 |
5 |
|
8. Nutritious snacks are available
during the day and evening. |
1 |
2 |
3 |
4 |
5 |
|
9. The environment in the dining room
encourages residents to relax,
socialize, and enjoy their food. |
1 |
2 |
3 |
4 |
5 |
TOTAL: _____________
(Best Possible Score: 45)
Useful Tips
- Ask the professional staff how the medicine a resident takes can
affect what they eat and how often they may want something to
drink.
- Visit at mealtime. Are residents rushed through meals or do they
have time to finish eating and to use the meal as an opportunity
to socialize with each other?
- Sometimes the food a home serves is fine, but a resident still
won't eat. Nursing home residents may like some control over
their diet. Can they select their meals from a menu or select their
mealtime?
- If residents need help eating, do care plans specify what type of
assistance they will receive?
- Safety
| | Worst | | | | Best |
|
1. There are handrails in the
hallways and grab bars in the
bathrooms. |
1 |
2 |
3 |
4 |
5 |
|
2. Exits are clearly marked. |
1 |
2 |
3 |
4 |
5 |
|
3. Spills and other accidents are
cleaned up quickly. |
1 |
2 |
3 |
4 |
5 |
|
4. Hallways are free of clutter and
have good lighting. |
1 |
2 |
3 |
4 |
5 |
|
5. There are enough staff to help
move residents quickly in an
emergency. |
1 |
2 |
3 |
4 |
5 |
|
6. The nursing home has smoke
detectors and sprinklers. |
1 |
2 |
3 |
4 |
5 |
TOTAL: _____________
(Best Possible Score: 30)
- Useful Tips Relating to Information in Nursing Home Compare
Nursing Home Compare contains summary information about nursing
homes from their last state inspection. It also contains information
that was reported by the nursing homes prior to the last State
inspection including nursing home and resident characteristics. If you
have questions or concerns about the information on a nursing home,
you should discuss them during your visit. This section contains useful
tips and questions that you may want to ask the nursing home staff,
family members and residents of the nursing home during your visit.
Nursing Home Compare Information on Results of Nursing Home
Inspections
- Bring a copy of the Nursing Home Compare inspection results for
the nursing home. Ask whether the deficiencies have been
corrected.
- Ask to see a copy of the most recent nursing home inspection
report.
Nursing Home Compare Information on Resident and Nursing
Home Characteristics
- For the Measure: Residents with Physical Restraints
- Does it appear that there is sufficient staff to assist
residents who need help in moving or getting in and out
of chairs and bed?
- Ask the Director of Nursing who is involved in the
decisions about physical restraints.
- When physical restraints are used, do the staff remove the
physical restraints on a regular basis to help residents with
moving, and with activities of daily living?
- Do the staff help residents with physical restraints to get in and
out of bed and chairs when they want to get up?
- Do staff help residents with physical restraints to move as much
as they would like to?
- For the Measure: Residents with Pressure (Bed) Sores
- Ask the staff how they identify if a resident is at risk for
skin breakdown. Ask them what they do to prevent
pressure sores for these residents.
- Ask the staff about the percentage of their residents
that have pressure sores and why.
- Do you see staff helping residents change their
positions in wheelchairs, chairs, and beds?
- For the Measure: Residents with Bowel and Baldder Incontinence
- Does the nursing home smell clean?
- Ask the staff what steps they take to prevent
bowel and bladder incontinence for residents who are at risk.
-
For the Measure: Residents Who Are Very Dependent in
Eating
- Look at your response to Question 2 in Section V above.
- Observe residents who need help in eating. Are they
able to finish their meals or is the food returned to the
kitchen uneaten?
-
For the Measure: Residents Who Are Bedfast
- Ask the Director of Nursing how staff are assigned to
care for these residents.
-
For the Measure: Residents With Restricted Joint
Motion
- Ask the Director of Nursing how the nursing home cares
for residents with restricted joint motion.
- Do the residents get help with getting out of chairs and
beds when they want to get up?
-
- For the Measure: Residents with Unplanned Weight
Gain or Loss
- Look at your responses to Questions 2, 3, 4, 5, 8, and 9
in section V above.
- For the Measure: Residents with Behavioral Symptoms
- What management and/or medical approaches for
behavioral symptoms are being used by the nursing
home?
- How does staff handle residents that have behavioral
symptoms such as calling out or yelling?
- Ask whether residents with behavioral symptoms are
checked by a doctor or behavioral specialist.
- Ask whether staff get special training to help them to
provide care to residents with behavioral symptoms.
Nursing Home Compare Information on Nursing Staff
Caring, competent nursing staff who respect each resident and family member are
very important in assuring that residents get needed care and enjoy the best
possible quality of life. Adequate nursing staff is needed to assess resident needs,
plan and give them care, and help them with eating, bathing and other activities.
Some residents (e.g., those who are more dependent in eating or who are bedfast) need
more help than other residents depending on their conditions.
The combinations of registered nurses (RNs), licensed practical and
vocational nurses (LPNs/LVNs), and certified nursing assistants (CNAs)that nursing
homes may have vary depending on the type of care that residents need and the number
of residents in the nursing home.
- Look at your responses to Questions 2 and 5 in section III above and
Questions 4, 5, and 10 in section IV above. Also look at your responses to
Questions 2 and 7 in section V above.
- Are nursing staff members courteous and friendly to residents and to other
staff?
- Do nursing staff respond timely to residents calls for assistance such as
help getting in and out of bed, dressing and going to the bathroom?
- Observe meal times. Do all residents who need assistance with eating get
help? Do staff give each resident enough time to chew food thoroughly and
complete the meal?
- Which nursing staff members are involved in planning the residents
individual care? (Are they the same ones who give the care to residents?)
- Ask questions about staff turnover. Is there frequent turnover among
certified nursing assistants (CNAs)? What about nurses and supervisors,
including the Director of Nursing and the Administrator? If staff changes
frequently, ask why.
- While the number of nursing staff is important to good care, also consider
other factors, such as education and training. How many registered nurses (RNs)
are on the staff, and how many available on each shift? What kind of training
do certified nursing assistants (CNAs) receive? How does the nursing home ensure
that all staff receive continuing education and keep their knowledge and skills
up-to-date?


Random Word
Random word is a new feature introduced with 0.4Beta. Random word feature allows
user to have a window that can show random words from telugu and english.
Random word improves vocabulary by letting user to see through a random
dictionary word (both telugu and english) at a time.
Random word options:
- Always On Top: Shows the random word always on top
of the screen. Accessible via right click on tray icon.
- Timer setting: Gives user option to set the random
word display timer. After configured time interval, a new word will be displayed
from telugu and english.
- Opacity setting:Random word display can be set with
a defined opacity level from user
- Playback controls:Random word display will be shown
with standard controls "Forward, Play/Pause, Stop, and Rewind". These controls
will let user to have the random word display pause for some time and playback
to previous words.


JS9 supports the ability to perform local analysis, i.e. tasks executed in your browser (not on the back-end server). This is accomplished by offering access to the image data and region information via a JS9 Public API. Obviously, all of JS9 JavaScript code is available to you within a web page, but the public API is designed to stable and well-documented.
Adding Simple Analysis Tasks to Your Web Page
For simple analysis (i.e., no mouse or keyboard event processing), it often is sufficient to define GUI elements directly on the web page, adding Javascript code to interact with these elements and call the public JS9 functions as needed. In particular, the JS9.GetImage() function will return a handle for the currently displayed image and the the various JS9.Region functions allow you to manipulate regions. These routines are described in the JS9 Public API.
The js9onchange.html demo web page illustrates these simple capabilities. It shows how to run a task every time a region changes, i.e. when it is moved, resized, or deleted. This is accomplished by setting the JS9.Regions.opts.onchange parameter to a function (if you are setting via JavaScript) or a string routine name (if you are setting via json in the prefs file):
// via JavaScript JS9.Regions.opts.onchange = myRegionChanged;or:
// from within js9Prefs.json { ... "Regions.opts": {"onchange": "myRegionChanged"} ... }The calling sequence of the xeqonchange function is:
function myRegionChanged(im, xreg)where im is the image handle of the currently displayed image, and xreg is an object containing information about the changed region. See below for a description of the returned region object. Note that you can turn off region change processing for individual regions or for all regions by means of the xeqonchange menu option in a given region's context menu or the global Regions menu, respectively.
The js9onchange.html demo web page also shows how server-side JS9 analysis tasks can be executed directly from the web page using HTML elements (buttons, forms, etc.) instead of the Analysis menu. See Server-side Analysis Tasks for more information.
For anything other than the simplest analysis, you can write a JS9 Plugin module. A plugin is a Javascript module that contains a constructor function to create a plugin GUI, and, optionally, one or more event callbacks to process desired events. At the end of the file, the plugin calls RegisterPlugin() to make itself known to JS9. Plugin modules should be stored in the js9/plugins directory (or in a sub-directory therein) and should be loaded into JS9-enabled web pages after js9.js itself is loaded.
To create instances of the plugin GUI, the constructor function gets called for each plugin div defined on the web page. The this context is seeded with a few JS9 properties, including:
A JS9 plugin is registered at the end of the module using the JS9.RegisterPlugin() public routine:
JS9.RegisterPlugin(xclass, xname, func, opts)where:
This class/name separation has been made so that multiple plugins can be written as part of one class and processed together as part of that class, e.g., displayed together in the View and Help menus.
The optional opts object contains the following elements, all of which also are optional:
Each of the callback functions are routines which get executed when the specified event takes place. The routines are passed the following arguments: current image object handle, the 1-indexed image position of the mouse and, for all but the on[layer]change, onimageload and onimagedisplay routines, the original event that triggered the callback. The on[layer]change callback gets passed the same xreg object as is used for the JS9.Regions() routine and the JS9.Regions.opts.onchange parameter. See below for a description of its contents.
Holding down the Shift key (where available) will turn off execution of all mouse event callbacks. This allows you to move the mouse to a specific location, and then move away without triggering a callback. The xeqonchange menu option in the Regions menu and each region's context menu can be used to turn off execution of the region onchange callback. The former does this globally, the latter only for the specific region.
The divArgs is an array specifying arguments to pass to the constructor function, when a div element is found in the web page. For example, the Panner and Magnifier plugins pass a width and height to the constructor in this way.
The menuItem is a string which specifies the name that will be used in the View menu when a plugin div is not found on the web page. If no menuItem is specified, the plugin will not appear in the View menu.
Furthermore, the menu property can be used to change the menu in which the above-mentioned menuItem plugin will be placed. For example, an Imexam plugin situates its plugins in the Analysis menu instead of the View menu. NB: At the moment, only the View and Analysis menus are supported for placement.
The winDims is an array specifying the width and height of the light window that will get created for this plugin via the View menu. The winTitle is a string specifying the title of the light window. The default is no title.
You can add HTML (e.g. command buttons) to the light window titlebar by putting an HTML string into the toolbarHTML property. The panner and magnifier use this technique to add zoom buttons. You also can add HTML onto a web page plugin div, but in this case, where the HTML is placed depends on the value of the toolbarSeparate property. If the value of toolbarSeparate is true, then a titlebar is created above the plugin and the HTML is added to it. Otherwise, the HTML is placed in top of the plugin itself.
The help property specifies the pathname of an html file that will be placed in the Help menu. This pathname should be relative to the plugins directory.
Within a callback, you can use the JS9 Public API to manipulate data, as detailed in the JS9 Public API.


|
|
IntroductionAny number of practical applications in computing require things to be in order. Even before we start computing, the importance of sorting is drilled into us. From group pictures that require the tallest people to stand in the back, to the highest grossing salesman getting the largest Christmas bonus, the need to put things smallest to largest or first to last cannot be underestimated.When we query a database, and append an ORDER BY clause, we are sorting. When we look for an entry in the phone book, we are dealing with a list that has already been sorted. (And imagine if it weren't!) If you need to search through an array efficiently using a binary search, it is necessary to first sort the array. When a problem statement dictates that in the case of a tie we should return the lexicographically first result, well… you get the idea. General Considerations Imagine taking a group of people, giving them each a deck of cards that has been shuffled, and requesting that they sort the cards in ascending rank order. Some people might start making piles, others might spread the cards all over a table, and still others might juggle the cards around in their hands. For some, the exercise might take a matter of seconds, for others several minutes or longer. Some might end up with a deck of cards where spades always appear before hearts, in other cases it might be less organized. Fundamentally, these are all the big bullet points that lead algorithmists to debate the pros and cons of various sorting algorithms. When comparing various sorting algorithms, there are several things to consider. The first is usually runtime. When dealing with increasingly large sets of data, inefficient sorting algorithms can become too slow for practical use within an application. A second consideration is memory space. Faster algorithms that require recursive calls typically involve creating copies of the data to be sorted. In some environments where memory space may be at a premium (such as an embedded system) certain algorithms may be impractical. In other cases, it may be possible to modify the algorithm to work "in place", without creating copies of the data. However, this modification may also come at the cost of some of the performance advantage. A third consideration is stability. Stability, simply defined, is what happens to elements that are comparatively the same. In a stable sort, those elements whose comparison key is the same will remain in the same relative order after sorting as they were before sorting. In an unstable sort, no guarantee is made as to the relative output order of those elements whose sort key is the same. Bubble Sort One of the first sorting algorithms that is taught to students is bubble sort. While it is not fast enough in practice for all but the smallest data sets, it does serve the purpose of showing how a sorting algorithm works. Typically, it looks something like this: for (int i = 0; i < data.Length; i++) for (int j = 0; j < data.Length - 1; j++) if (data[j] > data[j + 1]) { tmp = data[j]; data[j] = data[j + 1]; data[j + 1] = tmp; }The idea is to pass through the data from one end to the other, and swap two adjacent elements whenever the first is greater than the last. Thus, the smallest elements will "bubble" to the surface. This is O(n˛) runtime, and hence is very slow for large data sets. The single best advantage of a bubble sort, however, is that it is very simple to understand and code from memory. Additionally, it is a stable sort that requires no additional memory, since all swaps are made in place. Insertion Sort Insertion sort is an algorithm that seeks to sort a list one element at a time. With each iteration, it takes the next element waiting to be sorted, and adds it, in proper location, to those elements that have already been sorted. for (int i = 0; i <= data.Length; i++) { int j = i; while (j > 0 && data[i] < data[j - 1]) j--; int tmp = data[i]; for (int k = i; k > j; k--) data[k] = data[k - 1]; data[j] = tmp; }The data, as it is processed on each run of the outer loop, might look like this: {18, 6, 9, 1, 4, 15, 12, 5, 6, 7, 11} { 6, 18, 9, 1, 4, 15, 12, 5, 6, 7, 11} { 6, 9, 18, 1, 4, 15, 12, 5, 6, 7, 11} { 1, 6, 9, 18, 4, 15, 12, 5, 6, 7, 11} { 1, 4, 6, 9, 18, 15, 12, 5, 6, 7, 11} { 1, 4, 6, 9, 15, 18, 12, 5, 6, 7, 11} { 1, 4, 6, 9, 12, 15, 18, 5, 6, 7, 11} { 1, 4, 5, 6, 9, 12, 15, 18, 6, 7, 11} { 1, 4, 5, 6, 6, 9, 12, 15, 18, 7, 11} { 1, 4, 5, 6, 6, 7, 9, 12, 15, 18, 11} { 1, 4, 5, 6, 6, 7, 9, 11, 12, 15, 18}One of the principal advantages of the insertion sort is that it works very efficiently for lists that are nearly sorted initially. Furthermore, it can also work on data sets that are constantly being added to. For instance, if one wanted to maintain a sorted list of the highest scores achieved in a game, an insertion sort would work well, since new elements would be added to the data as the game was played. Merge Sort A merge sort works recursively. First it divides a data set in half, and sorts each half separately. Next, the first elements from each of the two lists are compared. The lesser element is then removed from its list and added to the final result list. int[] mergeSort (int[] data) { if (data.Length == 1) return data; int middle = data.Length / 2; int[] left = mergeSort(subArray(data, 0, middle - 1)); int[] right = mergeSort(subArray(data, middle, data.Length - 1)); int[] result = new int[data.Length]; int dPtr = 0; int lPtr = 0; int rPtr = 0; while (dPtr < data.Length) { if (lPtr == left.Length) { result[dPtr] = right[rPtr]; rPtr++; } else if (rPtr == right.Length) { result[dPtr] = left[lPtr]; lPtr++; } else if (left[lPtr] < right[rPtr]) { result[dPtr] = left[lPtr]; lPtr++; } else { result[dPtr] = right[rPtr]; rPtr++; } dPtr++; } return result; }Each recursive call has O(n) runtime, and a total of O(log n) recursions are required, thus the runtime of this algorithm is O(n * log n). A merge sort can also be modified for performance on lists that are nearly sorted to begin with. After sorting each half of the data, if the highest element in one list is less than the lowest element in the other half, then the merge step is unnecessary. (The Java API implements this particular optimization, for instance.) The data, as the process is called recursively, might look like this: {18, 6, 9, 1, 4, 15, 12, 5, 6, 7, 11} {18, 6, 9, 1, 4} {15, 12, 5, 6, 7, 11} {18, 6} {9, 1, 4} {15, 12, 5} {6, 7, 11} {18} {6} {9} {1, 4} {15} {12, 5} {6} {7, 11} {18} {6} {9} {1} {4} {15} {12} {5} {6} {7} {11} {18} {6} {9} {1, 4} {15} {5, 12} {6} {7, 11} {6, 18} {1, 4, 9} {5, 12, 15} {6, 7, 11} {1, 4, 6, 9, 18} {5, 6, 7, 11, 12, 15} {1, 4, 5, 6, 6, 7, 9, 11, 12, 15, 18}Apart from being fairly efficient, a merge sort has the advantage that it can be used to solve other problems, such as determining how "unsorted" a given list is. Heap Sort In a heap sort, we create a heap data structure. A heap is a data structure that stores data in a tree such that the smallest (or largest) element is always the root node. (Heaps, also known as priority queues, were discussed in more detail in Data Structures.) To perform a heap sort, all data from a list is inserted into a heap, and then the root element is repeatedly removed and stored back into the list. Since the root element is always the smallest element, the result is a sorted list. If you already have a Heap implementation available or you utilize the Java PriorityQueue (newly available in version 1.5), performing a heap sort is fairly short to code: Heap h = new Heap(); for (int i = 0; i < data.Length; i++) h.Add(data[i]); int[] result = new int[data.Length]; for (int i = 0; i < data.Length; i++) data[i] = h.RemoveLowest();The runtime of a heap sort has an upper bound of O(n * log n). Additionally, its requirement for storage space is only that of storing the heap; this size is linear in proportion to the size of the list. Heap sort has the disadvantage of not being stable, and is somewhat more complicated to understand beyond just the basic implementation. Quick Sort A quick sort, as the name implies, is intended to be an efficient sorting algorithm. The theory behind it is to sort a list in a way very similar to how a human might do it. First, divide the data into two groups of "high" values and "low" values. Then, recursively process the two halves. Finally, reassemble the now sorted list. Array quickSort(Array data) { if (Array.Length <= 1) return; middle = Array[Array.Length / 2]; Array left = new Array(); Array right = new Array(); for (int i = 0; i < Array.Length; i++) if (i != Array.Length / 2) { if (Array[i] <= middle) left.Add(Array[i]); else right.Add(Array[i]); } return concatenate(quickSort(left), middle, quickSort(right)); }The challenge of a quick sort is to determine a reasonable "midpoint" value for dividing the data into two groups. The efficiency of the algorithm is entirely dependent upon how successfully an accurate midpoint value is selected. In a best case, the runtime is O(n * log n). In the worst case-where one of the two groups always has only a single element-the runtime drops to O(n˛). The actual sorting of the elements might work out to look something like this: {18, 6, 9, 1, 4, 15, 12, 5, 6, 7, 11} {6, 9, 1, 4, 12, 5, 6, 7, 11} {15} {18} {6, 9, 1, 4, 5, 6, 7, 11} {12} {15} {18} {1, 4} {5} {6, 9, 6, 7, 11} {12} {15} {18} {1} {4} {5} {6} {6} {9, 7, 11} {12} {15} {18} {1} {4} {5} {6} {6} {7} {9, 11} {12} {15} {18} {1} {4} {5} {6} {6} {7} {9} {11} {12} {15} {18}If it is known that the data to be sorted all fit within a given range, or fit a certain distribution model, this knowledge can be used to improve the efficiency of the algorithm by choosing midpoint values that are likely to divide the data in half as close to evenly as possible. A generic algorithm that is designed to work without respect to data types or value ranges may simply select a value from the unsorted list, or use some random method to determine a midpoint. Radix Sort The radix sort was designed originally to sort data without having to directly compare elements to each other. A radix sort first takes the least-significant digit (or several digits, or bits), and places the values into buckets. If we took 4 bits at a time, we would need 16 buckets. We then put the list back together, and have a resulting list that is sorted by the least significant radix. We then do the same process, this time using the second-least significant radix. We lather, rinse, and repeat, until we get to the most significant radix, at which point the final result is a properly sorted list. For example, let's look at a list of numbers and do a radix sort using a 1-bit radix. Notice that it takes us 4 steps to get our final result, and that on each step we setup exactly two buckets: {6, 9, 1, 4, 15, 12, 5, 6, 7, 11} {6, 4, 12, 6} {9, 1, 15, 5, 7, 11} {4, 12, 9, 1, 5} {6, 6, 15, 7, 11} {9, 1, 11} {4, 12, 5, 6, 6, 15, 7} {1, 4, 5, 6, 6, 7} {9, 11, 12, 15}Let's do the same thing, but now using a 2-bit radix. Notice that it will only take us two steps to get our result, but each step requires setting up 4 buckets: {6, 9, 1, 4, 15, 12, 5, 6, 7, 11} {4, 12} {9, 1, 5} {6, 6} {15, 7, 11} {1} {4, 5, 6, 6, 7} {9, 11} {12, 15}Given the relatively small scope of our example, we could use a 4-bit radix and sort our list in a single step with 16 buckets: {6, 9, 1, 4, 15, 12, 5, 6, 7, 11} {1} {} {} {4} {5} {6, 6} {7} {} {9} {} {11} {12} {} {} {15}Notice, however, in the last example, that we have several empty buckets. This illustrates the point that, on a much larger scale, there is an obvious ceiling to how much we can increase the size of our radix before we start to push the limits of available memory. The processing time to reassemble a large number of buckets back into a single list would also become an important consideration at some point. Because radix sort is qualitatively different than comparison sorting, it is able to perform at greater efficiency in many cases. The runtime is O(n * k), where k is the size of the key. (32-bit integers, taken 4 bits at a time, would have k = 8.) The primary disadvantage is that some types of data may use very long keys (strings, for instance), or may not easily lend itself to a representation that can be processed from least significant to most-significant. (Negative floating-point values are the most commonly cited example.) Sorting Libraries Nowadays, most programming platforms include runtime libraries that provide a number of useful and reusable functions for us. The .NET framework, Java API, and C++ STL all provide some built-in sorting capabilities. Even better, the basic premise behind how they work is similar from one language to the next. For standard data types such as scalars, floats, and strings, everything needed to sort an array is already present in the standard libraries. But what if we have custom data types that require more complicated comparison logic? Fortunately, object-oriented programming provides the ability for the standard libraries to solve this as well. In both Java and C# (and VB for that matter), there is an interface called Comparable (IComparable in .NET). By implementing the IComparable interface on a user-defined class, you add a method int CompareTo (object other), which returns a negative value if less than, 0 if equal to, or a positive value if greater than the parameter. The library sort functions will then work on arrays of your new data type. Additionally, there is another interface called Comparator (IComparer in .NET), which defines a single method int Compare (object obj1, object obj2), which returns a value indicating the results of comparing the two parameters. The greatest joy of using the sorting functions provided by the libraries is that it saves a lot of coding time, and requires a lot less thought and effort. However, even with the heavy lifting already completed, it is still nice to know how things work under the hood.
|
|
|
Home |
About TopCoder |
Press Room |
Contact Us |
Careers |
Privacy |
Terms
Competitions | Cockpit |
| Copyright TopCoder, Inc. 2001-2011 |


{% extends 'spaces/base.html' %} {% load static %} {% block title %}Register Your Space{% endblock %} {% block style %} {% endblock %} {% block content %}
Thank you for registering a space with us. We will send you a mail shortly after confirming your Space.


This page features an outline drawing of the Cook.
This modal box is an example of a tour stop. You can add or embed other information here, like videos, images from other libraries, visualizations, and so on.
For instance, here's an image of the woodcut Cook from William Caxton's second edition of Chaucer's Canterbury Tales, digitized by the British Library:


WELCOME........Let's Play Pig Dice.... :-)
Player1
0
Totalscore
Turnscore
Roll Number
ROLL
HoLD
player2
0
Totalscore
Turnscore
Roll Number
ROLL
HOLD


| Name: | %name% [%objId%] |
| Grade: | %grade% |
| Count: | %count% |
| Owner: | %owner% |
| OwnerId: | %ownerId% |
| Fire Val: | %fireVal% |
| Water Val: | %waterVal% |
| Wind Val: | %windVal% |
| Earth Val: | %earthVal% |
| Holy Val: | %holyVal% |
| Unholy Val: | %unholyVal% |
| Ench Level: | %enchLevel% |
| Type: | %type% |
| Drop Time: | %dropTime% |
| Drop Owner: | %dropOwner% |
| Drop Owner Id: | %dropOwnerId% |


Run script forever, without parallel execution
Execute a script every minute, but make sure it never runs two instances. This snippet only works for blocking tasks, but can easily adapted to e.g. restart a nonblocking development server.
#!/bin/bash
PIDFILE=path/to/pid-file
if [ -e $PIDFILE ]; then
OLD_PID=$(cat $PIDFILE)
if ps -p "$OLD_PID" > /dev/null
then
exit 0
fi
fi
# good to go, no processes running
echo $$ > $PIDFILE
rsync $FROM $TO


" just normal people, born and live in Bandarlampung, currently study at Universitas Teknokrat Indonesia Specializing in Informatika. Love and addicted with programming and IT security "
Location: Bandar Lampung, Indonesia
Email<EMAIL_ADDRESS>Nomor: 0896-93068623