vendor: bump containerd/continuity

This is to include the Go 1.11 fix
(https://github.com/containerd/continuity/pull/120).
Again (see c64a2448d1).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin 2018-08-27 13:31:02 -07:00
parent 09921ca33f
commit bac67204e1
27 changed files with 107 additions and 571 deletions

View file

@ -117,7 +117,7 @@ google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
# containerd
github.com/containerd/containerd v1.2.0-beta.2
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/containerd/continuity c7c5070e6f6e090ab93b0a61eb921f2196fc3383
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031

View file

@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"github.com/containerd/continuity/devices"
@ -26,18 +25,6 @@ func (d *driver) Mkfifo(path string, mode os.FileMode) error {
return devices.Mknod(path, mode, 0, 0)
}
// Lchmod changes the mode of an file not following symlinks.
func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
if !filepath.IsAbs(path) {
path, err = filepath.Abs(path)
if err != nil {
return
}
}
return sysx.Fchmodat(0, path, uint32(mode), sysx.AtSymlinkNofollow)
}
// Getxattr returns all of the extended attributes for the file at path p.
func (d *driver) Getxattr(p string) (map[string][]byte, error) {
xattrs, err := sysx.Listxattr(p)

View file

@ -0,0 +1,19 @@
package driver
import (
"os"
"golang.org/x/sys/unix"
)
// Lchmod changes the mode of a file not following symlinks.
func (d *driver) Lchmod(path string, mode os.FileMode) error {
// On Linux, file mode is not supported for symlinks,
// and fchmodat() does not support AT_SYMLINK_NOFOLLOW,
// so symlinks need to be skipped entirely.
if st, err := os.Stat(path); err == nil && st.Mode()&os.ModeSymlink != 0 {
return nil
}
return unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), 0)
}

View file

@ -0,0 +1,14 @@
// +build darwin freebsd solaris
package driver
import (
"os"
"golang.org/x/sys/unix"
)
// Lchmod changes the mode of a file not following symlinks.
func (d *driver) Lchmod(path string, mode os.FileMode) error {
return unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
}

View file

