929 karma · joined March 29, 2011
The code is open source and available at https://github.com/rdwallis/MagicScrollWebReader if you want to have a poke at it.
I haven't started promoting it yet because of a bug in incognito mode but it's available at:
https://chrome.google.com/webstore/detail/magicscroll-web-re...
https://chrome.google.com/webstore/detail/magicscroll-web-re...
https://groups.google.com/forum/?hl=en&fromgroups#!forum...
They'll email you when issues occur and info becomes available.
It took about 30 minutes after the crash for me to receive an email which seems very reasonable.
I think it'll need to hit a critical mass before it's useful. People don't expect SSID's to have useful information so they don't look for it there.
I'm on a very slow connection and it's much faster to do a git push than to deploy a compiled application.
You're right about the flat number / street number situation though. It might be good to add that to the SSID as well.
Loud music seems like a perfect use case for the information.
Phone numbers are unique and let others contact you if they want to use your wifi for some reason. Would probably help neighbors get hold of each other in emergencies as well.
There's a lot of peace of mind in knowing that my users' passwords won't ever end up on pastebin but overall I regret the decision.
I get a couple of emails a week from users who don't understand how it works. If I had to do over I'd choose openID.
I epoxied the motherboard mount from an old computer case to some wood and then stuck the wood to the inside of a cheap fish tank. I installed the computer sans harddrive and then poured in 12 liters of mineral oil that I'd bought from a vet (Vet's use it as a horse laxative).
It resulted in a perfectly silent system but because I didn't cover the top it was also a really effective fly trap. Within a few months there were a bunch of dead flies floating at the top of the tank. Also the weight made it a real effort to move around and no matter how careful I was there was always a mess when I needed to swap out or adjust a part.
Still it was a lot of fun to build and I used it as my primary machine for about a year.
private final long creationTime = System.currentTimeMillis();
so it still has advantages over making the field a Date object.
You don't expose the underlying long value publicly so you end up with something like the following:
private long primitiveDate;
public Date getDate() { return new Date(primitiveDate); }
-----
This prevents calling methods from doing something stupid like:
o.getDate().setTime(123455L)
to modify a date that shouldn't be editable.
I may just be hitting a lot of outlier samples but Google Java projects seem antagonistic to Maven (I've used GWT, GAE and GData). GData's really bad; see comments at: http://code.google.com/p/gdata-java-client/wiki/Dependencies
I'd never have ended up using GWT if I'd tried it first as a mavenized project. But GWT itself is a really beautiful toolset and I'm sad to see it abandoned because of a weakness in one area. It's really frustrating that that weakness is probably the first thing that a whole bunch of people will run into when trying it out.
Also if you don't have to use GXT, don't. It is rubbish.
I think the most significant problem with the example books is not their position on the page but the couple of second delay before they appear. I'll definitely fix this in the next few days.
As for caching the example books in the background. It would be nice to do and I'll think about the problem for the next few days but I think it may be be extremely difficult based on the current design.
Edit: Thought on it a bit more. It may be possible to cache the contents of the example book but not the processing of the book. I suspect that the major part of the load delay comes from processing rather than downloading but it'll probably be worth it anyway.
---
I think MagicScroll's doing pretty well in terms of uptake but I don't have any kind of tracking implemented yet so I'm a bit blind.
I've got just over 6000 users from the Chrome Web Store.
https://chrome.google.com/webstore/detail/ghgnmgfdoiplfmhggh...
On my server logs I get between 700 and 900 hits to my cache manifest file every 24 hours with more over the weekend. As near as I can tell users turn a books page an average of just less than 400 times an hour. (Each page turn involves a round trip to the server for syncing purposes). More than 95% of the hits are coming from Chrome so I think there's a lot of room to expand.
---
I didn't build MagicScroll as a commercial venture but based on its limited popularity I do think it has the potential to create revenue, and I now hope to build a business around it. In the next month or so I plan to create a paid extension similar to Readability that will allow websites to be read using MagicScroll. I also intend to build an API for booksellers to allow MagicScroll to be integrated into their stores. If MagicScroll does gain a significant number of users I hope to integrate my own ebook store into it but I think that will be in a year or twos time at the earliest.
---
For those of you interested in the programming side. It is built in GWT and runs on the Google App Engine. I'm embarrassed to say that I don't have any real knowledge of javascript though I'm trying to rectify that. There are about 30 lines of native javascript in the project most of which facilates communication between the frame that holds the book and the UI.
The entire project is heavily cached and apart from unzipping the ePUB and some security logic everything happens clientside. There are obviously a lot of advantages to this and it was quite easy to do because I was working in GWT. In fact I found that the same logic on the client often runs significantly faster than it does on the App Engine server.
To do page rendering I'm using a very simple binary search. I draw a page with a certain number of characters and if it overflows I draw it half the size and then half between that and so on. It's quick but I have no idea how Google has managed to get their pages in Google Books to render so fast, or to change the font size without redrawing.
One thing I've perhaps overrelyed on is AsyncCallbacks here's part of the code that draws the book:
LoadDialog.get().show("Loading Book. Stage 2 of 3");
init(eacKey, new DelayedCallback<Void>(new SimpleCallback<Void>(){
@Override
public void onSuccess(Void result) {
resize();
LoadDialog.get().show("Loading Book. Stage 3 of 3");
PageRendererFrame.addEPubStyleSheets(new DelayedCallback<Void>(new SimpleCallback<Void>(){
@Override
public void onSuccess(Void result) {
SettingsWidget.get(new SimpleCallback<SettingsWidget>() {
@Override
public void onSuccess(final SettingsWidget settingsWidget) {
PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentColors().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {
@Override
public void onSuccess(Void result) {
PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentFont().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {
@Override
public void onSuccess(Void result) {
PageRendererFrame.showPage(new DelayedCallback<Void>(new SimpleCallback<Void>() {
@Override
public void onSuccess(Void result) {
hider.removeFromParent();
preventDraw = false;
callback.onSuccess(null);
}
}));
}
}));
}
}));
}
});
}
}));
}
}));
The DelayedCallback works like a normal callback but introduces a 1 millisecond delay to avoid the browser from thinking the code has frozen. SimpleCallback is just like AsyncCallback but without the onFailure method. If an exception occurs the program halts instead of recovering.
I made it so that whenever an uncaught exception occurs I get emailed about it. This has massively increased my stress levels but I think its contributed to the stability of the code so I'll probably do the same in the future. I now get less than 20 errors a day. Mostly if someone tries to use MagicScroll with IE7 or if they try to read an encrypted book.Anyway thanks for letting me ramble, I'm interested to know what HN thinks.