The next time I move (and have to change my address anyway) I'm totally signing up for one of those we-scan-your-paper-mail services. - ⓞnor
Consider the filing cabinet to be the audit trail table in your database. Every time the database changes, the audit trail table has to be updated, so indexing that table adds extra cost to every change in the DB. However, it makes the audit trail easy to query. If you don't index that table, every audit lookup requires an expensive table scan that bogs down your whole server for minutes at a time. That expense might be so high that you don't do audit queries even when you want to. - Gabe Schaffer
What's an audit query, and why would anyone ever do one to their old phone bills? - ⓞnor
The audit table in your database keeps track of when something in your database changed. You would do an audit query when you want to find out when some field changed or what the value was on a particular date, for example. You would want to do this with your old phone bills when you want to figure out the last time your rates changed or to see how this month's usage compared to this month a year ago. - Gabe Schaffer
My point is that keeping the data unindexed makes it almost impossible to use, so why bother keeping it at all? - Gabe Schaffer
Because "almost impossible" is different from actually impossible, and because the large cost of finding those few items you need is less than the combined small cost of indexing the many items you file. - ⓞnor
Sure, Onor, but odds are that the task of going through the unsorted mess would be substantial enough that you just wouldn't do it, or would find other ways around it like just asking the phone company. - Gabe Schaffer
Sounds good to me. But if the IRS comes knocking, you might really want those records... - ⓞnor
i like sinophore's comment on your blog (but i like commenting here better). i had a gigantic pile of bills/statements/etc in my closet which i had to sort through before i moved :( it was painful. - Neha Narula
The write penalty might be worth it if you ever need an incredibly fast seek performance... - Steve Lacey
Oh God, I can't stop laughing at the "Sure, Onor" comment. (Gabe, that "O" is an egg.) - niniane
The story is #7 on the Reddit front page. - Gary Burd
I am amused at how much discussion this post is generating. I hope RB doesn't mind. - niniane
I'm pretty sure you can't just uncircle an o like that, it messes up the phoenetics. - j1m
Anyway, I agree with ⓞnor's weights (as always) -- the point of saving papers is that there's a tiny, tiny, tiny chance that you'll need them. Not a chance that you'll want them really bad -- I don't know what that chance is -- but the chance that you'll *need* them. In that case you just search through the damn things, even if you have a file cabinetfull it won't take more than an evening to look at each one. In my experience this happens about once every 10 years. - j1m
Neha: Why did you have to sort them? Why not just move 'em all in unopened boxes? My name: we Circlevanians are used to people mangling our names. Call me Onor, Nor, @Nor, whatev'z. - ⓞnor
And if it turns out that you do need to search, just file then: manual incremental filing is probably less efficient than manual batch filing. - Larry Greenfield
Some people on the blog assert that there's some kind of hard latency requirement for lookup. Those people are wrong. John K Lin asserts that carefully filing your bank statements into neat little alphabetized folders is warm and human, but putting it all in storage for later and getting on with your life is cold and robot-like. John K Lin is weird. - ⓞnor
eggy: two things. First, there was a bunch of extra stuff like envelopes that I didn't need to move. Second, it gives me happiness to put things in file folders. - Neha Narula
@paul: Your sole provider of operating systems :-) - Sanjay Ghemawat
Microsoft executive sez: "The first in this series of television ads airs initially in the U.S., and it aims to re-ignite consumer excitement about the broader value of Windows." (via TechCrunch http://www.techcrunch.com/2008... ) I understand the goal, but I don't see how this ad helps. - Gary Burd
$10M for Seinfeld for this and $300M ad campaign in total - as an icebreaker to reintroduce Microsoft to viewers in a consumer context. I can think of million ways to spend this more usefully. - Krishna Gade
That was a really bad ad, seriously! - Sumit Chachra
"Roscoe Mitchell’s seminal solo joint Nonaah. Out of print for decades and never on CD, the tapes have finally been remastered for better sound and five previously unreleased tracks have been added to the original album’s already impressive sprawl." The 22 minute solo version of Nonaah is a little much, but otherwise this is pretty good. - Gary Burd
“It seems like the U-turn is pretty important for driving around Mountain View. In Rochester you see no U-turn signs everywhere but here it's the opposite.”
Typically, it's possible to choose a route that avoids this problem. Obviously the divided portions of El Camino sometimes require it though. - Paul Buchheit
I'd like this, but seems untrue for most situations. You will probably be making few u-turns in the future. - Chris White
I love the Nautilus in the fish tank at the Local Fish Store in Mountain View. Highly suggest bringing your kids to check it out. - Brian Daniel Eisenberg
@Benjamin, you moving out there, or just going out for a visit to the office? - Jason Carreira
I think he's the new FFer. Probably driving in u-turns trying to find La Fiesta. :) - Chris White
I avoided the u-turns by walking. My challenge was finding a low spot on the fence along the Stevens Creek Trail. - Gary Burd
Just in town to visit. I'm walking everywhere. - Benjamin Golub
Gary: did you? can I hop my bike over it? - Tudor Bosman
Paul is right. The need for the u-turn is on el camino, where you know the store you want is there, but you aren't sure what side of the street it's on. - Chris White
Tudor: Here's where I hop over the fence near the hotel: http://tinyurl.com/576dfg I don't think it's practical to hop over with a bicycle because there's a very steep drop from ECR down to the trail. There's an official access point here: http://tinyurl.com/5ts38l - Gary Burd
I *love* Vim. It's the first thing I install on any Windows system I have to work on. - Joey Gibson
I need to do this too Eric. I know how to use vim but not to it's fullest and I use it exclusively...I always mean to teach myself how to do more. - Benjamin Golub
I'm not sure if I want the lens yet; I need to see some reviews first. But they both sound awesome. I mainly use my wish list for things I really do not need and am likely never to purchase :P - Benjamin Golub
"Think of it this way: When you go to the movies, you don’t go around to each theater to see which movies are playing and when; it would take all of your time and effort running around from theater to theater. Instead, you check the kiosk out front.
Your blog publishing system provides a RSS kiosk, or ping feed, to let FriendFeed (and potential RSS readers) know when and what has been updated since its last visit. Friendfeed doesn’t have to go theater to theater to see which movie is playing. It also checks all RSSs in a domain at once, eliminating the need to download each one separately. Polling is less frequent, but more accurate. By cutting out a lot of wasted data transfer, it reduces the load and gets the relevant information directly." - Paul Buchheit via Bookmarklet
So we need an index for the RSS feeds. Who's gonna post the index of indexes? - Bill Sodeman
I clicked on Paul's link to the code, but it was hard to read because the whitespace was collapsed. Looking at the source it seems that they're nesting the code within tables within <pre> tags. Since <pre> can't contain tables, my browser is ignoring the <pre>s. Why would they do that instead of just putting style="collapse-whitespace:pre" on the table? - Gabe Schaffer
No, Paul, I have a modern browser: IE 6.0sp2. - Gabe Schaffer
I don't know if I'd call IE 6 a "modern browser", considering it was initially released over 7 years ago... in any case you can view the source in plain text here: http://simpleupdateprotocol.go... - Simon Willison
I wouldn't call IE6 a modern browser either, but 14% of the traffic to code.google.com still comes from it, so it does need to be supported -- I'll open a ticket to investigate the issue (I don't have access to Windows right now to confirm). Though @Gabe, since you're a technically inclined person, I'm curious why you are running IE6 rather than FF3 or IE7. - DeWitt Clinton
Most of my clients are still running IE6, so I know that when something works on my machine, it will work on theirs too. Besides, I haven't really found a feature in IE7 or FF that is worth upgrading for. And honestly, I would consider it a bug for a browser to render a block element like a table inside a pre (which only allows certain inline content), particularly on a page that specifies XHTML Strict. I expect the browser to either ignore the pre (like IE6) or ignore the table. - Gabe Schaffer
Cool, thanks for the feedback Gabe. I opened a ticket here: http://code.google.com/p/suppo.... Please feel free to add more detail to that ticket and star it so you can follow the progress. Cheers! - DeWitt Clinton
Thanks Paul. It's definitely an issue that needs to be dealt with. - Daniel Shaw
Since I can find colliding user IDs easily with MD5, is there any risk of a DoS attack? - Steve Weis
I'm not sure what you're asking Steve. Each site generates their own SUP-IDs, so they would be DOSing themselves. - Paul Buchheit
ok plea to all bloggers- please stop using "modest proposal"- you're referencing Swift who was writing satire, about killing Irish babies to prevent/deal with famine. Almost all blogs with this play on the phrase "modest proposal" are not being satirical... so it's a reference without meaning.. I get confused easily, granted. And, not just this post, but there have been others... OK english major out. Thnx. - anna
Paul, maybe I'm misunderstanding the protocol, but I can pick a name that intentionally collides with someone else's SUP-ID. Is there any expectation of collision resistance? - Steve Weis
Steve, The service assigns SUP-IDs. It is in the service's interest to minimize collisions between the SUP-IDs it assigns. - Gary Burd
Steve, each SUP feed has its own SUP-ID space, so you really can't cause problems with other people's feeds. If that's not what you mean, please provide an example of what you have in mind. - Paul Buchheit
@Gabe Raymond's proposal sounds sincere, so it's not really playing off of Swift's joke. Sigh. I guess nobody reads Swift anymore. He was funny! - anna
Steve, IF the service assigns SUP-IDs as md5(username), then yes, you could theoretically get a username that collides with another. But: usernames are usually short, and so you probably won't be able to find a collision with just a few (tens of) characters. Also, as Gary and Paul said, the provider assigns SUP-IDs, and it's in their interest to assign them in a collision-free manner; at the very least, they can hash a secret salt value together with the username. - Tudor Bosman
I've noticed that there is definitely some confusion around SUP. People have said comments like "I'll add it to my blog soon", but I don't think they understand that doing so could actually send MORE traffic to their personal site than they were getting before (from FriendFeed). I think it might help to clarify that this is really useful for large providers like YouTube, blogger.com, Twitter, etc. Personal WordPress installs won't likely benefit. Please correct me if I'm wrong :) - Patrick Lightbody
Patrick, for personal WordPress installs, it would be better to use a shared SUP feed. I'll probably write one when I get a chance. - Paul Buchheit
SUP is also good for providers that aren't big yet but expect to get big, like OurDoings. - Bruce Lewis via fftogo
Until SUP is widely adopted, one feature I'd like to see is "refresh my feeds" button that instructs the backend to refresh the feeds I own right away. - Misha Dynin
There are significant differences between SUP and the Six Apart update stream: (1) SUP documents are fixed length. SUP clients periodically poll the server for new updates. Six Apart streams updates to the client. (2) SUP documents contain opaque feed identifiers. Six Apart sends a stream of Atom feed entries. - Gary Burd
SUP can also be used to monitor for updates on any URL regardless of content-type using the X-SUP-ID HTTP header. You are correct though that it's essentially a compact, standardized, generalized, discoverable form of an update feed. - Paul Buchheit
As SUP is basically a "service-to-service" behind the scene protocol, streamed version with persistent connections seems to be more interesting. Also, SixApart streams contain the actual data and stream consumer does not need to fetch individual feeds. - Alex Kapranoff
Alex, streamed is less efficient because it delivers data that I don't care about, has privacy problems (what would Google Reader Shared Items stream?), and is much more complex to implement (try doing it in PHP on shared hosting). - Paul Buchheit
The first and the second things you mention are problems of the SixApart implementation which is not a standard of some unchangeable kind. One can easily add filtering to the Atom Stream protocol and probably do something with the secret URLs. Implementation for small shared hosting based sites is, on the other side, nearly impossible, yes. But why a small site would want to implement SUP? As far as I can see it should be interesting for moderately big services with thousands of feeds. - Alex Kapranoff
How do you propose that Google Reader should implement this Atom streaming in such a way that it would preserve feed privacy? My PHP on shard hosting example is somewhat extreme, but PHP is actually very popular, as is Rails, which I think would also have some difficulty managing endless streams of updates. The SUP design is very much line with how everything else on the web works so that it can be implemented everywhere -- endless streams of Atom data are unique to a single site I believe. - Paul Buchheit
I don't see how abstracting the username by a layer is going to help privacy. It should be up to the feed publishers on how to handle privacy. They can and should offer better privacy controls than an abstraction. Based on what i've read about this so far, I could easily write a script to crawl flickr or twitter and get every single users id and link it to their SUP-ID. I put it on a different comment, but maybe a POLL verb for http would work. - Shawn McCollum
Shawn, The id abstraction prevents crawlers from discovering the URLs of private feeds using information in the SUP feed. - Gary Burd
Private feeds shouldn't be in the SUP Feed at all. Obfuscation as a security or privacy model doesn't prevent, it just delays the inevitable. The SUP protocol isn't going to be universally accepted and no matter what, your going to have to support feeds the current way. Handle private feeds normally since without authentication it's really just hidden not private. I like the way FF allows you to regenerate your api key, something like that should be used for private feeds rather then a id and password. - Shawn McCollum
But Shawn; the SUP ID in the private feed means nothing unless you know the feed it belongs to. And if you know the feed it belongs to then you deserve to know it (ie someone registered it with you). Private feeds and SUP get along just fine. I suppose you could add another layer on top by generating a unique SUP id for each feed for each client. So the SUP id only means something to the client who requested it. But that's a lot more work for the server generating the SUP feed. - Benjamin Golub
Shawn, the advantage of SUP is that private feeds can still be protected by whatever mechanism you choose (such as the FriendFeed remote key), but still feed update information into a public SUP feed because the SUP-ID is completely opaque. (you can't discover the SUP-ID unless you already have access to the feed) - Paul Buchheit
another thought - why re-invent? Did they look at www.sitemaps.org? - Dave Hodson
It doesn't mean nothing, it mean that there is something you don't know. I can do alot with "knowing I don't know something". - Shawn McCollum
I think the SUP-ID concept is interesting but over architecting a solution for a small subset of the issue your trying to solve. It's nice that SUP-ID works to limit the size and help with private feeds. You could also implement something like the base html tag for size. Then either separate private and public updates with the private ones using SUP-ID or use a marker to identify that the backend needs to go through an extra hoop on this one. - Shawn McCollum
"It doesn't mean nothing, it mean that there is something you don't know. I can do alot with "knowing I don't know something"." Fill your SUP feed with random bogus SUP ids and bogus data. Then there will be *a lot* you don't know (including how many accounts the service *actually* has). - Benjamin Golub
Shawn, can you give an example of something you could do, knowing that an unknown feed within OurDoings was updated at a specific time? I don't see the vulnerability here. This is a real question as I already implemented SUP. - Bruce Lewis via fftogo
Just so everyone knows, I'm not trolling and I love friendfeed. I have personal not professional interest in speeding up feed aggregation. Just chatting so... Loading up random data will have a negative effect on the size feature of SUP and will cause more processing to be done by the consumer of the feed. Bruce, I'll put something down to answer your question in a bit, but right now i've got to pick up my son from daycare. - Shawn McCollum
It's funny you mention Netflix personalized feeds indirectly in your blog post, Dare, as I'm not sure a basic SUP feed would work help much for our feeds. The personalized Netflix feeds generate generate about 6 million posts per day (about 2M each of queue adds, shipped DVDs and received DVDs). Given that any given feed consumer is likely only interested in a small fraction of the 8.4M+ subscribers, the signal-to-nose ratio in a SUP feed would be quite low, unless you created a SUP feed per consumer. - Michael Hart
Michael, SUP is intended for large feed consumers, not people monitoring one or two feeds. If you are doing 6 million feed updates per day, and your SUP feed compresses to about 8 bytes/entry (as the FriendFeed SUP does), then that works out to about 555 bytes/second (or 33k/minute). A compressed netflix feed appears to be about 22k, so the breakeven point is around 2000 feed fetches / day. For clients who poll feeds every half hour, that is only 45 unique feeds. For those that poll 1000s, it's a big win. - Paul Buchheit
Of course the math is different with if-modified-since, but from what I can tell netflix does not currently support that. Also, if you want to be a little more clever, the size of the SUP could be reduced substantially by only including info on feeds that have ever been fetched, since the majority of netflix feeds have never been accessed. You can also have separate SUP feeds for queue adds, shipped, and received, since some clients (such as FriendFeed) are only interested in one category (adds, in our case). - Paul Buchheit
And of course that's just the bandwidth savings. Using SUP would also reduce feed latency and the overall number of requests. - Paul Buchheit
Paul, drop me an email and we can take this discussion offline. We have some interesting feed improvements on the way in the very short term including ETag-based cache control and programmatic feed access behind OAuth to get rid of the copy/paste nonsense. You can reach me at mhart at netflix dot com - Michael Hart
It doesn't go far enough for me in terms of granularity. I'd like a way to decouple feed page sizes from updates, so you can know exactly the entries that are updated/new, not just the feeds. This would be fantastic for mobile apps. Right now it's about asking endpoints to support a 'since' parameter on the feed. I wonder if X-SUP-ID will go through mobile networks- what they do sometimes with HTTP is 'interesting'. - Bill de hÓra
“This may be a dumb question, but for RSS, what element does the SUP link element need to be a child of? If it's the channel element, is there a danger that dumb RSS readers will treat it like a regular link element?”
That's what we did: http://friendfeed.com/api/feed... Hopefully dumb RSS readers would ignore the link tag entirely since it's from Atom (and it's in the Atom namespace). If you encounter any issues with this, let me know. - Paul Buchheit
There's a non-atom link element in RSS 2.0 according to an example on http://search.yahoo.com/mrss so I'm going to be paranoid. I know there are programs out there that show even more ignorance about XML namespaces than I do. I'll just use the HTTP header. I notice your docs have it in all caps even though HTTP headers conventionally use initial caps...or is that because SUP and ID are acronyms? Anyway I went with all caps. - Bruce Lewis
“Seems like an interesting idea for taking sips from a firehose. Quick bug report: The 'available_periods' key in the sup.json feed lists URLs with /api/sup - which is a refreshingly RESTful / hypermedia-ish pattern, but they're all 404. These should probably be /api/sup.json”
Well, I wanted to share in fact the original Paul's entry where the discussion is taking place, but I don't seem to find a way to directly link to it. Sorry. - Alex Popescu
The "via Reshare" link points to the original entry, though clearly we need to make that link more discoverable. - Paul Buchheit
I think it would be valuable to have it stand clear, as without your hint it would have taken me a while. In fact, I was planning to look at the page source to extract the entry ID and post the link :-). - Alex Popescu
Paul - so YouTube would have in their SUP feed the X "recent" SUP IDs that have changed (due to X users clicking Favorite "recently"), and then for each SUP ID the consumer would know to map that back to a real RSS/Atom URL to do the actual fetch. Is that right? - Patrick Lightbody
If so, doesn't that mean that the client's understanding of "recent" needs to match that of the server's (ie: 3 minutes)? Otherwise I'd imagine you could end up with excessive polling for those SUP IDs that are in the SUP feed, right? - Patrick Lightbody
My understanding goes in the same direction. I suppose SUP would not be very useful in case there are lots of updates on the service side belonging to lots of different feeds. - Alex Popescu
It would be interesting if a 'protocol' would be created: client: 'can you please create a SUP for the following feeds', service:'here is your SUP', client: 'thanks. I'll GET it every 3m'. I'm afraid that this will need some kind of agreement between the services, but definitely both will benefit from it. - Alex Popescu
Gary - got it, thanks. I just looked at the FF SUP and saw the time periods as well. So that allows the client and server to sync their definition of "recent" and then of course be much more efficient. I like it - simple and effective! :) - Patrick Lightbody
Yes, I took the movie. I used the camera that I loaned to you and Ross for the whiteboard movie. @jbeda was also there. Here's his movie: http://www.youtube.com/watch?v... - Gary Burd
That is super cool! How close were you to the dolphins? Do they react to or avoid people? - Dan Hsiao
Some dolphins swam within 10 ft of me. I assume that the dolphins were curious about us because the dolphins swam to us. - Gary Burd
not entirely sure that the creation of a stable black hole would require earth saving intervention. but if i were an alien i'd definitely make out that it did - what does this tell us about kevin? - Alex Gawley
Huh? This is the kind of video my 15mo old would LOVE. (And, BTW, this is exactly the kind of truck that comes to our house every week) - Steve Lacy
hooked up my youtube to friendfeed and voila - you notice that my favorite YT videos are the ones I bookmarked b/c my kids like to see them (over and over) - peter
"For between £200 and £2,000, people can buy a cow that stands no taller than a large German shepherd dog, gives 16 pints of milk a day that can be drunk unpasteurised, keeps the grass “mown” and will be a family pet for years before ending up in the freezer." (via boing boing) - Joe Beda
Are mini cows better for the ozone layer? - Gary Burd
"Interestingly, Apple has pulled the push notification service in this release "for further development." The capability was announced at Apple's Worldwide Developer's Conference Keynote in response to requests for background process support for third party iPhone applications. Applications that deal with messaging (such as AIM or Facebook) would likely stand to gain the most from the SDK enhancement. Apple had promised a September delivery of the functionality." - Gary Burd via Bookmarklet
I want to assign a user a random number (lets say from 0 to 10,000) - but I want to make sure that it is a unique number, no other user has that number. Presumably I'm storing all taken numbers in a database. How do I most efficiently make sure a new number is a unique number? While the set is still sparse, I can just assign a number, and see if it is taken, and then try again until I find an untaken one. But as the set of all numbers approaches being full, this will approach 10,000 tries just to find that last untaken number. Is there a better way? - Shannon Bauman
Hm... thinking about this some more. Perhaps if I just stored all of the untaken items in a list (is that the right structure?)... then do a random role of rand(list.length()), and go to that spot in the list, and then use that number stored there, and remove it from the list. That may work. Not sure how that equates to a database though :-) - Shannon Bauman
Just talking to myself, don't mind me :-) I may have to just have a continuous process running that does the assigning of IDs, and always stores the unused numbers in it - and then just hit up that process whenever i need a new ID assigned. I could then add that number to the DB for bookkeeping, etc. (I need the resulting number stored in a DB for other reasons/Longevity). - Shannon Bauman
It sounds just like dealing with hash collisions... one easy approach is to pick a random number and then scan for the next available number after that (modulo table size). Linear scans should be fast if the database stores things in sorted order. - Jim Norris
@jim - yeah, that totally makes sense. Thanks! - Shannon Bauman
How about just using a larger number? (like perhaps 128bits) - Paul Buchheit
@paul (and jim) - I am actually trying to completely fill the namespace so to speak (or numberspace as the case may be in this case). I basically want to keep assigning people numbers as they come in the door until all 10,000 numbers have been taken, and then close the door. But ideally I would like to do the assigning out of order. Perhaps what I should do is just do the shuffle before hand all at once, and then assign them from first to last after they have been shuffled? - Shannon Bauman
By the way - it is pretty amazing for me to be able to post a CS question, and have the two smartest CS people I know on the planet be able to give feedback. Damn that's cool. - Shannon Bauman
I was just about to suggest pre-shuffling. Create a 10,000 item linked list, generate a random number from 1 to 10,000, pluck it from the linked list and add that number to an array table along with an auto-incrementing sequential ID. Then generate a random number from 1 to (10,000-N), and repeat until the list is gone and you have a table with IDs and random non-colliding numbers. Mind you, there may be a faster method than traversing a linked list each time, but if you're talking about 10,000 instead of 1,000,000 and you're not doing it often then it's probably more efficient to code it quickly than execute it quickly. - Kevin Fox
@Kevin: alternatively: put the N (10,000) numbers in an array A. At step i (for 0 <= i < N), swap element A[i] with A[j], where j is a random number such that i <= j < N. - Tudor Bosman
ff is now your one-stop shop for cheating on your homework. - j1m
@j1m a healthy discussion doesn't do any wrong. Even if it is HW, it is the effort that counts. - Akshay Dodeja
Tudor's method is the best (although I don't agree that j has to be constrained on the lower limit by i) and my understanding is that that's the method used for most card-dealing games to shuffle the deck. The only challenge is making sure your random number generator is really random. - Stephen Mack
Tudor's solution is simple and efficient. If you need a solution that takes even less memory, then you use a vector of booleans indexed by id to keep track of allocated ids. If each boolean is represented as a single bit, then the solution requires 1250 bytes for the 10,000 ids. - Gary Burd
Could you use a block cipher/Feistel network approach? That way, you'd only have to store the number you had last operated on and when you needed the next number, you could pass it through the block cipher to generate the next one. I believe the easier way to do it is on an even number of bits, so 2^14 = 16384 > 10000. Whenever the cipher generated a number > 10000, you could just feed that number back into the cipher until you got one that was less than 10000. - Josh
Do these non-sequential numbers have to be random, or is "random-looking" good enough? If so, pick a primitive root of 10007 (5 works), and then cycle through by multiplying mod 10007 (multiply again if you get a 5-digit numbers). While the numbers are deterministic, they may work good enough for your approach, and you can get a counter that will spit out non-sequential numbers. - Alex Power
So, you'll get 5, 25, 125, 625, 3125, 5618, 8076, 352, 1760, 8800, 3972, ... Not random, but good enough to fool most people. If you use a larger primitive root, you'll probably be OK regardless. - Alex Power
Pre-shuffling is the way to go. Fisher-Yates shuffle is easy to implement. - Neil Kandalgaonkar