@ -10,8 +10,8 @@ type Usage struct {
// DiskUsage counts the number of inodes and disk usage for the resources under
// path.
func DiskUsage(roots ...string) (Usage, error) {
return diskUsage(roots...)
func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
return diskUsage(ctx, roots...)
}
// DiffUsage counts the numbers of inodes and disk usage in the

View file

@ -24,7 +24,7 @@ func newInode(stat *syscall.Stat_t) inode {
}
}
func diskUsage(roots ...string) (Usage, error) {
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
var (
size int64
@ -37,6 +37,12 @@ func diskUsage(roots ...string) (Usage, error) {
return err
}
select {
case <-ctx.Done():
return ctx.Err()
default:
}
inoKey := newInode(fi.Sys().(*syscall.Stat_t))
if _, ok := inodes[inoKey]; !ok {
inodes[inoKey] = struct{}{}

View file

@ -8,7 +8,7 @@ import (
"path/filepath"
)
func diskUsage(roots ...string) (Usage, error) {
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
var (
size int64
)
@ -21,6 +21,12 @@ func diskUsage(roots ...string) (Usage, error) {
return err
}
select {
case <-ctx.Done():
return ctx.Err()
default:
}
size += fi.Size()
return nil
}); err != nil {

View file

@ -0,0 +1,3 @@
This package is for internal use only. It is intended to only have
temporary changes before they are upstreamed to golang.org/x/sys/
(a.k.a. https://github.com/golang/sys).

View file

@ -1,10 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
TEXT ·use(SB),NOSPLIT,$0
RET

View file

@ -1,18 +0,0 @@
package sysx
const (
// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
AtSymlinkNofollow = 0x20
)
const (
// SYS_FCHMODAT defined from golang.org/sys/unix
SYS_FCHMODAT = 467
)
// These functions will be generated by generate.sh
// $ GOOS=darwin GOARCH=386 ./generate.sh chmod
// $ GOOS=darwin GOARCH=amd64 ./generate.sh chmod
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)

View file

@ -1,25 +0,0 @@
// mksyscall.pl -l32 chmod_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
use(unsafe.Pointer(_p0))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,25 +0,0 @@
// mksyscall.pl chmod_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
use(unsafe.Pointer(_p0))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,17 +0,0 @@
package sysx
const (
// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
AtSymlinkNofollow = 0x200
)
const (
// SYS_FCHMODAT defined from golang.org/sys/unix
SYS_FCHMODAT = 490
)
// These functions will be generated by generate.sh
// $ GOOS=freebsd GOARCH=amd64 ./generate.sh chmod
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)

View file

@ -1,25 +0,0 @@
// mksyscall.pl chmod_freebsd.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
use(unsafe.Pointer(_p0))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,12 +0,0 @@
package sysx
import "syscall"
const (
// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in /usr/include/linux/fcntl.h
AtSymlinkNofollow = 0x100
)
func Fchmodat(dirfd int, path string, mode uint32, flags int) error {
return syscall.Fchmodat(dirfd, path, mode, flags)
}

View file

@ -1,11 +0,0 @@
package sysx
import "golang.org/x/sys/unix"
const (
AtSymlinkNofollow = unix.AT_SYMLINK_NOFOLLOW
)
func Fchmodat(dirfd int, path string, mode uint32, flags int) error {
return unix.Fchmodat(dirfd, path, mode, flags)
}

View file

@ -1,37 +0,0 @@
package sysx
import (
"syscall"
"unsafe"
)
var _zero uintptr
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
//go:noescape
func use(p unsafe.Pointer)
// Do the interface allocations only once for common
// Errno values.
var (
errEAGAIN error = syscall.EAGAIN
errEINVAL error = syscall.EINVAL
errENOENT error = syscall.ENOENT
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case syscall.EAGAIN:
return errEAGAIN
case syscall.EINVAL:
return errEINVAL
case syscall.ENOENT:
return errENOENT
}
return e
}

View file

@ -1,14 +1,56 @@
// +build linux darwin
package sysx
import (
"bytes"
"fmt"
"syscall"
"golang.org/x/sys/unix"
)
const defaultXattrBufferSize = 5
// Listxattr calls syscall listxattr and reads all content
// and returns a string array
func Listxattr(path string) ([]string, error) {
return listxattrAll(path, unix.Listxattr)
}
var ErrNotSupported = fmt.Errorf("not supported")
// Removexattr calls syscall removexattr
func Removexattr(path string, attr string) (err error) {
return unix.Removexattr(path, attr)
}
// Setxattr calls syscall setxattr
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
return unix.Setxattr(path, attr, data, flags)
}
// Getxattr calls syscall getxattr
func Getxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Getxattr)
}
// LListxattr lists xattrs, not following symlinks
func LListxattr(path string) ([]string, error) {
return listxattrAll(path, unix.Llistxattr)
}
// LRemovexattr removes an xattr, not following symlinks
func LRemovexattr(path string, attr string) (err error) {
return unix.Lremovexattr(path, attr)
}
// LSetxattr sets an xattr, not following symlinks
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
return unix.Lsetxattr(path, attr, data, flags)
}
// LGetxattr gets an xattr, not following symlinks
func LGetxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Lgetxattr)
}
const defaultXattrBufferSize = 5
type listxattrFunc func(path string, dest []byte) (int, error)

View file

@ -1,71 +0,0 @@
package sysx
// These functions will be generated by generate.sh
// $ GOOS=darwin GOARCH=386 ./generate.sh xattr
// $ GOOS=darwin GOARCH=amd64 ./generate.sh xattr
//sys getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error)
//sys setxattr(path string, attr string, data []byte, flags int) (err error)
//sys removexattr(path string, attr string, options int) (err error)
//sys listxattr(path string, dest []byte, options int) (sz int, err error)
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
const (
xattrNoFollow = 0x01
)
func listxattrFollow(path string, dest []byte) (sz int, err error) {
return listxattr(path, dest, 0)
}
// Listxattr calls syscall getxattr
func Listxattr(path string) ([]string, error) {
return listxattrAll(path, listxattrFollow)
}
// Removexattr calls syscall getxattr
func Removexattr(path string, attr string) (err error) {
return removexattr(path, attr, 0)
}
// Setxattr calls syscall setxattr
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
return setxattr(path, attr, data, flags)
}
func getxattrFollow(path, attr string, dest []byte) (sz int, err error) {
return getxattr(path, attr, dest, 0, 0)
}
// Getxattr calls syscall getxattr
func Getxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, getxattrFollow)
}
func listxattrNoFollow(path string, dest []byte) (sz int, err error) {
return listxattr(path, dest, xattrNoFollow)
}
// LListxattr calls syscall listxattr with XATTR_NOFOLLOW
func LListxattr(path string) ([]string, error) {
return listxattrAll(path, listxattrNoFollow)
}
// LRemovexattr calls syscall removexattr with XATTR_NOFOLLOW
func LRemovexattr(path string, attr string) (err error) {
return removexattr(path, attr, xattrNoFollow)
}
// Setxattr calls syscall setxattr with XATTR_NOFOLLOW
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
return setxattr(path, attr, data, flags|xattrNoFollow)
}
func getxattrNoFollow(path, attr string, dest []byte) (sz int, err error) {
return getxattr(path, attr, dest, 0, xattrNoFollow)
}
// LGetxattr calls syscall getxattr with XATTR_NOFOLLOW
func LGetxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, getxattrNoFollow)
}

View file

@ -1,111 +0,0 @@
// mksyscall.pl -l32 xattr_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
var _p2 unsafe.Pointer
if len(dest) > 0 {
_p2 = unsafe.Pointer(&dest[0])
} else {
_p2 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
sz = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func setxattr(path string, attr string, data []byte, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
var _p2 unsafe.Pointer
if len(data) > 0 {
_p2 = unsafe.Pointer(&data[0])
} else {
_p2 = unsafe.Pointer(&_zero)
}
_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func listxattr(path string, dest []byte, options int) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(dest) > 0 {
_p1 = unsafe.Pointer(&dest[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
use(unsafe.Pointer(_p0))
sz = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,111 +0,0 @@
// mksyscall.pl xattr_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
var _p2 unsafe.Pointer
if len(dest) > 0 {
_p2 = unsafe.Pointer(&dest[0])
} else {
_p2 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
sz = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func setxattr(path string, attr string, data []byte, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
var _p2 unsafe.Pointer
if len(data) > 0 {
_p2 = unsafe.Pointer(&data[0])
} else {
_p2 = unsafe.Pointer(&_zero)
}
_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
use(unsafe.Pointer(_p0))
use(unsafe.Pointer(_p1))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func listxattr(path string, dest []byte, options int) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(dest) > 0 {
_p1 = unsafe.Pointer(&dest[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
use(unsafe.Pointer(_p0))
sz = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,12 +0,0 @@
package sysx
import (
"errors"
)
// Initial stub version for FreeBSD. FreeBSD has a different
// syscall API from Darwin and Linux for extended attributes;
// it is also not widely used. It is not exposed at all by the
// Go syscall package, so we need to implement directly eventually.
var unsupported = errors.New("extended attributes unsupported on FreeBSD")

View file

@ -1,44 +0,0 @@
package sysx
import "golang.org/x/sys/unix"
// Listxattr calls syscall listxattr and reads all content
// and returns a string array
func Listxattr(path string) ([]string, error) {
return listxattrAll(path, unix.Listxattr)
}
// Removexattr calls syscall removexattr
func Removexattr(path string, attr string) (err error) {
return unix.Removexattr(path, attr)
}
// Setxattr calls syscall setxattr
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
return unix.Setxattr(path, attr, data, flags)
}
// Getxattr calls syscall getxattr
func Getxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Getxattr)
}
// LListxattr lists xattrs, not following symlinks
func LListxattr(path string) ([]string, error) {
return listxattrAll(path, unix.Llistxattr)
}
// LRemovexattr removes an xattr, not following symlinks
func LRemovexattr(path string, attr string) (err error) {
return unix.Lremovexattr(path, attr)
}
// LSetxattr sets an xattr, not following symlinks
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
return unix.Lsetxattr(path, attr, data, flags)
}
// LGetxattr gets an xattr, not following symlinks
func LGetxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Lgetxattr)
}

View file

@ -1,7 +0,0 @@
package sysx
import (
"errors"
)
var unsupported = errors.New("extended attributes unsupported on OpenBSD")

View file

@ -1,12 +0,0 @@
package sysx
import (
"errors"
)
// Initial stub version for Solaris. Solaris has a different
// syscall API from Darwin and Linux for extended attributes;
// it is also not widely used. It is not exposed at all by the
// Go syscall package, so we need to implement directly eventually.
var unsupported = errors.New("extended attributes unsupported on Solaris")

View file

@ -1,7 +1,14 @@
// +build freebsd openbsd solaris
// +build !linux,!darwin
package sysx
import (
"errors"
"runtime"
)
var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
// Listxattr calls syscall listxattr and reads all content
// and returns a string array
func Listxattr(path string) ([]string, error) {

View file

@ -10,4 +10,4 @@ github.com/spf13/pflag 4c012f6dcd9546820e378d0bdda4d8fc772cdfea
golang.org/x/crypto 9f005a07e0d31d45e6656d241bb5c0f2efd4bc94
golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
golang.org/x/sys 665f6529cca930e27b831a0d1dafffbe1c172924
golang.org/x/sys 77b0e4315053a57ed2962443614bdb28db152054