My phone is faster than my first PC, and faster than my first cable modem

Recent Photos

 

RT : I just pushed 3.1.0 with full support for iOS 4.1 and GameKit/GameCenter.
 

Simon say’s MonoTouch scrolling like iPhone home screen in C#

One of the most popular user experiences on the iPhone is the home screen and how you can slide “pages” into view with all the snappy behaviors. Luckily with the UIScrollViewer control and MonoTouch this is all super simple to implement.

I am going to show you how to put a UIScrollViewer on your view and populate it with 10 labels that will be used for 10 views of which we can scroll. In a real world application you could construct anything you wish in these 10 pages. You could even load new views, with view controller’s.

In a resource hungry application, if these views are too heavy to populate fully, you could easily lazy-load them. You would do this by loading the page previous to the current page, and the page after the current page. This way when you scroll they are visible and as you move pages, pages are dynamically loaded.

In this tutorial we will stay simple with labels to get the points across on what is needed to make this technique work.

We will put the index number on the label as well as alternating colour’s of red and blue to easily see our scrolling. Let’s get started!

First double click your .xib file of the view you wish edit and Interface Builder will be launched. Drag a Scroll Viewer and Page Control on to your view.

SampleScrollViewer-01

Create both a scrollView and pageControl IBOutlet on your AppDelegate  or ViewController depending on what view you are editing.

SampleScrollViewer-02

Connect the 2 IBOutlet’s to the actual controls.

SampleScrollViewer-03

Enable paging on the Scroll Viewer. This will give the Scroll Viewer the snap effect the home screen has. Disable horizontal and vertical to hide the scroll bars.

SampleScrollViewer-04

In our AppDelegate or ViewController we are going to create a new method called CreatePanels. This method will populate our Scroll Viewer with 10 items that we can drag our finger to slide into view like the home screen.

We use the Scroll Viewer’s frame to calculate how big each label should be to consume the entire visible area of the Scroll Viewer. We position all of the views that go in the Scroll Viewer with Scroll Viewer width * the counter.

private void CreatePanels()
{
    scrollView.Scrolled += ScrollViewScrolled;

    int count = 10;
    RectangleF scrollFrame = scrollView.Frame;
    scrollFrame.Width = scrollFrame.Width * count;
    scrollView.ContentSize = scrollFrame.Size;

    for (int i=0; i<count; i++)
    {
        UILabel label = new UILabel();
        label.TextColor = UIColor.Black;
        label.TextAlignment = UITextAlignment.Center;
        label.Text = i.ToString();

        if (i % 2 == 0)
            label.BackgroundColor = UIColor.Red;
        else
            label.BackgroundColor = UIColor.Blue;

        RectangleF frame = scrollView.Frame;
        PointF location = new PointF();
        location.X = frame.Width * i;

        frame.Location = location;
        label.Frame = frame;

        scrollView.AddSubview(label);
    }

    pageControl.Pages = count;
}

The Page Control is used to allow us to display to the user which page we are currently viewing in the Scroll Viewer. We use the event we hooked up above to alter the current page on the Page Control when the Scroll Viewer is scrolled to a new “page”. The page control is the same control you see on the home screen which displays the little white dots indicating which page you are looking at.

private void ScrollViewScrolled (object sender, EventArgs e)
{
    double page = Math.Floor((scrollView.ContentOffset.X - scrollView.Frame.Width / 2) / scrollView.Frame.Width) + 1;

    pageControl.CurrentPage = (int)page;
}

And there we have it. A user interface that behaves exactly as the home screen scrolling effect!

Please retweet and feel free to follow me @simongui on Twitter at http://www.twitter.com/simongui

SampleScrollViewer-05

This website uses IntenseDebate comments, but they are not currently loaded because either your browser doesn't support JavaScript, or they didn't load fast enough.

