@Override
    public Widget asWidget() {
        if (fp == null) {

            final Storage storage = Storage.getLocalStorageIfSupported();
            if (storage == null) {
                new MessageBox("Not Supported", "Your browser doesn't appear to supprt HTML5 localStorage").show();
                return new HTML("LocalStorage not supported in this browser");
            }

            // Writer to translate load config into string
            UrlEncodingWriter<PhotoLoadConfig> writer = new UrlEncodingWriter<PhotoLoadConfig>(TestAutoBeanFactory.instance, PhotoLoadConfig.class);
            // Reader to translate String results into objects
            JsonReader<PhotoListLoadResult, PhotoCollection> reader = new JsonReader<PhotoListLoadResult, PhotoCollection>(
                    TestAutoBeanFactory.instance, PhotoCollection.class) {
                @Override
                protected PhotoListLoadResult createReturnData(Object loadConfig, PhotoCollection records) {
                    PagingLoadConfig cfg = (PagingLoadConfig) loadConfig;
                    PhotoListLoadResult res = TestAutoBeanFactory.instance.dataLoadResult().as();
                    res.setData(records.getTopics());
                    res.setOffset(cfg.getOffset());
                    res.setTotalLength(records.getTotalCount());
                    return res;
                }
            };

            // Proxy to load from server
            String url = "/photo/getPhotosList.json";
            RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
            final HttpProxy<PhotoLoadConfig> remoteProxy = new HttpProxy<PhotoLoadConfig>(builder);
            remoteProxy.setWriter(writer);

            // Proxy to load objects from local storage
            final StorageReadProxy<PhotoLoadConfig> localReadProxy = new StorageReadProxy<PhotoLoadConfig>(storage);
            localReadProxy.setWriter(writer);

            // Proxy to persist network-loaded objects into local storage
            final StorageWriteProxy<PhotoLoadConfig, String> localWriteProxy = new StorageWriteProxy<PhotoLoadConfig, String>(storage);
            localWriteProxy.setKeyWriter(writer);

            // Wrapper Proxy to dispatch to either storage or scripttag, and to save results
            DataProxy<PhotoLoadConfig, String> proxy = new DataProxy<PhotoLoadConfig, String>() {
                @Override
                public void load(final PhotoLoadConfig loadConfig, final Callback<String, Throwable> callback) {
                    // Storage read is known to be synchronous, so read it first - if null, continue
                    localReadProxy.load(loadConfig, new Callback<String, Throwable>() {
                        @Override
                        public void onFailure(Throwable reason) {
                            // ignore failure, go remote
                            onSuccess(null);
                        }

                        @Override
                        public void onSuccess(String result) {
                            if (result != null) {
                                callback.onSuccess(result);
                            } else {
                                //read from remote and save it
                                remoteProxy.load(loadConfig, new Callback<String, Throwable>() {
                                    @Override
                                    public void onSuccess(String result) {
                                        Entry<PhotoLoadConfig, String> data = new Entry<PhotoLoadConfig, String>(loadConfig, result);
                                        localWriteProxy.load(data, new Callback<Void, Throwable>() {
                                            @Override
                                            public void onSuccess(Void result) {
                                                // ignore response
                                            }

                                            @Override
                                            public void onFailure(Throwable reason) {
                                                // ignore response
                                            }
                                        });
                                        callback.onSuccess(result);
                                    }

                                    @Override
                                    public void onFailure(Throwable reason) {
                                        callback.onFailure(reason);
                                    }
                                });
                            }
                        }
                    });
                }
            };


            PagingLoader<PhotoLoadConfig, PhotoListLoadResult> loader = new PagingLoader<PhotoLoadConfig, PhotoListLoadResult>(
                    proxy, reader);
            loader.useLoadConfig(TestAutoBeanFactory.instance.loadConfig().as());

            PhotoProperties props = GWT.create(PhotoProperties.class);

            ListStore<Photo> store = new ListStore<Photo>(props.key());
            loader.addLoadHandler(new LoadResultListStoreBinding<PhotoLoadConfig, Photo, PhotoListLoadResult>(store));

            ColumnConfig<Photo, String> cc1 = new ColumnConfig<Photo, String>(props.title(), 100, "Title");
            ColumnConfig<Photo, String> cc2 = new ColumnConfig<Photo, String>(props.ownername(), 100, "Owner Name");
            ColumnConfig<Photo, String> cc3 = new ColumnConfig<Photo, String>(props.views(), 100, "Views");
            ColumnConfig<Photo, Date> cc4 = new ColumnConfig<Photo, Date>(props.dateupload(), 100, "Date Upload");
            cc4.setCell(new DateCell());
            ColumnConfig<Photo, Date> cc5 = new ColumnConfig<Photo, Date>(props.dateupload(), 100, "Last Update");
            cc5.setCell(new DateCell());
            ColumnConfig<Photo, String> cc6 = new ColumnConfig<Photo, String>(props.url_sq(), 100, "Photo");
            cc6.setCell(new ImageCell());

            List<ColumnConfig<Photo, ?>> l = new ArrayList<ColumnConfig<Photo, ?>>();
            l.add(cc1);
            l.add(cc2);
            l.add(cc3);
            l.add(cc4);
            l.add(cc5);
            l.add(cc6);
            ColumnModel<Photo> cm = new ColumnModel<Photo>(l);

            Grid<Photo> grid = new Grid<Photo>(store, cm);
            grid.getView().setForceFit(true);
            grid.setLoader(loader);
            grid.setLoadMask(true);
            grid.setBorders(true);

            final PagingToolBar toolBar = new PagingToolBar(10);
            toolBar.getElement().getStyle().setProperty("borderBottom", "none");
            toolBar.add(new TextButton("Clear Cache", new SelectHandler() {
                @Override
                public void onSelect(SelectEvent event) {
                    storage.clear();
                }
            }));
            toolBar.bind(loader);

            fp = new FramedPanel();
            fp.setHeadingText("LocalStorage Grid Example");
            fp.setCollapsible(true);
            fp.setAnimCollapse(true);
            fp.setWidth("100%");
            fp.setHeight(500);

            fp.addStyleName("margin-10");
            fp.setButtonAlign(BoxLayoutPack.CENTER);

            VerticalLayoutContainer con = new VerticalLayoutContainer();
            con.setBorders(true);
            con.add(grid, new VerticalLayoutData(1, 1));
            con.add(toolBar, new VerticalLayoutData(1, -1));
            fp.setWidget(con);

            loader.load();
        }
        return fp;
    }