From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jeff Layton Subject: Re: [PATCH v23 19/22] richacl: Add richacl xattr handler Date: Tue, 12 Jul 2016 08:13:30 -0400 Message-ID: <1468325610.7798.23.camel@redhat.com> References: <1467294433-3222-1-git-send-email-agruenba@redhat.com> <1467294433-3222-20-git-send-email-agruenba@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: Christoph Hellwig , Theodore Ts'o , Andreas Dilger , "J. Bruce Fields" , Trond Myklebust , Anna Schumaker , Dave Chinner , linux-ext4@vger.kernel.org, xfs@oss.sgi.com, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-api@vger.kernel.org To: Andreas Gruenbacher , Alexander Viro Return-path: In-Reply-To: <1467294433-3222-20-git-send-email-agruenba@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-Id: linux-cifs.vger.kernel.org On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote: > Add richacl xattr handler implementing the xattr operations based on = the > get_richacl and set_richacl inode operations. >=20 > Signed-off-by: Andreas Gruenbacher > --- > =C2=A0fs/richacl.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0| 22 +++++++++= +++++++ > =C2=A0fs/richacl_xattr.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0| 61 +++++++++++++++++++++++++++++++++++++++= ++++ > =C2=A0include/linux/richacl.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= |=C2=A0=C2=A01 + > =C2=A0include/linux/richacl_xattr.h |=C2=A0=C2=A02 ++ > =C2=A04 files changed, 86 insertions(+) >=20 > diff --git a/fs/richacl.c b/fs/richacl.c > index 40e4af9..b7d7104 100644 > --- a/fs/richacl.c > +++ b/fs/richacl.c > @@ -549,6 +549,28 @@ out: > =C2=A0EXPORT_SYMBOL_GPL(richacl_permission); > =C2=A0 > =C2=A0/** > + * set_richacl=C2=A0=C2=A0-=C2=A0=C2=A0set the richacl of an inode > + * @inode: inode whose richacl to set > + * @acl: access control list > + */ > +int > +set_richacl(struct inode *inode, struct richacl *acl) > +{ > + if (!IS_RICHACL(inode)) > + return -EOPNOTSUPP; > + if (!inode->i_op->set_richacl) > + return -EOPNOTSUPP; > + > + if (!uid_eq(current_fsuid(), inode->i_uid) && > + =C2=A0=C2=A0=C2=A0=C2=A0inode_permission(inode, MAY_CHMOD) && > + =C2=A0=C2=A0=C2=A0=C2=A0!capable(CAP_FOWNER)) > + return -EPERM; > + > + return inode->i_op->set_richacl(inode, acl); > +} > +EXPORT_SYMBOL(set_richacl); > + > +/** > =C2=A0 * __richacl_chmod=C2=A0=C2=A0-=C2=A0=C2=A0update the file mask= s to reflect the new mode > =C2=A0 * @acl: access control list > =C2=A0 * @mode: new file permission bits including the file type > diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c > index dc1ad36..5eb4aba 100644 > --- a/fs/richacl_xattr.c > +++ b/fs/richacl_xattr.c > @@ -18,7 +18,9 @@ > =C2=A0#include=20 > =C2=A0#include=20 > =C2=A0#include=20 > +#include=20 > =C2=A0#include=20 > +#include=20 > =C2=A0 > =C2=A0/** > =C2=A0 * richacl_from_xattr=C2=A0=C2=A0-=C2=A0=C2=A0convert a richacl= xattr into the in-memory representation > @@ -159,3 +161,62 @@ richacl_to_xattr(struct user_namespace *user_ns, > =C2=A0 return real_size; > =C2=A0} > =C2=A0EXPORT_SYMBOL_GPL(richacl_to_xattr); > + > +static bool > +richacl_xattr_list(struct dentry *dentry) > +{ > + return IS_RICHACL(d_backing_inode(dentry)); > +} > + > +static int > +richacl_xattr_get(const struct xattr_handler *handler, > + =C2=A0=C2=A0struct dentry *unused, struct inode *inode, > + =C2=A0=C2=A0const char *name, void *buffer, size_t buffer_size) > +{ > + struct richacl *acl; > + int error; > + > + if (*name) > + return -EINVAL; > + if (!IS_RICHACL(inode)) > + return -EOPNOTSUPP; > + if (S_ISLNK(inode->i_mode)) > + return -EOPNOTSUPP; > + acl =3D get_richacl(inode); > + if (IS_ERR(acl)) > + return PTR_ERR(acl); > + if (acl =3D=3D NULL) > + return -ENODATA; > + error =3D richacl_to_xattr(current_user_ns(), acl, buffer, buffer_s= ize); > + richacl_put(acl); > + return error; > +} > + > +static int > +richacl_xattr_set(const struct xattr_handler *handler, > + =C2=A0=C2=A0struct dentry *unused, struct inode *inode, > + =C2=A0=C2=A0const char *name, const void *value, size_t size, > + =C2=A0=C2=A0int flags) > +{ > + struct richacl *acl =3D NULL; > + int ret; > + > + if (value) { > + acl =3D richacl_from_xattr(current_user_ns(), value, size, > + =C2=A0-EINVAL); > + if (IS_ERR(acl)) > + return PTR_ERR(acl); > + } > + > + ret =3D set_richacl(inode, acl); > + richacl_put(acl); > + return ret; > +} > + > +struct xattr_handler richacl_xattr_handler =3D { > + .name =3D XATTR_NAME_RICHACL, > + .list =3D richacl_xattr_list, > + .get =3D richacl_xattr_get, > + .set =3D richacl_xattr_set, > +}; > +EXPORT_SYMBOL(richacl_xattr_handler); > diff --git a/include/linux/richacl.h b/include/linux/richacl.h > index a442372..e7db066 100644 > --- a/include/linux/richacl.h > +++ b/include/linux/richacl.h > @@ -206,5 +206,6 @@ extern int richacl_chmod(struct inode *, umode_t)= ; > =C2=A0extern int richacl_equiv_mode(const struct richacl *, umode_t *= ); > =C2=A0extern struct richacl *richacl_inherit(const struct richacl *, = int); > =C2=A0extern struct richacl *richacl_create(umode_t *, struct inode *= ); > +extern int set_richacl(struct inode *, struct richacl *); > =C2=A0 > =C2=A0#endif /* __RICHACL_H */ > diff --git a/include/linux/richacl_xattr.h b/include/linux/richacl_xa= ttr.h > index 0efa14b..6c6adb1 100644 > --- a/include/linux/richacl_xattr.h > +++ b/include/linux/richacl_xattr.h > @@ -26,4 +26,6 @@ extern size_t richacl_xattr_size(const struct richa= cl *); > =C2=A0extern int richacl_to_xattr(struct user_namespace *, const stru= ct richacl *, > =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0void *, size_t); > =C2=A0 > +extern struct xattr_handler richacl_xattr_handler; > + > =C2=A0#endif /* __RICHACL_XATTR_H */ Cue same refrain about syscalls vs. xattrs. Otherwise: Reviewed-by: Jeff Layton From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from relay.sgi.com (relay1.corp.sgi.com [137.38.102.111]) by oss.sgi.com (Postfix) with ESMTP id 4C38E7CB3 for ; Tue, 12 Jul 2016 07:13:36 -0500 (CDT) Received: from cuda.sgi.com (cuda3.sgi.com [192.48.176.15]) by relay1.corp.sgi.com (Postfix) with ESMTP id 0FDAA8F8039 for ; Tue, 12 Jul 2016 05:13:35 -0700 (PDT) Received: from mail-qk0-f170.google.com (mail-qk0-f170.google.com [209.85.220.170]) by cuda.sgi.com with ESMTP id 0VJ0MXzLvCC9uZOU (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO) for ; Tue, 12 Jul 2016 05:13:34 -0700 (PDT) Received: by mail-qk0-f170.google.com with SMTP id o67so11413565qke.1 for ; Tue, 12 Jul 2016 05:13:34 -0700 (PDT) Message-ID: <1468325610.7798.23.camel@redhat.com> Subject: Re: [PATCH v23 19/22] richacl: Add richacl xattr handler From: Jeff Layton Date: Tue, 12 Jul 2016 08:13:30 -0400 In-Reply-To: <1467294433-3222-20-git-send-email-agruenba@redhat.com> References: <1467294433-3222-1-git-send-email-agruenba@redhat.com> <1467294433-3222-20-git-send-email-agruenba@redhat.com> Mime-Version: 1.0 List-Id: XFS Filesystem from SGI List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: xfs-bounces@oss.sgi.com Sender: xfs-bounces@oss.sgi.com To: Andreas Gruenbacher , Alexander Viro Cc: "J. Bruce Fields" , linux-nfs@vger.kernel.org, Theodore Ts'o , linux-cifs@vger.kernel.org, linux-api@vger.kernel.org, Trond Myklebust , linux-kernel@vger.kernel.org, xfs@oss.sgi.com, Christoph Hellwig , Andreas Dilger , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org, Anna Schumaker T24gVGh1LCAyMDE2LTA2LTMwIGF0IDE1OjQ3ICswMjAwLCBBbmRyZWFzIEdydWVuYmFjaGVyIHdy b3RlOgo+IEFkZCByaWNoYWNsIHhhdHRyIGhhbmRsZXIgaW1wbGVtZW50aW5nIHRoZSB4YXR0ciBv cGVyYXRpb25zIGJhc2VkIG9uIHRoZQo+IGdldF9yaWNoYWNsIGFuZCBzZXRfcmljaGFjbCBpbm9k ZSBvcGVyYXRpb25zLgo+IAo+IFNpZ25lZC1vZmYtYnk6IEFuZHJlYXMgR3J1ZW5iYWNoZXIgPGFn cnVlbmJhQHJlZGhhdC5jb20+Cj4gLS0tCj4gwqBmcy9yaWNoYWNsLmPCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqB8IDIyICsrKysrKysrKysrKysrKysKPiDCoGZzL3JpY2hhY2xf eGF0dHIuY8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHwgNjEgKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKwo+IMKgaW5jbHVkZS9saW51eC9yaWNoYWNsLmjCoMKgwqDC oMKgwqDCoHzCoMKgMSArCj4gwqBpbmNsdWRlL2xpbnV4L3JpY2hhY2xfeGF0dHIuaCB8wqDCoDIg KysKPiDCoDQgZmlsZXMgY2hhbmdlZCwgODYgaW5zZXJ0aW9ucygrKQo+IAo+IGRpZmYgLS1naXQg YS9mcy9yaWNoYWNsLmMgYi9mcy9yaWNoYWNsLmMKPiBpbmRleCA0MGU0YWY5Li5iN2Q3MTA0IDEw MDY0NAo+IC0tLSBhL2ZzL3JpY2hhY2wuYwo+ICsrKyBiL2ZzL3JpY2hhY2wuYwo+IEBAIC01NDks NiArNTQ5LDI4IEBAIG91dDoKPiDCoEVYUE9SVF9TWU1CT0xfR1BMKHJpY2hhY2xfcGVybWlzc2lv bik7Cj4gwqAKPiDCoC8qKgo+ICsgKiBzZXRfcmljaGFjbMKgwqAtwqDCoHNldCB0aGUgcmljaGFj bCBvZiBhbiBpbm9kZQo+ICsgKiBAaW5vZGU6CWlub2RlIHdob3NlIHJpY2hhY2wgdG8gc2V0Cj4g KyAqIEBhY2w6CWFjY2VzcyBjb250cm9sIGxpc3QKPiArICovCj4gK2ludAo+ICtzZXRfcmljaGFj bChzdHJ1Y3QgaW5vZGUgKmlub2RlLCBzdHJ1Y3QgcmljaGFjbCAqYWNsKQo+ICt7Cj4gKwlpZiAo IUlTX1JJQ0hBQ0woaW5vZGUpKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCWlmICghaW5v ZGUtPmlfb3AtPnNldF9yaWNoYWNsKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlp ZiAoIXVpZF9lcShjdXJyZW50X2ZzdWlkKCksIGlub2RlLT5pX3VpZCkgJiYKPiArCcKgwqDCoMKg aW5vZGVfcGVybWlzc2lvbihpbm9kZSwgTUFZX0NITU9EKSAmJgo+ICsJwqDCoMKgwqAhY2FwYWJs ZShDQVBfRk9XTkVSKSkKPiArCQlyZXR1cm4gLUVQRVJNOwo+ICsKPiArCXJldHVybiBpbm9kZS0+ aV9vcC0+c2V0X3JpY2hhY2woaW5vZGUsIGFjbCk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChzZXRf cmljaGFjbCk7Cj4gKwo+ICsvKioKPiDCoCAqIF9fcmljaGFjbF9jaG1vZMKgwqAtwqDCoHVwZGF0 ZSB0aGUgZmlsZSBtYXNrcyB0byByZWZsZWN0IHRoZSBuZXcgbW9kZQo+IMKgICogQGFjbDoJYWNj ZXNzIGNvbnRyb2wgbGlzdAo+IMKgICogQG1vZGU6CW5ldyBmaWxlIHBlcm1pc3Npb24gYml0cyBp bmNsdWRpbmcgdGhlIGZpbGUgdHlwZQo+IGRpZmYgLS1naXQgYS9mcy9yaWNoYWNsX3hhdHRyLmMg Yi9mcy9yaWNoYWNsX3hhdHRyLmMKPiBpbmRleCBkYzFhZDM2Li41ZWI0YWJhIDEwMDY0NAo+IC0t LSBhL2ZzL3JpY2hhY2xfeGF0dHIuYwo+ICsrKyBiL2ZzL3JpY2hhY2xfeGF0dHIuYwo+IEBAIC0x OCw3ICsxOCw5IEBACj4gwqAjaW5jbHVkZSAKPiDCoCNpbmNsdWRlIAo+IMKgI2luY2x1ZGUgCj4g KyNpbmNsdWRlIAo+IMKgI2luY2x1ZGUgCj4gKyNpbmNsdWRlIAo+IMKgCj4gwqAvKioKPiDCoCAq IHJpY2hhY2xfZnJvbV94YXR0csKgwqAtwqDCoGNvbnZlcnQgYSByaWNoYWNsIHhhdHRyIGludG8g dGhlIGluLW1lbW9yeSByZXByZXNlbnRhdGlvbgo+IEBAIC0xNTksMyArMTYxLDYyIEBAIHJpY2hh Y2xfdG9feGF0dHIoc3RydWN0IHVzZXJfbmFtZXNwYWNlICp1c2VyX25zLAo+IMKgCXJldHVybiBy ZWFsX3NpemU7Cj4gwqB9Cj4gwqBFWFBPUlRfU1lNQk9MX0dQTChyaWNoYWNsX3RvX3hhdHRyKTsK PiArCj4gK3N0YXRpYyBib29sCj4gK3JpY2hhY2xfeGF0dHJfbGlzdChzdHJ1Y3QgZGVudHJ5ICpk ZW50cnkpCj4gK3sKPiArCXJldHVybiBJU19SSUNIQUNMKGRfYmFja2luZ19pbm9kZShkZW50cnkp KTsKPiArfQo+ICsKPiArc3RhdGljIGludAo+ICtyaWNoYWNsX3hhdHRyX2dldChjb25zdCBzdHJ1 Y3QgeGF0dHJfaGFuZGxlciAqaGFuZGxlciwKPiArCQnCoMKgc3RydWN0IGRlbnRyeSAqdW51c2Vk LCBzdHJ1Y3QgaW5vZGUgKmlub2RlLAo+ICsJCcKgwqBjb25zdCBjaGFyICpuYW1lLCB2b2lkICpi dWZmZXIsIHNpemVfdCBidWZmZXJfc2l6ZSkKPiArewo+ICsJc3RydWN0IHJpY2hhY2wgKmFjbDsK PiArCWludCBlcnJvcjsKPiArCj4gKwlpZiAoKm5hbWUpCj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4g KwlpZiAoIUlTX1JJQ0hBQ0woaW5vZGUpKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCWlm IChTX0lTTE5LKGlub2RlLT5pX21vZGUpKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCWFj bCA9IGdldF9yaWNoYWNsKGlub2RlKTsKPiArCWlmIChJU19FUlIoYWNsKSkKPiArCQlyZXR1cm4g UFRSX0VSUihhY2wpOwo+ICsJaWYgKGFjbCA9PSBOVUxMKQo+ICsJCXJldHVybiAtRU5PREFUQTsK PiArCWVycm9yID0gcmljaGFjbF90b194YXR0cihjdXJyZW50X3VzZXJfbnMoKSwgYWNsLCBidWZm ZXIsIGJ1ZmZlcl9zaXplKTsKPiArCXJpY2hhY2xfcHV0KGFjbCk7Cj4gKwlyZXR1cm4gZXJyb3I7 Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQKPiArcmljaGFjbF94YXR0cl9zZXQoY29uc3Qgc3RydWN0 IHhhdHRyX2hhbmRsZXIgKmhhbmRsZXIsCj4gKwkJwqDCoHN0cnVjdCBkZW50cnkgKnVudXNlZCwg c3RydWN0IGlub2RlICppbm9kZSwKPiArCQnCoMKgY29uc3QgY2hhciAqbmFtZSwgY29uc3Qgdm9p ZCAqdmFsdWUsIHNpemVfdCBzaXplLAo+ICsJCcKgwqBpbnQgZmxhZ3MpCj4gK3sKPiArCXN0cnVj dCByaWNoYWNsICphY2wgPSBOVUxMOwo+ICsJaW50IHJldDsKPiArCj4gKwlpZiAodmFsdWUpIHsK PiArCQlhY2wgPSByaWNoYWNsX2Zyb21feGF0dHIoY3VycmVudF91c2VyX25zKCksIHZhbHVlLCBz aXplLAo+ICsJCQkJCcKgLUVJTlZBTCk7Cj4gKwkJaWYgKElTX0VSUihhY2wpKQo+ICsJCQlyZXR1 cm4gUFRSX0VSUihhY2wpOwo+ICsJfQo+ICsKPiArCXJldCA9IHNldF9yaWNoYWNsKGlub2RlLCBh Y2wpOwo+ICsJcmljaGFjbF9wdXQoYWNsKTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0 cnVjdCB4YXR0cl9oYW5kbGVyIHJpY2hhY2xfeGF0dHJfaGFuZGxlciA9IHsKPiArCS5uYW1lID0g WEFUVFJfTkFNRV9SSUNIQUNMLAo+ICsJLmxpc3QgPSByaWNoYWNsX3hhdHRyX2xpc3QsCj4gKwku Z2V0ID0gcmljaGFjbF94YXR0cl9nZXQsCj4gKwkuc2V0ID0gcmljaGFjbF94YXR0cl9zZXQsCj4g K307Cj4gK0VYUE9SVF9TWU1CT0wocmljaGFjbF94YXR0cl9oYW5kbGVyKTsKPiBkaWZmIC0tZ2l0 IGEvaW5jbHVkZS9saW51eC9yaWNoYWNsLmggYi9pbmNsdWRlL2xpbnV4L3JpY2hhY2wuaAo+IGlu ZGV4IGE0NDIzNzIuLmU3ZGIwNjYgMTAwNjQ0Cj4gLS0tIGEvaW5jbHVkZS9saW51eC9yaWNoYWNs LmgKPiArKysgYi9pbmNsdWRlL2xpbnV4L3JpY2hhY2wuaAo+IEBAIC0yMDYsNSArMjA2LDYgQEAg ZXh0ZXJuIGludCByaWNoYWNsX2NobW9kKHN0cnVjdCBpbm9kZSAqLCB1bW9kZV90KTsKPiDCoGV4 dGVybiBpbnQgcmljaGFjbF9lcXVpdl9tb2RlKGNvbnN0IHN0cnVjdCByaWNoYWNsICosIHVtb2Rl X3QgKik7Cj4gwqBleHRlcm4gc3RydWN0IHJpY2hhY2wgKnJpY2hhY2xfaW5oZXJpdChjb25zdCBz dHJ1Y3QgcmljaGFjbCAqLCBpbnQpOwo+IMKgZXh0ZXJuIHN0cnVjdCByaWNoYWNsICpyaWNoYWNs X2NyZWF0ZSh1bW9kZV90ICosIHN0cnVjdCBpbm9kZSAqKTsKPiArZXh0ZXJuIGludCBzZXRfcmlj aGFjbChzdHJ1Y3QgaW5vZGUgKiwgc3RydWN0IHJpY2hhY2wgKik7Cj4gwqAKPiDCoCNlbmRpZiAv KiBfX1JJQ0hBQ0xfSCAqLwo+IGRpZmYgLS1naXQgYS9pbmNsdWRlL2xpbnV4L3JpY2hhY2xfeGF0 dHIuaCBiL2luY2x1ZGUvbGludXgvcmljaGFjbF94YXR0ci5oCj4gaW5kZXggMGVmYTE0Yi4uNmM2 YWRiMSAxMDA2NDQKPiAtLS0gYS9pbmNsdWRlL2xpbnV4L3JpY2hhY2xfeGF0dHIuaAo+ICsrKyBi L2luY2x1ZGUvbGludXgvcmljaGFjbF94YXR0ci5oCj4gQEAgLTI2LDQgKzI2LDYgQEAgZXh0ZXJu IHNpemVfdCByaWNoYWNsX3hhdHRyX3NpemUoY29uc3Qgc3RydWN0IHJpY2hhY2wgKik7Cj4gwqBl eHRlcm4gaW50IHJpY2hhY2xfdG9feGF0dHIoc3RydWN0IHVzZXJfbmFtZXNwYWNlICosIGNvbnN0 IHN0cnVjdCByaWNoYWNsICosCj4gwqAJCQnCoMKgwqDCoHZvaWQgKiwgc2l6ZV90KTsKPiDCoAo+ ICtleHRlcm4gc3RydWN0IHhhdHRyX2hhbmRsZXIgcmljaGFjbF94YXR0cl9oYW5kbGVyOwo+ICsK PiDCoCNlbmRpZiAvKiBfX1JJQ0hBQ0xfWEFUVFJfSCAqLwoKQ3VlIHNhbWUgcmVmcmFpbiBhYm91 dCBzeXNjYWxscyB2cy4geGF0dHJzLiBPdGhlcndpc2U6CgpSZXZpZXdlZC1ieTogSmVmZiBMYXl0 b24gPGpsYXl0b25AcmVkaGF0LmNvbT4KCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fCnhmcyBtYWlsaW5nIGxpc3QKeGZzQG9zcy5zZ2kuY29tCmh0dHA6Ly9v c3Muc2dpLmNvbS9tYWlsbWFuL2xpc3RpbmZvL3hmcwo=