9 Responses to “Simon say’s MonoTouch scrolling like iPhone home screen in C#”

  1. Alex York 21 September 2009 at 6:38 am #

    Very nice! A good simple example too with no clutter. Keep it up.

  2. CraigD 22 September 2009 at 11:43 am #

    Simon, I think the UIPageControl can also change the view (by a touch to the left or right ends of the dots). This seems to work in the Simulator with the following code addition (in FinishedLaunching):

    pageControl.ValueChanged += delegate(object sender, EventArgs e) {
    var pc = (UIPageControl)sender;
    double fromPage = Math.Floor((scrollView.ContentOffset.X – scrollView.Frame.Width / 2) / scrollView.Frame.Width) + 1;
    var toPage = pc.CurrentPage;
    var pageOffset = scrollView.ContentOffset.X + scrollView.Frame.Width;
    Console.WriteLine("fromPage " + fromPage + " toPage " + toPage);
    if (fromPage > toPage)
    pageOffset = scrollView.ContentOffset.X – scrollView.Frame.Width;
    PointF p = new PointF(pageOffset, 0);
    scrollView.SetContentOffset(p,true);
    };

  3. Russell 19 October 2009 at 9:27 am #

    I did everything you said, and it is showing this error.

    error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'

    PLZ HELP

  4. Hwoof 15 January 2010 at 12:51 am #

    Thanks for this demo – superb – helped me a lot (plus also the tip from Craig – that will allow me to do lazy loading of views – much appreciated!)

  5. huseyin 17 March 2010 at 4:02 pm #

    Can we apply only using mono too? not monotouch?

  6. Aaron Williams 4 April 2010 at 10:42 am #

    Thanks for the example!

  7. superyeti420 6 April 2010 at 8:28 am #

    Hi Guys, great example. I made a small change to the button code, if you were pressing the buttons really quickly you could get the event to fire more than once at the last page. it was being calculated based on the current offset which caused issues, i changed it to use the page# * page width to get the correct display all the time. Include this code in the FinishedLoading method.

    pageControl.ValueChanged += delegate(object sender, EventArgs e) {
    var pc = (UIPageControl)sender;
    double fromPage = Math.Floor((scrollView.ContentOffset.X – scrollView.Frame.Width / 2) / scrollView.Frame.Width) + 1;
    var toPage = pc.CurrentPage;
    var pageOffset = scrollView.Frame.Width*toPage;
    Console.WriteLine("fromPage " + fromPage + " toPage " + toPage);
    PointF p = new PointF(pageOffset, 0);
    scrollView.SetContentOffset(p,true);
    };

  8. Appan 2 May 2010 at 10:04 am #

    hi, shal u provide information of fast scrolling (through mouse wheel or key board) on our own user controls created in c#. control created by painting. scrolling action is available but not as fast as apple iphone scrolling.please provide information

  9. lucas 16 May 2010 at 2:08 pm #

    is there anyplace to download the complete xcode project? i am new and i am needing to see some of the connections. or, please email a zip file of the project to slucas@iquanta.com. thank you in advance.


