From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Vetter Date: Wed, 21 Oct 2015 15:39:45 +0000 Subject: Re: [PATCH] drm: rcar-du: Perform initialization/cleanup at probe/remove time Message-Id: <20151021153945.GI16848@phenom.ffwll.local> List-Id: References: <1445295114-20921-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> <20151020073213.GP13786@phenom.ffwll.local> <2416796.7aKg1mPfX6@avalon> In-Reply-To: <2416796.7aKg1mPfX6@avalon> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: Laurent Pinchart Cc: Laurent Pinchart , dri-devel@lists.freedesktop.org, linux-sh@vger.kernel.org On Wed, Oct 21, 2015 at 06:16:08PM +0300, Laurent Pinchart wrote: > Hi Daniel, > > On Tuesday 20 October 2015 09:32:13 Daniel Vetter wrote: > > On Tue, Oct 20, 2015 at 01:51:54AM +0300, Laurent Pinchart wrote: > > > The drm driver .load() operation is prone to race conditions as it > > > initializes the driver after registering the device nodes. Its usage is > > > deprecated, inline it in the probe function and call drm_dev_alloc() and > > > drm_dev_register() explicitly. > > > > > > For consistency inline the .unload() handler in the remove function as > > > well. > > > > > > Signed-off-by: Laurent Pinchart > > > > > > --- > > > > > > drivers/gpu/drm/rcar-du/rcar_du_drv.c | 184 +++++++++++++----------- > > > drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | 11 +- > > > drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 11 +- > > > drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | 11 +- > > > 4 files changed, 104 insertions(+), 113 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c > > > b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index bebcc97db5e5..46d628752371 > > > 100644 > > > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c > > > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c > > [snip] > > > > -static int rcar_du_remove(struct platform_device *pdev) > > > +static int rcar_du_probe(struct platform_device *pdev) > > > { > > > - struct rcar_du_device *rcdu = platform_get_drvdata(pdev); > > > + struct device_node *np = pdev->dev.of_node; > > > + struct rcar_du_device *rcdu; > > > + struct drm_connector *connector; > > > + struct drm_device *ddev; > > > + struct resource *mem; > > > + int ret; > > > + > > > + if (np = NULL) { > > > + dev_err(&pdev->dev, "no device tree node\n"); > > > + return -ENODEV; > > > + } > > > + > > > + /* Allocate and initialize the DRM and R-Car device structures. */ > > > + rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL); > > > + if (rcdu = NULL) > > > + return -ENOMEM; > > > + > > > + init_waitqueue_head(&rcdu->commit.wait); > > > > > > - drm_put_dev(rcdu->ddev); > > > + rcdu->dev = &pdev->dev; > > > + rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; > > > + > > > + ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); > > > + if (!ddev) > > > + return -ENOMEM; > > > + > > > + rcdu->ddev = ddev; > > > + ddev->dev_private = rcdu; > > > + > > > + platform_set_drvdata(pdev, rcdu); > > > + > > > + /* I/O resources */ > > > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > > + rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem); > > > + if (IS_ERR(rcdu->mmio)) { > > > + ret = PTR_ERR(rcdu->mmio); > > > + goto error; > > > + } > > > + > > > + /* Initialize vertical blanking interrupts handling. Start with > vblank > > > + * disabled for all CRTCs. > > > + */ > > > + ret = drm_vblank_init(ddev, (1 << rcdu->info->num_crtcs) - 1); > > > + if (ret < 0) { > > > + dev_err(&pdev->dev, "failed to initialize vblank\n"); > > > + goto error; > > > + } > > > + > > > + /* DRM/KMS objects */ > > > + ret = rcar_du_modeset_init(rcdu); > > > + if (ret < 0) { > > > + dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret); > > > + goto error; > > > + } > > > + > > > + ddev->irq_enabled = 1; > > > + > > > + /* Register the DRM device with the core and the connectors with > > > + * sysfs. > > > + */ > > > + ret = drm_dev_register(ddev, 0); > > > + if (ret) > > > + goto error; > > > + > > > + mutex_lock(&ddev->mode_config.mutex); > > > + drm_for_each_connector(connector, ddev) { > > > + ret = drm_connector_register(connector); > > > + if (ret < 0) > > > + break; > > > + } > > > + mutex_unlock(&ddev->mode_config.mutex); > > > > I'm wondereding whether we shouldn't just wrap this up in a helper somehow, > > like drm_dev_modeset_register. > > How about drm_connector_plug_all() to match the existing > drm_connector_unplug_all() ? plug/unplug has for me a different meaning wrt connectors. And because of the MST problem I'd just leave this along really. > > Only trouble is that we might be racing with adding MST connectors already, > > and that's where I stopped thinking about it ;-) > > You'll have to brief me on the MST issue if you want my opinion on the matter > :-) MST can hot-add connectors, and we can do that as soon as we process hotplug events. Which is generally towards the end of the init sequence, but decidedly before drm_dev_register(). So a function which walks all connectors (even when holding relevant locks) could try to double-register a connector added through MST hotplug, leading to slight unpleasantries. But since this is hard I didn't think up an idea for how to address this. Since there's also the question whether the hotplug uevent will fare well before the drm_dev_register() call ... -Daniel > > > Anyway that aside aside: > > > > Acked-by: Daniel Vetter > > Thanks. > > > > + > > > + if (ret < 0) > > > + goto error; > > > + > > > + DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); > > > > > > return 0; > > > + > > > +error: > > > + rcar_du_remove(pdev); > > > + > > > + return ret; > > > > > > } > > -- > Regards, > > Laurent Pinchart > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Vetter Subject: Re: [PATCH] drm: rcar-du: Perform initialization/cleanup at probe/remove time Date: Wed, 21 Oct 2015 17:39:45 +0200 Message-ID: <20151021153945.GI16848@phenom.ffwll.local> References: <1445295114-20921-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> <20151020073213.GP13786@phenom.ffwll.local> <2416796.7aKg1mPfX6@avalon> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail-wi0-f177.google.com (mail-wi0-f177.google.com [209.85.212.177]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0EF236EE70 for ; Wed, 21 Oct 2015 08:39:50 -0700 (PDT) Received: by wikq8 with SMTP id q8so99611798wik.1 for ; Wed, 21 Oct 2015 08:39:48 -0700 (PDT) Content-Disposition: inline In-Reply-To: <2416796.7aKg1mPfX6@avalon> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Laurent Pinchart Cc: Laurent Pinchart , dri-devel@lists.freedesktop.org, linux-sh@vger.kernel.org List-Id: dri-devel@lists.freedesktop.org T24gV2VkLCBPY3QgMjEsIDIwMTUgYXQgMDY6MTY6MDhQTSArMDMwMCwgTGF1cmVudCBQaW5jaGFy dCB3cm90ZToKPiBIaSBEYW5pZWwsCj4gCj4gT24gVHVlc2RheSAyMCBPY3RvYmVyIDIwMTUgMDk6 MzI6MTMgRGFuaWVsIFZldHRlciB3cm90ZToKPiA+IE9uIFR1ZSwgT2N0IDIwLCAyMDE1IGF0IDAx OjUxOjU0QU0gKzAzMDAsIExhdXJlbnQgUGluY2hhcnQgd3JvdGU6Cj4gPiA+IFRoZSBkcm0gZHJp dmVyIC5sb2FkKCkgb3BlcmF0aW9uIGlzIHByb25lIHRvIHJhY2UgY29uZGl0aW9ucyBhcyBpdAo+ ID4gPiBpbml0aWFsaXplcyB0aGUgZHJpdmVyIGFmdGVyIHJlZ2lzdGVyaW5nIHRoZSBkZXZpY2Ug bm9kZXMuIEl0cyB1c2FnZSBpcwo+ID4gPiBkZXByZWNhdGVkLCBpbmxpbmUgaXQgaW4gdGhlIHBy b2JlIGZ1bmN0aW9uIGFuZCBjYWxsIGRybV9kZXZfYWxsb2MoKSBhbmQKPiA+ID4gZHJtX2Rldl9y ZWdpc3RlcigpIGV4cGxpY2l0bHkuCj4gPiA+IAo+ID4gPiBGb3IgY29uc2lzdGVuY3kgaW5saW5l IHRoZSAudW5sb2FkKCkgaGFuZGxlciBpbiB0aGUgcmVtb3ZlIGZ1bmN0aW9uIGFzCj4gPiA+IHdl bGwuCj4gPiA+IAo+ID4gPiBTaWduZWQtb2ZmLWJ5OiBMYXVyZW50IFBpbmNoYXJ0Cj4gPiA+IDxs YXVyZW50LnBpbmNoYXJ0K3JlbmVzYXNAaWRlYXNvbmJvYXJkLmNvbT4KPiA+ID4gLS0tCj4gPiA+ IAo+ID4gPiAgZHJpdmVycy9ncHUvZHJtL3JjYXItZHUvcmNhcl9kdV9kcnYuYyAgICAgfCAxODQg ICsrKysrKysrKysrKystLS0tLS0tLS0tLQo+ID4gPiAgZHJpdmVycy9ncHUvZHJtL3JjYXItZHUv cmNhcl9kdV9oZG1pY29uLmMgfCAgMTEgKy0KPiA+ID4gIGRyaXZlcnMvZ3B1L2RybS9yY2FyLWR1 L3JjYXJfZHVfbHZkc2Nvbi5jIHwgIDExICstCj4gPiA+ICBkcml2ZXJzL2dwdS9kcm0vcmNhci1k dS9yY2FyX2R1X3ZnYWNvbi5jICB8ICAxMSArLQo+ID4gPiAgNCBmaWxlcyBjaGFuZ2VkLCAxMDQg aW5zZXJ0aW9ucygrKSwgMTEzIGRlbGV0aW9ucygtKQo+ID4gPiAKPiA+ID4gZGlmZiAtLWdpdCBh L2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfZHJ2LmMKPiA+ID4gYi9kcml2ZXJzL2dw dS9kcm0vcmNhci1kdS9yY2FyX2R1X2Rydi5jIGluZGV4IGJlYmNjOTdkYjVlNS4uNDZkNjI4NzUy MzcxCj4gPiA+IDEwMDY0NAo+ID4gPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vcmNhci1kdS9yY2Fy X2R1X2Rydi5jCj4gPiA+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfZHJ2 LmMKPiAKPiBbc25pcF0KPiAKPiA+ID4gLXN0YXRpYyBpbnQgcmNhcl9kdV9yZW1vdmUoc3RydWN0 IHBsYXRmb3JtX2RldmljZSAqcGRldikKPiA+ID4gK3N0YXRpYyBpbnQgcmNhcl9kdV9wcm9iZShz dHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQo+ID4gPiAgewo+ID4gPiAtCXN0cnVjdCByY2Fy X2R1X2RldmljZSAqcmNkdSA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+ID4gPiArCXN0 cnVjdCBkZXZpY2Vfbm9kZSAqbnAgPSBwZGV2LT5kZXYub2Zfbm9kZTsKPiA+ID4gKwlzdHJ1Y3Qg cmNhcl9kdV9kZXZpY2UgKnJjZHU7Cj4gPiA+ICsJc3RydWN0IGRybV9jb25uZWN0b3IgKmNvbm5l Y3RvcjsKPiA+ID4gKwlzdHJ1Y3QgZHJtX2RldmljZSAqZGRldjsKPiA+ID4gKwlzdHJ1Y3QgcmVz b3VyY2UgKm1lbTsKPiA+ID4gKwlpbnQgcmV0Owo+ID4gPiArCj4gPiA+ICsJaWYgKG5wID09IE5V TEwpIHsKPiA+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAibm8gZGV2aWNlIHRyZWUgbm9kZVxu Iik7Cj4gPiA+ICsJCXJldHVybiAtRU5PREVWOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCS8q IEFsbG9jYXRlIGFuZCBpbml0aWFsaXplIHRoZSBEUk0gYW5kIFItQ2FyIGRldmljZSBzdHJ1Y3R1 cmVzLiAqLwo+ID4gPiArCXJjZHUgPSBkZXZtX2t6YWxsb2MoJnBkZXYtPmRldiwgc2l6ZW9mKCpy Y2R1KSwgR0ZQX0tFUk5FTCk7Cj4gPiA+ICsJaWYgKHJjZHUgPT0gTlVMTCkKPiA+ID4gKwkJcmV0 dXJuIC1FTk9NRU07Cj4gPiA+ICsKPiA+ID4gKwlpbml0X3dhaXRxdWV1ZV9oZWFkKCZyY2R1LT5j b21taXQud2FpdCk7Cj4gPiA+IAo+ID4gPiAtCWRybV9wdXRfZGV2KHJjZHUtPmRkZXYpOwo+ID4g PiArCXJjZHUtPmRldiA9ICZwZGV2LT5kZXY7Cj4gPiA+ICsJcmNkdS0+aW5mbyA9IG9mX21hdGNo X2RldmljZShyY2FyX2R1X29mX3RhYmxlLCByY2R1LT5kZXYpLT5kYXRhOwo+ID4gPiArCj4gPiA+ ICsJZGRldiA9IGRybV9kZXZfYWxsb2MoJnJjYXJfZHVfZHJpdmVyLCAmcGRldi0+ZGV2KTsKPiA+ ID4gKwlpZiAoIWRkZXYpCj4gPiA+ICsJCXJldHVybiAtRU5PTUVNOwo+ID4gPiArCj4gPiA+ICsJ cmNkdS0+ZGRldiA9IGRkZXY7Cj4gPiA+ICsJZGRldi0+ZGV2X3ByaXZhdGUgPSByY2R1Owo+ID4g PiArCj4gPiA+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgcmNkdSk7Cj4gPiA+ICsKPiA+ ID4gKwkvKiBJL08gcmVzb3VyY2VzICovCj4gPiA+ICsJbWVtID0gcGxhdGZvcm1fZ2V0X3Jlc291 cmNlKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAwKTsKPiA+ID4gKwlyY2R1LT5tbWlvID0gZGV2bV9p b3JlbWFwX3Jlc291cmNlKCZwZGV2LT5kZXYsIG1lbSk7Cj4gPiA+ICsJaWYgKElTX0VSUihyY2R1 LT5tbWlvKSkgewo+ID4gPiArCQlyZXQgPSBQVFJfRVJSKHJjZHUtPm1taW8pOwo+ID4gPiArCQln b3RvIGVycm9yOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCS8qIEluaXRpYWxpemUgdmVydGlj YWwgYmxhbmtpbmcgaW50ZXJydXB0cyBoYW5kbGluZy4gU3RhcnQgd2l0aCAKPiB2YmxhbmsKPiA+ ID4gKwkgKiBkaXNhYmxlZCBmb3IgYWxsIENSVENzLgo+ID4gPiArCSAqLwo+ID4gPiArCXJldCA9 IGRybV92YmxhbmtfaW5pdChkZGV2LCAoMSA8PCByY2R1LT5pbmZvLT5udW1fY3J0Y3MpIC0gMSk7 Cj4gPiA+ICsJaWYgKHJldCA8IDApIHsKPiA+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiZmFp bGVkIHRvIGluaXRpYWxpemUgdmJsYW5rXG4iKTsKPiA+ID4gKwkJZ290byBlcnJvcjsKPiA+ID4g Kwl9Cj4gPiA+ICsKPiA+ID4gKwkvKiBEUk0vS01TIG9iamVjdHMgKi8KPiA+ID4gKwlyZXQgPSBy Y2FyX2R1X21vZGVzZXRfaW5pdChyY2R1KTsKPiA+ID4gKwlpZiAocmV0IDwgMCkgewo+ID4gPiAr CQlkZXZfZXJyKCZwZGV2LT5kZXYsICJmYWlsZWQgdG8gaW5pdGlhbGl6ZSBEUk0vS01TICglZClc biIsIHJldCk7Cj4gPiA+ICsJCWdvdG8gZXJyb3I7Cj4gPiA+ICsJfQo+ID4gPiArCj4gPiA+ICsJ ZGRldi0+aXJxX2VuYWJsZWQgPSAxOwo+ID4gPiArCj4gPiA+ICsJLyogUmVnaXN0ZXIgdGhlIERS TSBkZXZpY2Ugd2l0aCB0aGUgY29yZSBhbmQgdGhlIGNvbm5lY3RvcnMgd2l0aAo+ID4gPiArCSAq IHN5c2ZzLgo+ID4gPiArCSAqLwo+ID4gPiArCXJldCA9IGRybV9kZXZfcmVnaXN0ZXIoZGRldiwg MCk7Cj4gPiA+ICsJaWYgKHJldCkKPiA+ID4gKwkJZ290byBlcnJvcjsKPiA+ID4gKwo+ID4gPiAr CW11dGV4X2xvY2soJmRkZXYtPm1vZGVfY29uZmlnLm11dGV4KTsKPiA+ID4gKwlkcm1fZm9yX2Vh Y2hfY29ubmVjdG9yKGNvbm5lY3RvciwgZGRldikgewo+ID4gPiArCQlyZXQgPSBkcm1fY29ubmVj dG9yX3JlZ2lzdGVyKGNvbm5lY3Rvcik7Cj4gPiA+ICsJCWlmIChyZXQgPCAwKQo+ID4gPiArCQkJ YnJlYWs7Cj4gPiA+ICsJfQo+ID4gPiArCW11dGV4X3VubG9jaygmZGRldi0+bW9kZV9jb25maWcu bXV0ZXgpOwo+ID4gCj4gPiBJJ20gd29uZGVyZWRpbmcgd2hldGhlciB3ZSBzaG91bGRuJ3QganVz dCB3cmFwIHRoaXMgdXAgaW4gYSBoZWxwZXIgc29tZWhvdywKPiA+IGxpa2UgZHJtX2Rldl9tb2Rl c2V0X3JlZ2lzdGVyLgo+IAo+IEhvdyBhYm91dCBkcm1fY29ubmVjdG9yX3BsdWdfYWxsKCkgdG8g bWF0Y2ggdGhlIGV4aXN0aW5nIAo+IGRybV9jb25uZWN0b3JfdW5wbHVnX2FsbCgpID8KCnBsdWcv dW5wbHVnIGhhcyBmb3IgbWUgYSBkaWZmZXJlbnQgbWVhbmluZyB3cnQgY29ubmVjdG9ycy4gQW5k IGJlY2F1c2Ugb2YKdGhlIE1TVCBwcm9ibGVtIEknZCBqdXN0IGxlYXZlIHRoaXMgYWxvbmcgcmVh bGx5LgoKPiA+IE9ubHkgdHJvdWJsZSBpcyB0aGF0IHdlIG1pZ2h0IGJlIHJhY2luZyB3aXRoIGFk ZGluZyBNU1QgY29ubmVjdG9ycyBhbHJlYWR5LAo+ID4gYW5kIHRoYXQncyB3aGVyZSBJIHN0b3Bw ZWQgdGhpbmtpbmcgYWJvdXQgaXQgOy0pCj4gCj4gWW91J2xsIGhhdmUgdG8gYnJpZWYgbWUgb24g dGhlIE1TVCBpc3N1ZSBpZiB5b3Ugd2FudCBteSBvcGluaW9uIG9uIHRoZSBtYXR0ZXIgCj4gOi0p CgpNU1QgY2FuIGhvdC1hZGQgY29ubmVjdG9ycywgYW5kIHdlIGNhbiBkbyB0aGF0IGFzIHNvb24g YXMgd2UgcHJvY2Vzcwpob3RwbHVnIGV2ZW50cy4gV2hpY2ggaXMgZ2VuZXJhbGx5IHRvd2FyZHMg dGhlIGVuZCBvZiB0aGUgaW5pdCBzZXF1ZW5jZSwKYnV0IGRlY2lkZWRseSBiZWZvcmUgZHJtX2Rl dl9yZWdpc3RlcigpLgoKU28gYSBmdW5jdGlvbiB3aGljaCB3YWxrcyBhbGwgY29ubmVjdG9ycyAo ZXZlbiB3aGVuIGhvbGRpbmcgcmVsZXZhbnQKbG9ja3MpIGNvdWxkIHRyeSB0byBkb3VibGUtcmVn aXN0ZXIgYSBjb25uZWN0b3IgYWRkZWQgdGhyb3VnaCBNU1QgaG90cGx1ZywKbGVhZGluZyB0byBz bGlnaHQgdW5wbGVhc2FudHJpZXMuCgpCdXQgc2luY2UgdGhpcyBpcyBoYXJkIEkgZGlkbid0IHRo aW5rIHVwIGFuIGlkZWEgZm9yIGhvdyB0byBhZGRyZXNzIHRoaXMuClNpbmNlIHRoZXJlJ3MgYWxz byB0aGUgcXVlc3Rpb24gd2hldGhlciB0aGUgaG90cGx1ZyB1ZXZlbnQgd2lsbCBmYXJlIHdlbGwK YmVmb3JlIHRoZSBkcm1fZGV2X3JlZ2lzdGVyKCkgY2FsbCAuLi4KLURhbmllbAoKCj4gCj4gPiBB bnl3YXkgdGhhdCBhc2lkZSBhc2lkZToKPiA+IAo+ID4gQWNrZWQtYnk6IERhbmllbCBWZXR0ZXIg PGRhbmllbC52ZXR0ZXJAZmZ3bGwuY2g+Cj4gCj4gVGhhbmtzLgo+IAo+ID4gPiArCj4gPiA+ICsJ aWYgKHJldCA8IDApCj4gPiA+ICsJCWdvdG8gZXJyb3I7Cj4gPiA+ICsKPiA+ID4gKwlEUk1fSU5G TygiRGV2aWNlICVzIHByb2JlZFxuIiwgZGV2X25hbWUoJnBkZXYtPmRldikpOwo+ID4gPiAKPiA+ ID4gIAlyZXR1cm4gMDsKPiA+ID4gKwo+ID4gPiArZXJyb3I6Cj4gPiA+ICsJcmNhcl9kdV9yZW1v dmUocGRldik7Cj4gPiA+ICsKPiA+ID4gKwlyZXR1cm4gcmV0Owo+ID4gPiAKPiA+ID4gIH0KPiAK PiAtLSAKPiBSZWdhcmRzLAo+IAo+IExhdXJlbnQgUGluY2hhcnQKPiAKCi0tIApEYW5pZWwgVmV0 dGVyClNvZnR3YXJlIEVuZ2luZWVyLCBJbnRlbCBDb3Jwb3JhdGlvbgpodHRwOi8vYmxvZy5mZnds bC5jaApfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpkcmkt ZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cDov L2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo=