diff --git a/_multibuild b/_multibuild
deleted file mode 100644
index fcc7b97..0000000
--- a/_multibuild
+++ /dev/null
@@ -1,3 +0,0 @@
-
- test
-
diff --git a/_service b/_service
index f0048dd..4b64973 100644
--- a/_service
+++ b/_service
@@ -1,10 +1,7 @@
-
- libcst-0.4.9/native
- xz
+
+ libcst-*.tar.gz
+ native/Cargo.toml
true
-
- libcst-0.4.9/native
-
diff --git a/cargo_config b/cargo_config
deleted file mode 100644
index 6fb4ff4..0000000
--- a/cargo_config
+++ /dev/null
@@ -1,5 +0,0 @@
-[source.crates-io]
-replace-with = "vendored-sources"
-
-[source.vendored-sources]
-directory = "vendor"
\ No newline at end of file
diff --git a/libcst-0.4.9.tar.gz b/libcst-0.4.9.tar.gz
deleted file mode 100644
index 08fa58d..0000000
--- a/libcst-0.4.9.tar.gz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:01786c403348f76f274dbaf3888ae237ffb73e6ed6973e65eba5c1fc389861dd
-size 742071
diff --git a/libcst-1.4.0.tar.gz b/libcst-1.4.0.tar.gz
new file mode 100644
index 0000000..c9f9b32
--- /dev/null
+++ b/libcst-1.4.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:449e0b16604f054fa7f27c3ffe86ea7ef6c409836fe68fe4e752a1894175db00
+size 771364
diff --git a/pyo3-022.patch b/pyo3-022.patch
new file mode 100644
index 0000000..819aebc
--- /dev/null
+++ b/pyo3-022.patch
@@ -0,0 +1,223 @@
+From 03ca79632fe42ff2d4b22ed6d03c2289497e8d6c Mon Sep 17 00:00:00 2001
+From: Jelmer Vernooij
+Date: Tue, 30 Jul 2024 15:34:55 +0000
+Subject: [PATCH] Upgrade pyo3 to 0.22
+
+---
+ .cargo/config.toml | 8 +++++++-
+ native/libcst/Cargo.toml | 2 +-
+ native/libcst/src/nodes/expression.rs | 13 +++++++------
+ native/libcst/src/nodes/parser_config.rs | 2 +-
+ native/libcst/src/nodes/traits.rs | 2 +-
+ native/libcst/src/parser/errors.rs | 13 +++++++------
+ native/libcst/src/py.rs | 2 +-
+ native/libcst_derive/src/into_py.rs | 15 +++++++++------
+ 8 files changed, 34 insertions(+), 23 deletions(-)
+
+--- a/.cargo/config.toml
++++ b/.cargo/config.toml
+@@ -8,4 +8,10 @@ rustflags = [
+ rustflags = [
+ "-C", "link-arg=-undefined",
+ "-C", "link-arg=dynamic_lookup",
+-]
+\ No newline at end of file
++]
++
++[source.crates-io]
++replace-with = "vendored-sources"
++
++[source.vendored-sources]
++directory = "vendor"
+--- a/native/libcst/Cargo.toml
++++ b/native/libcst/Cargo.toml
+@@ -36,7 +36,7 @@ trace = ["peg/trace"]
+
+ [dependencies]
+ paste = "1.0.9"
+-pyo3 = { version = "0.20", optional = true }
++pyo3 = { version = "0.22", optional = true }
+ thiserror = "1.0.37"
+ peg = "0.8.1"
+ chic = "1.2.2"
+--- a/native/libcst/src/nodes/expression.rs
++++ b/native/libcst/src/nodes/expression.rs
+@@ -2524,6 +2524,7 @@ impl<'r, 'a> Inflate<'a> for DeflatedNam
+ #[cfg(feature = "py")]
+ mod py {
+
++ use pyo3::types::PyAnyMethods;
+ use pyo3::types::PyModule;
+
+ use super::*;
+@@ -2535,7 +2536,7 @@ mod py {
+ match self {
+ Self::Starred(s) => s.try_into_py(py),
+ Self::Simple { value, comma } => {
+- let libcst = PyModule::import(py, "libcst")?;
++ let libcst = PyModule::import_bound(py, "libcst")?;
+ let kwargs = [
+ Some(("value", value.try_into_py(py)?)),
+ comma
+@@ -2547,11 +2548,11 @@ mod py {
+ .filter(|x| x.is_some())
+ .map(|x| x.as_ref().unwrap())
+ .collect::>()
+- .into_py_dict(py);
++ .into_py_dict_bound(py);
+ Ok(libcst
+ .getattr("Element")
+ .expect("no Element found in libcst")
+- .call((), Some(kwargs))?
++ .call((), Some(&kwargs))?
+ .into())
+ }
+ }
+@@ -2571,7 +2572,7 @@ mod py {
+ whitespace_before_colon,
+ ..
+ } => {
+- let libcst = PyModule::import(py, "libcst")?;
++ let libcst = PyModule::import_bound(py, "libcst")?;
+ let kwargs = [
+ Some(("key", key.try_into_py(py)?)),
+ Some(("value", value.try_into_py(py)?)),
+@@ -2592,11 +2593,11 @@ mod py {
+ .filter(|x| x.is_some())
+ .map(|x| x.as_ref().unwrap())
+ .collect::>()
+- .into_py_dict(py);
++ .into_py_dict_bound(py);
+ Ok(libcst
+ .getattr("DictElement")
+ .expect("no Element found in libcst")
+- .call((), Some(kwargs))?
++ .call((), Some(&kwargs))?
+ .into())
+ }
+ }
+--- a/native/libcst/src/nodes/parser_config.rs
++++ b/native/libcst/src/nodes/parser_config.rs
+@@ -125,7 +125,7 @@ fn parser_config_asdict<'py>(py: Python<
+ ("version", config.version.clone_ref(py)),
+ ("future_imports", config.future_imports.clone_ref(py)),
+ ]
+- .into_py_dict(py)
++ .into_py_dict_bound(py)
+ }
+
+ pub fn init_module(_py: Python, m: &PyModule) -> PyResult<()> {
+--- a/native/libcst/src/nodes/traits.rs
++++ b/native/libcst/src/nodes/traits.rs
+@@ -170,7 +170,7 @@ pub mod py {
+ .map(|x| x.try_into_py(py))
+ .collect::>>()?
+ .into_iter();
+- Ok(PyTuple::new(py, converted).into())
++ Ok(PyTuple::new_bound(py, converted).into())
+ }
+ }
+
+--- a/native/libcst/src/parser/errors.rs
++++ b/native/libcst/src/parser/errors.rs
+@@ -28,7 +28,7 @@ pub enum ParserError<'a> {
+ #[cfg(feature = "py")]
+ mod py_error {
+
+- use pyo3::types::{IntoPyDict, PyModule};
++ use pyo3::types::{IntoPyDict, PyAnyMethods, PyModule};
+ use pyo3::{IntoPy, PyErr, PyErrArguments, Python};
+
+ use super::ParserError;
+@@ -65,13 +65,14 @@ mod py_error {
+ ("raw_line", (line + 1).into_py(py)),
+ ("raw_column", col.into_py(py)),
+ ]
+- .into_py_dict(py);
+- let libcst = PyModule::import(py, "libcst").expect("libcst cannot be imported");
+- PyErr::from_value(
++ .into_py_dict_bound(py);
++ let libcst =
++ PyModule::import_bound(py, "libcst").expect("libcst cannot be imported");
++ PyErr::from_value_bound(
+ libcst
+ .getattr("ParserSyntaxError")
+ .expect("ParserSyntaxError not found")
+- .call((), Some(kwargs))
++ .call((), Some(&kwargs))
+ .expect("failed to instantiate"),
+ )
+ })
+@@ -86,7 +87,7 @@ mod py_error {
+ ("raw_line", self.raw_line.into_py(py)),
+ ("raw_column", self.raw_column.into_py(py)),
+ ]
+- .into_py_dict(py)
++ .into_py_dict_bound(py)
+ .into_py(py)
+ }
+ }
+--- a/native/libcst/src/py.rs
++++ b/native/libcst/src/py.rs
+@@ -8,7 +8,7 @@ use pyo3::prelude::*;
+
+ #[pymodule]
+ #[pyo3(name = "native")]
+-pub fn libcst_native(_py: Python, m: &PyModule) -> PyResult<()> {
++pub fn libcst_native(_py: Python, m: &Bound) -> PyResult<()> {
+ #[pyfn(m)]
+ fn parse_module(source: String, encoding: Option<&str>) -> PyResult {
+ let m = crate::parse_module(source.as_str(), encoding)?;
+--- a/native/libcst_derive/src/into_py.rs
++++ b/native/libcst_derive/src/into_py.rs
+@@ -38,12 +38,14 @@ fn impl_into_py_enum(ast: &DeriveInput,
+ let kwargs_toks = fields_to_kwargs(&var.fields, true);
+ toks.push(quote! {
+ Self::#varname { #(#fieldnames,)* .. } => {
+- let libcst = pyo3::types::PyModule::import(py, "libcst")?;
++ use pyo3::types::PyAnyMethods;
++
++ let libcst = pyo3::types::PyModule::import_bound(py, "libcst")?;
+ let kwargs = #kwargs_toks ;
+ Ok(libcst
+ .getattr(stringify!(#varname))
+ .expect(stringify!(no #varname found in libcst))
+- .call((), Some(kwargs))?
++ .call((), Some(&kwargs))?
+ .into())
+ }
+ })
+@@ -87,12 +89,13 @@ fn impl_into_py_struct(ast: &DeriveInput
+ #[automatically_derived]
+ impl#generics crate::nodes::traits::py::TryIntoPy for #ident #generics {
+ fn try_into_py(self, py: pyo3::Python) -> pyo3::PyResult {
+- let libcst = pyo3::types::PyModule::import(py, "libcst")?;
++ use pyo3::types::PyAnyMethods;
++ let libcst = pyo3::types::PyModule::import_bound(py, "libcst")?;
+ let kwargs = #kwargs_toks ;
+ Ok(libcst
+ .getattr(stringify!(#ident))
+ .expect(stringify!(no #ident found in libcst))
+- .call((), Some(kwargs))?
++ .call((), Some(&kwargs))?
+ .into())
+ }
+ }
+@@ -162,7 +165,7 @@ fn fields_to_kwargs(fields: &Fields, is_
+ #(#optional_rust_varnames.map(|x| x.try_into_py(py)).transpose()?.map(|x| (stringify!(#optional_py_varnames), x)),)*
+ };
+ if empty_kwargs {
+- quote! { pyo3::types::PyDict::new(py) }
++ quote! { pyo3::types::PyDict::new_bound(py) }
+ } else {
+ quote! {
+ [ #kwargs_pairs #optional_pairs ]
+@@ -170,7 +173,7 @@ fn fields_to_kwargs(fields: &Fields, is_
+ .filter(|x| x.is_some())
+ .map(|x| x.as_ref().unwrap())
+ .collect::>()
+- .into_py_dict(py)
++ .into_py_dict_bound(py)
+ }
+ }
+ }
diff --git a/python-libcst.changes b/python-libcst.changes
index e53989f..0a6a96d 100644
--- a/python-libcst.changes
+++ b/python-libcst.changes
@@ -1,3 +1,112 @@
+-------------------------------------------------------------------
+Mon Sep 9 11:38:15 UTC 2024 - Matej Cepl
+
+- Add pyo3-022.patch bumping the dependency of pyo3 to 0.22
+ (gh#Instagram/LibCST!1180).
+
+-------------------------------------------------------------------
+Mon Jul 22 10:24:31 UTC 2024 - Matej Cepl
+
+- Upgrade to 1.4.0:
+ - Fix Literal parse error in RemoveImportsVisitor
+ - Don't reset context.scratch between files
+ - Various documentation fixes
+ Typo fix FullRepoManager
+ ✏️ Fix tiny typo in docs/source/metadata.rst
+ ✏️ Fix typo in docs/source/scope_tutorial.ipynb
+ Update CONTRIBUTING.md
+ - Add helper functions for common ways of filtering nodes
+ - Dump CST to .dot (graphviz) files
+ - Implement PEP-696
+- Upgrade to 1.3.1:
+ - ImportError due to missing mypy_extensions dependency
+- Upgrade to 1.3.0:
+ - Removed dependencies on typing_extensions and typing_inspect
+- Temporarily switch off running of the test suite (gh#Instagram/LibCST#1176)
+
+-------------------------------------------------------------------
+Fri Mar 1 00:29:21 UTC 2024 - Soc Virnyl Estela
+
+- Update to version 1.2.0
+ * Upgrade pyo3 to 0.20
+ * Remove reference to distutil
+ * Add roundtrip tests from Python
+ * Fix parsing list matchers without explicit brackets
+ * Make readme example use python syntax highlighting
+ * Upgrade rust to version 1.70 in readthedocs config
+ * Update maturin requirement from <0.16,>=0.8.3 to >=0.8.3,<1.5
+ * Allow `Element::codegen` to be used by external users
+ * installing rustc/cargo for mybinder demo
+ * Update test_fix_pyre_directives.py
+ * remove 3.8 support
+ * Update syn to v2
+ * Set repository metadata entry for Rust crates
+ * upgrade flake8
+ * Update pyproject.toml for Python 3.12 support
+ * fix filepathprovider generic type
+ * Update README.rst
+ * Fix link in type_inference_provider.py
+ * Parse multiline expressions in f-strings
+ * Upgrade pyre
+ * eliminate relative paths from Cargo.toml
+ * Parse arbitrarily nested f-strings
+ * ScopeProvider: Record Access for Attributes and Decorators
+ * AddImportsVisitor: add imports before the first non-import statement
+ * Scope provider changes for type annotations
+ * add upper bound to pyo3 dependency
+ * scope_provider: Simplify parent resolution
+ * parser: remove Regexes from whitespace parser
+ * Add crate metadata
+ * Support files with mixed newlines
+ * PEP 695 - Type Parameter Syntax
+ * Remove need for regex in TextPosition::matches
+ * Fix readme's Python version requirement
+ * Switch to using thread_local regular expressions to avoid regex mutex contention
+ * Remove criterion-cycles-per-byte dependency and related benchmark measurement
+ * drop support for Python 3.7
+ * Don't gather dirs ending .py
+ * Don't insert duplicate imports
+ * Don't swallow trailing whitespace
+ * Allow pyo3 >=0.17
+ * Do not annotate the same variable multiple times in ApplyTypeAnnotationsVisitor
+ * Update changelog to 1.0.1
+ * Codemod CLI: Print diff only when there is a change
+ * Fix parsing of code without trailing newlines
+ * Fix whitespace, fstring, walrus related parse errors
+ * Fix Sentinal typo
+ * remove quotes around charset in .editorconfig
+ * Update maturin requirement from <0.14,>=0.8.3 to >=0.8.3,<0.16
+ * Fix type of `evaluated_value` on string to allow bytes
+ * Switch default parser implementation to native
+ * exclude native/target directory from sdist
+ * update changelog
+ * relax validation rules on decorators
+ * Fix crash on escaped backslashes in rf-string
+ * Fix pyre setup link in metadata.rst
+ * Support PEP 604 in ApplyTypeAnnotationsVisitor
+ * Fix spelling and grammar in some comments
+ * Fix ApplyTypeAnnotationsVisitor behavior on attribute assignments.
+ * Allow running codemods without configuring in YAML
+ * Ensure current Python interpreter is used for subprocesses
+ * Use subprocess.DEVNULL instead of opening os.devnull by hand
+ * PEP 621 + hatch to run tests/lint/etc
+ * Fix: relative imports from '' package are not allowed
+ * Add new FilePathProvider
+ * Use new setup-python caching actions
+ * Pass root path to FullyQualifiedNameProvider
+ * Script to regenerate test fixtures
+ * Add setuptools-rust to build requirements in setup.py
+ * Ignore common virtualenv names
+ * Fix Github issue 855 - fail to parse with statement
+ * fix PEP 604 union annotations in decorators
+ * Add py3.11 classifier
+- Update _service file
+ * remove obsoleted mode "disabled" to "manual"
+ * adopt new obs-service-cargo packaging method
+- Remove patches
+ * remove-ufmt-dep.patch
+ * replace-python-call.patch
+
-------------------------------------------------------------------
Fri Apr 21 12:27:55 UTC 2023 - Dirk Müller
diff --git a/python-libcst.spec b/python-libcst.spec
index 4f8bd3c..5b77d6e 100644
--- a/python-libcst.spec
+++ b/python-libcst.spec
@@ -1,7 +1,7 @@
#
-# spec file
+# spec file for package python-libcst
#
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -16,32 +16,28 @@
#
-%define skip_python2 1
-%define rustflags '-Clink-arg=-Wl,-z,relro,-z,now'
%global flavor @BUILD_FLAVOR@%{nil}
-%if "%{flavor}" == "test"
-%define psuffix -test
-%bcond_without test
-%else
+# %%if "%%{flavor}" == "test"
+# %%define psuffix -test
+# %%bcond_without test
+# %%else
%define psuffix %{nil}
%bcond_with test
-%endif
+# %%endif
%define modname libcst
%{?sle15_python_module_pythons}
Name: python-libcst%{psuffix}
-Version: 0.4.9
+Version: 1.4.0
Release: 0
Summary: Python 3.5+ concrete syntax tree with AST-like properties
License: MIT
URL: https://github.com/Instagram/LibCST
-Source0: https://files.pythonhosted.org/packages/source/l/%{modname}/%{modname}-%{version}.tar.gz
-Source1: vendor.tar.xz
-Source2: cargo_config
-# PATCH-FIX-OPENSUSE remove-ufmt-dep.patch python-ufmt package doesn't exists in Tumbleweed
-Patch0: remove-ufmt-dep.patch
-# PATCH-FIX-OPENSUSE replace-python-call.patch
-# wrong executable call when outside of venv (gh#Instagram/LibCST#468)
-Patch1: replace-python-call.patch
+Source0: https://files.pythonhosted.org/packages/source/l/libcst/%{modname}-%{version}.tar.gz
+Source1: vendor.tar.zst
+# PATCH-FIX-UPSTREAM pyo3-022.patch gh#Instagram/LibCST!1180 mcepl@suse.com
+# updgrade pyo3 to 0.22 version
+Patch0: pyo3-022.patch
+BuildRequires: %{python_module pip}
BuildRequires: %{python_module setuptools-rust}
BuildRequires: %{python_module setuptools_scm}
BuildRequires: %{python_module setuptools}
@@ -50,7 +46,7 @@ BuildRequires: cargo
BuildRequires: cargo-packaging
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-BuildRequires: rust
+BuildRequires: zstd
Requires: python-PyYAML >= 5.2
Requires: python-typing-inspect >= 0.4.0
Requires: python-typing_extensions >= 3.7.4.2
@@ -71,52 +67,40 @@ BuildRequires: %{python_module typing_extensions >= 3.7.4.2}
A concrete syntax tree with AST-like properties for Python 3.5+ programs.
%prep
-%setup -q -n libcst-%{version}
-tar x -C native/ -f %{SOURCE1}
-cp -rf native/vendor vendor
-mkdir -p .cargo && echo "" >> .cargo/config.toml && cat %{SOURCE2} >>.cargo/config.toml
+%autosetup -a1 -n libcst-%{version} -p1
-pushd native
-mkdir -p .cargo
-cat %{SOURCE2} >>.cargo/config.toml
-popd
+# # Depends on optional pyre
+# rm \
+# libcst/metadata/tests/test_type_inference_provider.py \
+# libcst/metadata/tests/test_full_repo_manager.py \
+# libcst/tests/test_pyre_integration.py
-%autopatch -p1
-
-# Depends on optional pyre
-rm \
- libcst/metadata/tests/test_type_inference_provider.py \
- libcst/metadata/tests/test_full_repo_manager.py \
- libcst/tests/test_pyre_integration.py
-
-# gh#Instagram/LibCST#467
-sed -i -e 's/import AbstractBaseMatcherNodeMeta/import Optional, AbstractBaseMatcherNodeMeta/' libcst/codegen/gen_matcher_classes.py
-
-%if !%{with test}
%build
export CARGO_NET_OFFLINE=true PROFILE=release
-%python_build
-%endif
+%pyproject_wheel
%install
-%if !%{with test}
export CARGO_NET_OFFLINE=true PROFILE=release
-%python_install
-%python_expand %fdupes %{buildroot}%{$python_sitearch}
-%endif
+%pyproject_install
+# gh#Instagram/LibCST#818
+%{python_expand rm -rf %{buildroot}%{$python_sitearch}/libcst/tests
+%fdupes %{buildroot}%{$python_sitearch}
+}
+
+%clean
%if %{with test}
%check
-%python_exec -m libcst.codegen.generate all
-%pyunittest -v
+%python_expand find %{buildroot}%{$python_sitearch} -name \*.so\*
+%pyunittest_arch discover -v libcst/tests
%endif
-%if !%{with test}
+%if %{without test}
%files %{python_files}
%doc README.rst
%license LICENSE
%{python_sitearch}/libcst
-%{python_sitearch}/libcst-%{version}-py*.egg-info
+%{python_sitearch}/libcst-%{version}*-info
%endif
%changelog
diff --git a/remove-ufmt-dep.patch b/remove-ufmt-dep.patch
deleted file mode 100644
index 4d94eb9..0000000
--- a/remove-ufmt-dep.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-Index: libcst-0.4.9/libcst/codegen/generate.py
-===================================================================
---- libcst-0.4.9.orig/libcst/codegen/generate.py
-+++ libcst-0.4.9/libcst/codegen/generate.py
-@@ -25,8 +25,10 @@ from libcst.codegen.transforms import (
-
-
- def format_file(fname: str) -> None:
-- with open(os.devnull, "w") as devnull:
-- subprocess.check_call(["ufmt", "format", fname], stdout=devnull, stderr=devnull)
-+ # Do not format to avoid ufmt dependency that's not yet in opensuse
-+ pass
-+ # with open(os.devnull, "w") as devnull:
-+ # subprocess.check_call(["ufmt", "format", fname], stdout=devnull, stderr=devnull)
-
-
- def clean_generated_code(code: str) -> str:
diff --git a/replace-python-call.patch b/replace-python-call.patch
deleted file mode 100644
index 73e8dae..0000000
--- a/replace-python-call.patch
+++ /dev/null
@@ -1,36 +0,0 @@
----
- libcst/codegen/generate.py | 2 +-
- libcst/codemod/tests/test_codemod_cli.py | 4 ++--
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/libcst/codegen/generate.py
-+++ b/libcst/codegen/generate.py
-@@ -69,7 +69,7 @@ def codegen_visitors() -> None:
- # by attempting to run codegen again in a new process.
- with open(os.devnull, "w") as devnull:
- subprocess.check_call(
-- ["python3", "-m", "libcst.codegen.gen_visitor_functions"],
-+ [sys.executable, "-m", "libcst.codegen.gen_visitor_functions"],
- cwd=base,
- stdout=devnull,
- )
---- a/libcst/codemod/tests/test_codemod_cli.py
-+++ b/libcst/codemod/tests/test_codemod_cli.py
-@@ -4,7 +4,7 @@
- # LICENSE file in the root directory of this source tree.
- #
-
--
-+import sys
- import subprocess
- from pathlib import Path
-
-@@ -16,7 +16,7 @@ class TestCodemodCLI(UnitTest):
- def test_codemod_formatter_error_input(self) -> None:
- rlt = subprocess.run(
- [
-- "python",
-+ sys.executable,
- "-m",
- "libcst.tool",
- "codemod",
diff --git a/vendor.tar.xz b/vendor.tar.xz
deleted file mode 100644
index 58e043a..0000000
--- a/vendor.tar.xz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c119328db7b0c42d71498ee49480fcac03cb8026743e46f8fedbee5b0e6c62f2
-size 14686248
diff --git a/vendor.tar.zst b/vendor.tar.zst
new file mode 100644
index 0000000..f09a60a
--- /dev/null
+++ b/vendor.tar.zst
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0612f718a0d5f7c7f0a70c6151c9370d6c5d51f9074a11c8c3df5d7bf650b655
+size 30171484