Leave a Reply

 
PHVsPjxsaT48c3Ryb25nPndvb19hYm91dDwvc3Ryb25nPiAtIFNvZnR3YXJlIERldmVsb3BlciwgZ2FkZ2V0IGdlZWsgYW5kIG1vYmlsaXR5IGp1bmt5LjwvbGk+PGxpPjxzdHJvbmc+d29vX2Fib3V0bGluazwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Fib3V0X2J1dHRvbjwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Fib3V0X2hlYWRlcjwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Fib3V0X3Bob3RvPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fYWJvdXRfdGV4dDwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Fkczwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fYWRfMzAwX2Fkc2Vuc2U8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19hZF8zMDBfaW1hZ2U8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzLzMwMHgyNTBhLmpwZzwvbGk+PGxpPjxzdHJvbmc+d29vX2FkXzMwMF91cmw8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF9jb250ZW50PC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19hZF9jb250ZW50X2Fkc2Vuc2U8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19hZF9jb250ZW50X2ltYWdlPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy83Mjh4OTBhLmpwZzwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2NvbnRlbnRfdXJsPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fYWRfZm9vdGVyPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19hZF9mb290ZXJfYWRzZW5zZTwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2Zvb3Rlcl9pbWFnZTwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTQ2OHg2MC0yLmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2Zvb3Rlcl91cmw8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF9oZWFkZXI8L3N0cm9uZz4gLSBmYWxzZTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2hlYWRlcl9jb2RlPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fYWRfaGVhZGVyX2ltYWdlPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy80Njh4NjBhLmpwZzwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2hlYWRlcl91cmw8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV8xPC9zdHJvbmc+IC0gaHR0cDovL3NpbW9uLm51cmVhbGl0eS5jYS93cC1jb250ZW50L2Fkcy9hZC0xMjV4MTI1LmpwZzwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2ltYWdlXzI8L3N0cm9uZz4gLSBodHRwOi8vc2ltb24ubnVyZWFsaXR5LmNhL3dwLWNvbnRlbnQvYWRzL2FkLTEyNXgxMjUuanBnPC9saT48bGk+PHN0cm9uZz53b29fYWRfaW1hZ2VfMzwvc3Ryb25nPiAtIGh0dHA6Ly9zaW1vbi5udXJlYWxpdHkuY2Evd3AtY29udGVudC9hZHMvYWQtMTI1eDEyNS5qcGc8L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV80PC9zdHJvbmc+IC0gaHR0cDovL3NpbW9uLm51cmVhbGl0eS5jYS93cC1jb250ZW50L2Fkcy9hZC0xMjV4MTI1LmpwZzwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3RvcDwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fYWRfdG9wX2Fkc2Vuc2U8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19hZF90b3BfaW1hZ2U8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzLzQ2OHg2MGEuanBnPC9saT48bGk+PHN0cm9uZz53b29fYWRfdG9wX3VybDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8xPC9zdHJvbmc+IC0gaHR0cDovL2V4YW1wbGUuY29tL2Fkcy9hZDFfZGVzdGluYXRpb24uaHRtbDwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8yPC9zdHJvbmc+IC0gaHR0cDovL2V4YW1wbGUuY29tL2Fkcy9hZDFfZGVzdGluYXRpb24uaHRtbDwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8zPC9zdHJvbmc+IC0gaHR0cDovL2V4YW1wbGUuY29tL2Fkcy9hZDFfZGVzdGluYXRpb24uaHRtbDwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF80PC9zdHJvbmc+IC0gaHR0cDovL2V4YW1wbGUuY29tL2Fkcy9hZDFfZGVzdGluYXRpb24uaHRtbDwvbGk+PGxpPjxzdHJvbmc+d29vX2FsdF9jb2xvdXJzPC9zdHJvbmc+IC0gZGVmYXVsdC5jc3M8L2xpPjxsaT48c3Ryb25nPndvb19hbHRfc3R5bGVzaGVldDwvc3Ryb25nPiAtIGNsZWFuLWxpZ2h0LmNzczwvbGk+PGxpPjxzdHJvbmc+d29vX2FyY2hpdmVzPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fYXNpZGVzX2NhdGVnb3J5PC9zdHJvbmc+IC0gU2VsZWN0IGEgY2F0ZWdvcnk6PC9saT48bGk+PHN0cm9uZz53b29fYXNpZGVzX2VudHJpZXM8L3N0cm9uZz4gLSBTZWxlY3QgYSBudW1iZXI6PC9saT48bGk+PHN0cm9uZz53b29fYXV0b19pbWc8L3N0cm9uZz4gLSBmYWxzZTwvbGk+PGxpPjxzdHJvbmc+d29vX2Jpbzwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Jsb2dfY2F0PC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fYmxvZ19uYXZpZ2F0aW9uPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19ibG9nX3Blcm1hbGluazwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Jsb2dfc3VibmF2aWdhdGlvbjwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fYnV0dG9uX2xpbms8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19jYXRfYm94XzE8L3N0cm9uZz4gLSBmYWxzZTwvbGk+PGxpPjxzdHJvbmc+d29vX2NhdF9ib3hfMV9pbWFnZTwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2NhdF9jb2xvcl8xPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fY2F0X25hdl8xPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19jYXRfbmF2XzEwPC9zdHJvbmc+IC0gdHJ1ZTwvbGk+PGxpPjxzdHJvbmc+d29vX2NhdF9uYXZfMTY8L3N0cm9uZz4gLSB0cnVlPC9saT48bGk+PHN0cm9uZz53b29fY2F0X25hdl8xNzwvc3Ryb25nPiAtIHRydWU8L2xpPjxsaT48c3Ryb25nPndvb19jYXRfbmF2XzE4PC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19jYXRfbmF2XzIxPC9zdHJvbmc+IC0gdHJ1ZTwvbGk+PGxpPjxzdHJvbmc+d29vX2NhdF9uYXZfMjI8L3N0cm9uZz4gLSBmYWxzZTwvbGk+PGxpPjxzdHJvbmc+d29vX2NhdF9uYXZfMzwvc3Ryb25nPiAtIHRydWU8L2xpPjxsaT48c3Ryb25nPndvb19jb250YWN0bWU8L3N0cm9uZz4gLSBTZWxlY3QgYSBwYWdlOjwvbGk+PGxpPjxzdHJvbmc+d29vX2N1c3RvbV9jc3M8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19jdXN0b21fZmF2aWNvbjwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2RlbGljaW91czwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2RpZ2c8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19mYWNlYm9vazwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlYXR1cmVkX3Bvc3RzPC9zdHJvbmc+IC0gU2VsZWN0IGEgbnVtYmVyOjwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlZWRidXJuZXJfaWQ8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19mZWVkYnVybmVyX3VybDwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZsaWNrcjwvc3Ryb25nPiAtIDQxMjY1ODU3QE4wNDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZsaWNrcl9pZDwvc3Ryb25nPiAtIDQxMjY1ODU3QE4wNDwvbGk+PGxpPjxzdHJvbmc+d29vX2dvb2dsZV9hbmFseXRpY3M8L3N0cm9uZz4gLSA8c2NyaXB0IHR5cGU9XCJ0ZXh0L2phdmFzY3JpcHRcIj4NCnZhciBnYUpzSG9zdCA9ICgoXCJodHRwczpcIiA9PSBkb2N1bWVudC5sb2NhdGlvbi5wcm90b2NvbCkgPyBcImh0dHBzOi8vc3NsLlwiIDogXCJodHRwOi8vd3d3LlwiKTsNCmRvY3VtZW50LndyaXRlKHVuZXNjYXBlKFwiJTNDc2NyaXB0IHNyYz1cJ1wiICsgZ2FKc0hvc3QgKyBcImdvb2dsZS1hbmFseXRpY3MuY29tL2dhLmpzXCcgdHlwZT1cJ3RleHQvamF2YXNjcmlwdFwnJTNFJTNDL3NjcmlwdCUzRVwiKSk7DQo8L3NjcmlwdD4NCjxzY3JpcHQgdHlwZT1cInRleHQvamF2YXNjcmlwdFwiPg0KdHJ5ew0KdmFyIHBhZ2VUcmFja2VyID0gX2dhdC5fZ2V0VHJhY2tlcihcIlVBLTczNDg5NDMtMlwiKTsNCnBhZ2VUcmFja2VyLl90cmFja1BhZ2V2aWV3KCk7DQp9IGNhdGNoKGVycikge308L3NjcmlwdD48L2xpPjxsaT48c3Ryb25nPndvb19ncmF2YXRhcjwvc3Ryb25nPiAtIHRydWU8L2xpPjxsaT48c3Ryb25nPndvb19sYXN0Zm08L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19sYXlvdXQ8L3N0cm9uZz4gLSBoZWFkZXItYWx0LnBocDwvbGk+PGxpPjxzdHJvbmc+d29vX2xpbmtlZGluPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fbG9nbzwvc3Ryb25nPiAtIGh0dHA6Ly9zaW1vbi5udXJlYWxpdHkuY2Evd3AtY29udGVudC93b29fdXBsb2Fkcy80LWxvZ28ucG5nPC9saT48bGk+PHN0cm9uZz53b29fbWFudWFsPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL3N1cHBvcnQvdGhlbWUtZG9jdW1lbnRhdGlvbi90aGljay88L2xpPjxsaT48c3Ryb25nPndvb19uYXZfZXhjbHVkZTwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX290aGVyX2VudHJpZXM8L3N0cm9uZz4gLSAxMDwvbGk+PGxpPjxzdHJvbmc+d29vX3Bvc3Rfc2l6ZTwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fcmVzaXplPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19zY3JvbGxlcl9wb3N0czwvc3Ryb25nPiAtIFNlbGVjdCBhIG51bWJlcjo8L2xpPjxsaT48c3Ryb25nPndvb19zaG9ydG5hbWU8L3N0cm9uZz4gLSB3b288L2xpPjxsaT48c3Ryb25nPndvb19zaWRlYmFyX2FkX2hyZWZfMTwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX3NpZGViYXJfYWRfaHJlZl8yPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fc2lkZWJhcl9hZF9ocmVmXzM8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19zaWRlYmFyX2FkX2hyZWZfNDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX3NpZGViYXJfYWRfaW1nXzE8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTEuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fc2lkZWJhcl9hZF9pbWdfMjwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTEyNXgxMjUtMi5naWY8L2xpPjxsaT48c3Ryb25nPndvb19zaWRlYmFyX2FkX2ltZ18zPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy93b290aGVtZXMtMTI1eDEyNS0zLmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX3NpZGViYXJfYWRfaW1nXzQ8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTQuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fc2lkZV9pbWFnZTwvc3Ryb25nPiAtIGh0dHA6Ly9zaW1vbi5udXJlYWxpdHkuY2Evd3AtY29udGVudC9hZHMvYWQtMTIweDI0MC5qcGc8L2xpPjxsaT48c3Ryb25nPndvb19zaWRlX3VybDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX3NpbmdsZV90aHVtYjwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fc3R1bWJsZTwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX3RleHRsb2dvPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb190aGVtZW5hbWU8L3N0cm9uZz4gLSBUSGlDSzwvbGk+PGxpPjxzdHJvbmc+d29vX3R3aXR0ZXI8L3N0cm9uZz4gLSBzaW1vbmd1aTwvbGk+PGxpPjxzdHJvbmc+d29vX3VwbG9hZHM8L3N0cm9uZz4gLSBhOjI6e2k6MDtzOjU5OiJodHRwOi8vc2ltb24ubnVyZWFsaXR5LmNhL3dwLWNvbnRlbnQvd29vX3VwbG9hZHMvNC1sb2dvLnBuZyI7aToxO3M6NTk6Imh0dHA6Ly9zaW1vbi5udXJlYWxpdHkuY2Evd3AtY29udGVudC93b29fdXBsb2Fkcy8zLWxvZ28ucG5nIjt9PC9saT48bGk+PHN0cm9uZz53b29feW91dHViZTwvc3Ryb25nPiAtIDwvbGk+PC91bD4=