diff --git a/thirdparty/fft2d/HPKBUILD b/thirdparty/fft2d/HPKBUILD new file mode 100644 index 0000000000000000000000000000000000000000..751f00bd773b4292fd48cabe03c6ab7d41883379 --- /dev/null +++ b/thirdparty/fft2d/HPKBUILD @@ -0,0 +1,72 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Contributor: Jeff Han +# Maintainer: Jeff Han + +pkgname=fft2d +pkgver=v2 +pkgrel=0 +pkgdesc="A package to calculate Discrete Fourier/Cosine/Sine Transforms of 1-dimensional sequences of length 2^N." +url="https://www.kurims.kyoto-u.ac.jp/~ooura/fft.html" +archs=("armeabi-v7a" "arm64-v8a") +license=("Free Software License") +depends=() +makedepends=() + +source="https://www.kurims.kyoto-u.ac.jp/~ooura/$pkgname.tgz" + +downloadpackage=true +autounpack=true + +builddir=$pkgname +packagename=$builddir.tgz +patchflag=true + +prepare() { + mkdir -p $builddir/$ARCH-build + + if $patchflag + then + cd $builddir + patch -p1 < `pwd`/../fft2d_pkg.patch + # patch只需要打一次,关闭打patch + patchflag=false + cd $OLDPWD + fi +} + +build() { + ret=0 + cd $builddir + ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -B$ARCH-build -S./ > $buildlog 2>&1 + $MAKE VERBOSE=1 -C $ARCH-build >> $buildlog 2>&1 + ret=$? + cd $OLDPWD + return $ret +} + +package() { + cd $builddir + $MAKE -C $ARCH-build install >> $buildlog 2>&1 + cd $OLDPWD +} + +check() { + echo "The test must be on an OpenHarmony device!" +} + +# 清理环境 +cleanbuild() { + rm -rf ${PWD}/$builddir +} diff --git a/thirdparty/fft2d/HPKCHECK b/thirdparty/fft2d/HPKCHECK new file mode 100644 index 0000000000000000000000000000000000000000..684c46f04889abe7b90b956a247722696e59c080 --- /dev/null +++ b/thirdparty/fft2d/HPKCHECK @@ -0,0 +1,31 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Contributor: Jeff Han +# Maintainer: Jeff Han + +source HPKBUILD > /dev/null 2>&1 +logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_${OHOS_SDK_VER}_test.log + +openharmonycheck() { + res=0 + cd ${builddir}/${ARCH}-build + ./shrtdctt > ${logfile} 2>&1 + res=$? + if [ $res -ne 0 ]; then + cd $OLDPWD + return $res + fi + cd $OLDPWD + return $res +} diff --git a/thirdparty/fft2d/OAT.xml b/thirdparty/fft2d/OAT.xml new file mode 100644 index 0000000000000000000000000000000000000000..03ee5a760a1f17e2e86907647046114696ade760 --- /dev/null +++ b/thirdparty/fft2d/OAT.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/thirdparty/fft2d/README.OpenSource b/thirdparty/fft2d/README.OpenSource new file mode 100644 index 0000000000000000000000000000000000000000..eeeb94653b402f9a9962ae8ec5dad46aa24e946d --- /dev/null +++ b/thirdparty/fft2d/README.OpenSource @@ -0,0 +1,11 @@ +[ + { + "Name": "fft2d", + "License": "Free Software License", + "License File": "LICENSE", + "Version Number": "v2", + "Owner": "huangminzhong2@huawei.com", + "Upstream URL": "https://www.kurims.kyoto-u.ac.jp/~ooura/fft.html ", + "Description": "This is a package to calculate Discrete Fourier/Cosine/Sine Transforms of 1-dimensional sequences of length 2^N. This package contains C and Fortran FFT codes." + } +] diff --git a/thirdparty/fft2d/README_zh.md b/thirdparty/fft2d/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..39d250b29d070a4e7b12462ff829040fe85d9193 --- /dev/null +++ b/thirdparty/fft2d/README_zh.md @@ -0,0 +1,9 @@ +# fft2d 三方库说明 +## 功能简介 +fft2d 这是一个用于计算长度为2^N的一维序列的离散傅立叶/余弦/正弦变换的程序包。 +## 使用约束 +- SDK版本:ohos_sdk_linux 4.1.3.401 +- 三方库版本:v2 + +## 集成方式 ++ [应用hap包集成](docs/hap_integrate.md) diff --git a/thirdparty/fft2d/SHA512SUM b/thirdparty/fft2d/SHA512SUM new file mode 100644 index 0000000000000000000000000000000000000000..0442f3c7f8caf196c57836d92ce3774965094037 --- /dev/null +++ b/thirdparty/fft2d/SHA512SUM @@ -0,0 +1 @@ +af993f68e8e1eb3cb927a51e86da8f74cfafc912a7cd055515e50fe543dd19ab5a6f7b1c2be4a55d6f4a0e5d766ead34c3be4c5705be6353f78cb2a55bd5cf16 fft2d.tgz diff --git a/thirdparty/fft2d/docs/hap_integrate.md b/thirdparty/fft2d/docs/hap_integrate.md new file mode 100644 index 0000000000000000000000000000000000000000..4b1549fb3b5c4c14b4fdafd1110b0defa7d8ba0e --- /dev/null +++ b/thirdparty/fft2d/docs/hap_integrate.md @@ -0,0 +1,83 @@ +# fft2d集成到应用hap + +本库是在RK3568开发板上基于OpenHarmony3.2 Release版本的镜像验证的,如果是从未使用过RK3568,可以先查看[润和RK3568开发板标准系统快速上手](https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/docs/rk3568_helloworld)。 + +## 开发环境 + +- [开发环境准备](../../../docs/hap_integrate_environment.md) + +## 编译三方库 + +* 下载本仓库 + + ```shell + git clone https://gitee.com/openharmony-sig/tpc_c_cplusplus.git --depth=1 + ``` + +* 三方库目录结构 + + ```shell + tpc_c_cplusplus/thirdparty/fft2d #三方库fft2d的目录结构如下 + ├── docs #三方库相关文档的文件夹 + ├── HPKBUILD #构建脚本 + ├── HPKCHECK #测试脚本 + ├── OAT.xml #扫描结果文件 + ├── SHA512SUM #三方库校验文件 + ├── README.OpenSource #说明三方库源码的下载地址,版本,license等信息 + ├── README_zh.md #三方库简介 + ├── fft2d_pkg.patch #用于fft2d库编译的补丁 + ``` + +* 在lycium目录下编译三方库 + + 编译环境的搭建参考[准备三方库构建环境](../../../lycium/README.md#1编译环境准备) + + ```shell + cd lycium + ./build.sh fft2d + ``` + +* 三方库头文件及生成的库 + + 在lycium目录下会生成usr目录,该目录下存在已编译完成的32位和64位三方库 + + ```shell + fft2d/arm64-v8a-build fft2d/armeabi-v7a-build + ``` + +* [测试三方库](#测试三方库) + +## 应用中使用三方库 + +- 在IDE的cpp目录下新增thirdparty目录,将编译生成的头文件拷贝到该目录下,将编译生成的三方库拷贝到工程的libs目录下,如下图所示: + + ![thirdparty_install_dir](pic/libfft2d-dev.png) + +- 在最外层(cpp目录下)CMakeLists.txt中添加如下语句 + + ```cmake + #将三方库加入工程中 + target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/liballoc.so) + target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libfftsg2d.so) + target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libfftsg3d.so) + target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libshrtdct.so) + + #将三方库的头文件加入工程中 + target_include_directories(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/fft2d/${OHOS_ARCH}/include) + ``` + + +## 测试三方库 + +- 编译出可执行的文件进行测试,[准备三方库测试环境](../../../lycium/README.md#3ci环境准备) + +- 如图所示,进入到构建目录运行测试用例(注意arm64-v8a-build为构建64位的目录,armeabi-v7a-build为构建32位的目录) + + ![fft2d_test](pic/cmd-test-ret.png) + +## 参考资料 + +* [OpenHarmony三方库地址](https://gitee.com/openharmony-tpc) +* [OpenHarmony知识体系](https://gitee.com/openharmony-sig/knowledge) +* [fft2d三方库地址](https://www.kurims.kyoto-u.ac.jp/~ooura/fft.html) + diff --git a/thirdparty/fft2d/docs/pic/cmd-test-ret.png b/thirdparty/fft2d/docs/pic/cmd-test-ret.png new file mode 100644 index 0000000000000000000000000000000000000000..5531c1bf48f626d920444b407c5568d6ea230e33 Binary files /dev/null and b/thirdparty/fft2d/docs/pic/cmd-test-ret.png differ diff --git a/thirdparty/fft2d/docs/pic/libfft2d-dev.png b/thirdparty/fft2d/docs/pic/libfft2d-dev.png new file mode 100644 index 0000000000000000000000000000000000000000..b3d7f7487a9d50df53b4c60f0abca877afdc7e43 Binary files /dev/null and b/thirdparty/fft2d/docs/pic/libfft2d-dev.png differ diff --git a/thirdparty/fft2d/fft2d_pkg.patch b/thirdparty/fft2d/fft2d_pkg.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ea310c402460a379df78dfe9d56281954006e57 --- /dev/null +++ b/thirdparty/fft2d/fft2d_pkg.patch @@ -0,0 +1,186 @@ +diff -Naur fft2d/CMakeLists.txt fft2dcp/CMakeLists.txt +--- fft2d/CMakeLists.txt 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/CMakeLists.txt 2024-03-02 15:53:43.547521200 +0800 +@@ -0,0 +1,100 @@ ++# Copyright (c) 2023 Huawei Device Co., Ltd. ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++cmake_minimum_required(VERSION 3.16) ++ ++# Project 创建工程文件 ++project(fft2d C CXX) ++ ++# 添加C源文件到项目中 ++set(SOURCE_FILES_FFTSG2D ++ ${CMAKE_CURRENT_SOURCE_DIR}/fftsg2d.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/fftsg.c) ++set(SOURCE_FILES_FFTSG3D ++ ${CMAKE_CURRENT_SOURCE_DIR}/fftsg3d.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/fftsg.c) ++ ++#生成动态库.so文件,默认在build文件夹中 ++add_library(fft4f2d SHARED ${CMAKE_CURRENT_SOURCE_DIR}/fft4f2d.c) ++add_library(fftsg2d SHARED ${SOURCE_FILES_FFTSG2D}) ++add_library(fftsg3d SHARED ${SOURCE_FILES_FFTSG3D}) ++add_library(shrtdct SHARED ${CMAKE_CURRENT_SOURCE_DIR}/shrtdct.c) ++add_library(alloc SHARED ${CMAKE_CURRENT_SOURCE_DIR}/alloc.c) ++ ++#设置编译模式 ++set(CMAKE_BUILD_TYPE "Release" ) ++ ++#生成文件到指定位置 ++set(LIBRARY_OUTPUT_PATH ${CMAKE_INSTALL_PREFIX}/lib) ++set(LIBRARY_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include) ++set(TEST_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/sample2d) ++ ++#fftsg2dt测试程序 ++set(TEST_FFTSG2D ++ ${TEST_SRC_PATH}/fftsg2dt.c) ++add_executable(fftsg2dt ${TEST_FFTSG2D}) ++target_link_libraries(fftsg2dt fftsg2d m alloc) ++ ++#fftsg3dt测试程序 ++set(TEST_FFTSG3D ++ ${TEST_SRC_PATH}/fftsg3dt.c) ++add_executable(fftsg3dt ${TEST_FFTSG3D}) ++target_link_libraries(fftsg3dt fftsg3d m alloc) ++ ++#shrtdct测试程序 ++set(TEST_SHRTDCT ++ ${TEST_SRC_PATH}/shrtdctt.c) ++add_executable(shrtdctt ${TEST_SHRTDCT}) ++target_link_libraries(shrtdctt shrtdct m alloc) ++ ++#fft4f2d测试程序 ++set(TEST_FFT4F2D ++ ${TEST_SRC_PATH}/fft4f2dt.c) ++add_executable(fft4f2dt ${TEST_FFT4F2D}) ++target_link_libraries(fft4f2dt fft4f2d m alloc) ++ ++INSTALL(FILES ++ fft4f2d.h ++ fftsg.h ++ fftsg2d.h ++ fftsg3d.h ++ alloc.h ++ shrtdct.h ++ DESTINATION ${LIBRARY_INCLUDE_PATH} COMPONENT Headers ++) ++ ++install(TARGETS fft4f2d ++LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} ++ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH} ++) ++ ++install(TARGETS fftsg2d ++LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} ++ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH} ++) ++ ++install(TARGETS fftsg3d ++LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} ++ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH} ++) ++ ++install(TARGETS shrtdct ++LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} ++ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH} ++) ++ ++install(TARGETS alloc ++LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} ++ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH} ++) ++ +diff -Naur fft2d/fft4f2d.h fft2dcp/fft4f2d.h +--- fft2d/fft4f2d.h 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/fft4f2d.h 2024-03-02 15:51:35.486254100 +0800 +@@ -0,0 +1,11 @@ ++#ifndef _FFT4F2D_H_ ++#define _FFT4F2D_H_ ++ ++#include ++ ++void cdft2d(int, int, int, double **, int *, double *); ++void rdft2d(int, int, int, double **, int *, double *); ++void ddct2d(int, int, int, double **, double **, int *, double *); ++void ddst2d(int, int, int, double **, double **, int *, double *); ++ ++#endif /*_FFT4F2D_H_*/ +\ No newline at end of file +diff -Naur fft2d/fftsg.h fft2dcp/fftsg.h +--- fft2d/fftsg.h 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/fftsg.h 2024-03-02 15:51:35.489254000 +0800 +@@ -0,0 +1,13 @@ ++#ifndef _FFTSG_H_ ++#define _FFTSG_H_ ++ ++#include ++ ++void cdft(int, int, double *, int *, double *); ++void rdft(int, int, double *, int *, double *); ++void ddct(int, int, double *, int *, double *); ++void ddst(int, int, double *, int *, double *); ++void dfct(int, double *, double *, int *, double *); ++void dfst(int, double *, double *, int *, double *); ++ ++#endif /*_FFTSG_H_*/ +\ No newline at end of file +diff -Naur fft2d/fftsg2d.h fft2dcp/fftsg2d.h +--- fft2d/fftsg2d.h 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/fftsg2d.h 2024-03-02 15:51:35.491254100 +0800 +@@ -0,0 +1,12 @@ ++#ifndef _FFTSG2D_H_ ++#define _FFTSG2D_H_ ++ ++#include ++ ++void cdft2d(int, int, int, double **, double *, int *, double *); ++void rdft2d(int, int, int, double **, double *, int *, double *); ++void rdft2dsort(int, int, int, double **); ++void ddct2d(int, int, int, double **, double *, int *, double *); ++void ddst2d(int, int, int, double **, double *, int *, double *); ++ ++#endif /*_FFTSG2D_H_*/ +\ No newline at end of file +diff -Naur fft2d/fftsg3d.h fft2dcp/fftsg3d.h +--- fft2d/fftsg3d.h 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/fftsg3d.h 2024-03-02 15:51:35.493254000 +0800 +@@ -0,0 +1,12 @@ ++#ifndef _FFTSG3D_H_ ++#define _FFTSG3D_H_ ++ ++#include ++ ++void cdft3d(int, int, int, int, double ***, double *, int *, double *); ++void rdft3d(int, int, int, int, double ***, double *, int *, double *); ++void rdft3dsort(int, int, int, int, double ***); ++void ddct3d(int, int, int, int, double ***, double *, int *, double *); ++void ddst3d(int, int, int, int, double ***, double *, int *, double *); ++ ++#endif /*_FFTSG3D_H_*/ +\ No newline at end of file +diff -Naur fft2d/shrtdct.h fft2dcp/shrtdct.h +--- fft2d/shrtdct.h 1970-01-01 08:00:00.000000000 +0800 ++++ fft2dcp/shrtdct.h 2024-03-02 15:51:35.496254400 +0800 +@@ -0,0 +1,9 @@ ++#ifndef _SHRTDCTT_H_ ++#define _SHRTDCTT_H_ ++ ++#include ++ ++void ddct8x8s(int isgn, double **a); ++void ddct16x16s(int isgn, double **a); ++ ++#endif /*_SHRTDCTT_H_*/ +\ No newline at end of file diff --git a/thirdparty/libheif/HPKBUILD b/thirdparty/libheif/HPKBUILD index 641c94083b94d3a9c9b99b3e69ff901c56d311d8..4b1793047c1e126993c990cfd473396d4ca2561c 100644 --- a/thirdparty/libheif/HPKBUILD +++ b/thirdparty/libheif/HPKBUILD @@ -7,19 +7,17 @@ pkgdesc="libheif is an HEIF and AVIF file format decoder and encoder." url="https://github.com/strukturag/libheif" archs=("armeabi-v7a" "arm64-v8a") license=("GNU LESSER GENERAL PUBLIC LICENSE") -depends=("jpeg" "libpng") +depends=("jpeg" "libpng" "libde265") makedepends=() -#网络原因更换成gitee下载源 -#source="https://github.com/strukturag/$pkgname/archive/refs/tags/$pkgver.tar.gz" -source=https://gitee.com/lycium_pkg_mirror/$pkgname/repository/archive/$pkgver +source="https://github.com/strukturag/$pkgname/archive/refs/tags/$pkgver.tar.gz" autounpack=true downloadpackage=true buildtools="configure" -builddir=$pkgname-${pkgver} -packagename=$builddir.zip +builddir=$pkgname-${pkgver:1} +packagename=$builddir.tar.gz source envset.sh host= @@ -30,7 +28,7 @@ prepare() { if $autogenflag then cd $builddir - ./autogen.sh > $buildlog 2>&1 + ./autogen.sh > $publicbuildlog 2>&1 autogenflag=false cd $OLDPWD fi @@ -40,19 +38,21 @@ prepare() { setarm32ENV host=arm-linux export LDFLAGS="${OHOS_SDK}/native/llvm/lib/clang/$CLANG_VERSION/lib/arm-linux-ohos/a7_hard_neon-vfpv4/libclang_rt.builtins.a ${LDFLAGS}" - fi - if [ $ARCH == "arm64-v8a" ] + elif [ $ARCH == "arm64-v8a" ] then setarm64ENV host=aarch64-linux export LDFLAGS="${OHOS_SDK}/native/llvm/lib/clang/$CLANG_VERSION/lib/aarch64-linux-ohos/libclang_rt.builtins.a ${LDFLAGS}" + else + echo "${ARCH} not support" + return -1 fi } build() { cd $builddir/$ARCH-build # 不强依赖jpeg和libpng, 下方的写法能找到libpng但是找不到jpeg. 显示开启测试 - PKG_CONFIG_PATH="${pkgconfigpath}" libpng_CFLAGS="-I$LYCIUM_ROOT/usr/libpng/$ARCH/include" libpng_LIBS="-L$LYCIUM_ROOT/usr/libpng/$ARCH/lib -lpng" ../configure "$@" --host=$host --enable-tests --disable-go --disable-gdk-pixbuf --disable-aom --disable-libde265 --disable-x265 --disable-rav1e --disable-dav1d --enable-svt > `pwd`/build.log 2>&1 + PKG_CONFIG_LIBDIR="${pkgconfigpath}" libpng_CFLAGS="-I$LYCIUM_ROOT/usr/libpng/$ARCH/include" libpng_LIBS="-L$LYCIUM_ROOT/usr/libpng/$ARCH/lib -lpng" ../configure "$@" --host=$host --enable-tests --enable-go --enable-gdk-pixbuf --enable-aom --enable-libde265 --enable-x265 --enable-rav1e --enable-dav1d --enable-svt > $buildlog 2>&1 $MAKE >> $buildlog 2>&1 ret=$? cd $OLDPWD @@ -62,21 +62,25 @@ build() { package() { cd $builddir/$ARCH-build $MAKE install >> $buildlog 2>&1 + cp ../../$builddir/$ARCH-build/libheif/.libs/libheif.so.1 ../../$builddir/$ARCH-build/tests/ + cd $OLDPWD + unset host if [ $ARCH == "armeabi-v7a" ] then unsetarm32ENV - fi - if [ $ARCH == "arm64-v8a" ] + elif [ $ARCH == "arm64-v8a" ] then unsetarm64ENV + else + echo "${ARCH} not support" + return -1 fi - unset host } check() { cd $builddir/$ARCH-build/tests - sed -i.bak 's|test-local: heif-unit-tests|test-local: #heif-unit-tests|g' Makefile + sed -i '/.*test-local: heif-unit-tests/c\test-local: #heif-unit-tests' Makefile cd $OLDPWD echo "The test must be on an OpenHarmony device!" # real test CMD @@ -84,6 +88,6 @@ check() { } # 清理环境 -cleanbuild(){ +cleanbuild() { rm -rf ${PWD}/$builddir #${PWD}/$packagename -} +} \ No newline at end of file