├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── output.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── sharry │ │ └── demo │ │ └── picturepicker │ │ └── MainActivity.kt │ └── res │ ├── drawable │ ├── app_activity_main_launcher.xml │ └── ic_launcher_foreground.xml │ ├── layout │ └── app_activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-zh │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── provider_paths.xml ├── build.gradle ├── git ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib-picturepicker ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sharry │ │ └── picturepicker │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sharry │ │ │ └── picturepicker │ │ │ ├── camera │ │ │ ├── CameraCallback.java │ │ │ ├── CameraConfig.java │ │ │ ├── CameraRequestFragment.java │ │ │ └── CameraRequestManager.java │ │ │ ├── crop │ │ │ ├── CropCallback.java │ │ │ ├── CropConfig.java │ │ │ ├── PictureCropFragment.java │ │ │ └── PictureCropManager.java │ │ │ ├── picker │ │ │ ├── FolderAdapter.java │ │ │ ├── PickerCallback.java │ │ │ ├── PickerConfig.java │ │ │ ├── PictureAdapter.java │ │ │ ├── PictureFolder.java │ │ │ ├── PicturePickerActivity.java │ │ │ ├── PicturePickerContract.java │ │ │ ├── PicturePickerManager.java │ │ │ ├── PicturePickerModel.java │ │ │ └── PicturePickerPresenter.java │ │ │ ├── support │ │ │ ├── fragment │ │ │ │ └── CallbackFragment.java │ │ │ ├── loader │ │ │ │ ├── IPictureLoader.java │ │ │ │ └── PictureLoader.java │ │ │ ├── permission │ │ │ │ ├── PermissionsCallback.java │ │ │ │ ├── PermissionsFragment.java │ │ │ │ └── PermissionsManager.java │ │ │ └── utils │ │ │ │ ├── ColorUtil.java │ │ │ │ ├── FileUtil.java │ │ │ │ ├── PictureUtil.java │ │ │ │ ├── SharedElementUtils.java │ │ │ │ └── VersionUtil.java │ │ │ ├── watcher │ │ │ ├── PictureWatcherActivity.java │ │ │ ├── PictureWatcherContract.java │ │ │ ├── PictureWatcherManager.java │ │ │ ├── PictureWatcherPresenter.java │ │ │ ├── SharedElementData.java │ │ │ ├── WatcherCallback.java │ │ │ ├── WatcherConfig.java │ │ │ ├── WatcherPagerAdapter.java │ │ │ └── WatcherPreviewAdapter.java │ │ │ └── widget │ │ │ ├── CheckedIndicatorView.java │ │ │ ├── DraggableViewPager.java │ │ │ ├── PicturePickerFabBehavior.java │ │ │ ├── photoview │ │ │ ├── Compat.java │ │ │ ├── CustomGestureDetector.java │ │ │ ├── OnGestureListener.java │ │ │ ├── OnMatrixChangedListener.java │ │ │ ├── OnOutsidePhotoTapListener.java │ │ │ ├── OnPhotoTapListener.java │ │ │ ├── OnScaleChangedListener.java │ │ │ ├── OnSingleFlingListener.java │ │ │ ├── OnViewDragListener.java │ │ │ ├── OnViewTapListener.java │ │ │ ├── PhotoView.java │ │ │ ├── PhotoViewAttacher.java │ │ │ └── Util.java │ │ │ └── toolbar │ │ │ ├── AppBarHelper.java │ │ │ ├── Builder.java │ │ │ ├── ImageViewOptions.java │ │ │ ├── Options.java │ │ │ ├── SToolbar.java │ │ │ ├── Style.java │ │ │ ├── TextViewOptions.java │ │ │ ├── Utils.java │ │ │ └── ViewOptions.java │ └── res │ │ ├── drawable │ │ ├── libpicturepicker_common_arrow_right_white.xml │ │ ├── libpicturepicker_picker_bottom_indicator.xml │ │ ├── libpicturepicker_picker_camera.xml │ │ └── libpicturepicker_picker_fab.xml │ │ ├── layout │ │ ├── libpicturepicker_activity_picture_picker.xml │ │ ├── libpicturepicker_activity_picture_watcher.xml │ │ ├── libpicturepicker_recycle_item_activity_picture_picker_folder.xml │ │ └── libpicturepicker_recycle_item_activity_picture_picker_picture.xml │ │ ├── values-zh │ │ └── libpicturepicker_strings.xml │ │ └── values │ │ ├── libpicturepicker_attrs.xml │ │ ├── libpicturepicker_strings.xml │ │ ├── libpicturepicker_themes.xml │ │ └── libpricturepicker_colors.xml │ └── test │ └── java │ └── com │ └── sharry │ └── picturepicker │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea 38 | 39 | 40 | # Keystore files 41 | *.jks 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 注 2 | PicturePicker 不再维护, 若需要音视频等更多的功能支持, 请移步置 [SAlbum](https://github.com/SharryChoo/SAlbum) 3 | 4 | ## Current Version 5 | [![](https://jitpack.io/v/FrankChoo/PicturePicker.svg)](https://jitpack.io/#FrankChoo/PicturePicker) 6 | - -x 表示使用的是 jetpack androidx 的依赖 7 | - 若使用 AppCompat 将 '-x' 后缀去除即可 8 | 9 | ## How to integration 10 | ### Step 1 11 | Add it in your **root build.gradle** at the end of repositories 12 | ``` 13 | allprojects { 14 | repositories { 15 | ... 16 | maven { url 'https://jitpack.io' } 17 | } 18 | } 19 | ``` 20 | 21 | ### Step 2 22 | Add it in your **module build.gradle** at the end of repositories 23 | ``` 24 | dependencies { 25 | ... 26 | implementation 'com.github.SharryChoo:PicturePicker:+' 27 | implementation 'com.android.support:appcompat-v7:27.+' 28 | implementation 'com.android.support:design:27.+' 29 | implementation 'com.android.support:recyclerview-v7:27.+' 30 | } 31 | ``` 32 | 33 | ## Preview([图片无法显示](http://note.youdao.com/noteshare?id=ee9a0d7909afc4e66b6dda57df10eda6&sub=125F838B572242DBA6B85FE66D89F77C)) 34 | ### 图片裁剪 35 | ![图片裁剪.gif](https://user-gold-cdn.xitu.io/2018/8/6/1650cff2ccf5f4fa?w=282&h=500&f=gif&s=4452628) 36 | 37 | ### 权限与拍照 38 | ![权限与拍照.gif](https://user-gold-cdn.xitu.io/2018/8/6/1650cff2cfcacddc?w=282&h=500&f=gif&s=3251641) 39 | 40 | ### Material Design 动画 41 | ![Material Design 动画.gif](https://user-gold-cdn.xitu.io/2018/8/6/1650cff2cfd00353?w=282&h=500&f=gif&s=3963525) 42 | 43 | ### 共享元素跳转 44 | ![共享元素跳转.gif](https://user-gold-cdn.xitu.io/2018/8/6/1650cff2d58d7b01?w=282&h=500&f=gif&s=4602043) 45 | 46 | ## How to use 47 | ### 图片选择器(集成了拍照和裁剪) 48 | ``` 49 | // 1. Create an instance of PickerConfig. 50 | val pickerConfig = PickerConfig.Builder() 51 | .setThreshold(etAlbumThreshold.text.toString().toInt()) // 一共选中的数量 52 | .setSpanCount(etSpanCount.text.toString().toInt()) // 每行展示的数目 53 | .isToolbarScrollable(true) // Toolbar Behavior 动画 54 | .isFabScrollable(true) // Fab Behavior 动画 55 | .setToolbarBackgroundColor( 56 | ContextCompat.getColor(this, R.color.colorPrimary) 57 | ) // Toolbar 背景设置 58 | .setIndicatorSolidColor( 59 | ContextCompat.getColor(this, R.color.colorPrimary) 60 | ) // 选中指示器的颜色 61 | .setIndicatorBorderColor( 62 | ContextCompat.getColor(this, R.color.colorPrimary), 63 | ContextCompat.getColor(this, android.R.color.white) 64 | ) // 指示器边界的颜色 65 | .setPickerItemBackgroundColor( 66 | ContextCompat.getColor(this, android.R.color.white) 67 | ) // 条目背景色 68 | .setCameraConfig(...) // 设置相机配置, null 表示不启用拍照功能 69 | .setsetCropConfig(...) // 设置裁剪配置, null 表示不启用裁剪功能 70 | .build() 71 | 72 | // 2. Launch picture picker. 73 | PicturePickerManager.with(context) 74 | // 传入我们上面构建的 pickerConfig. 75 | .setPickerConfig( 76 | // 调用 rebuild 方法, 对该实例二次编辑 77 | pickerConfig.rebuild() 78 | ...... 79 | .build() 80 | ) 81 | // 注入图片加载器 82 | .setPictureLoader { context, uri, imageView -> 83 | Glide.with(context).load(uri).into(imageView) 84 | } 85 | .start { 86 | it.forEach { Toast.makeText(this, it, Toast.LENGTH_SHORT).show() } 87 | } 88 | ``` 89 | ### 相机(集成了裁剪) 90 | ``` 91 | // 1. Create an instance of CameraConfig 92 | val cameraConfig = CameraConfig.Builder() 93 | .setFileProviderAuthority("$packageName.FileProvider") // 指定 FileProvider 的 authority, 用于 7.0 获取文件 URI 94 | .setCameraDirectory(APP_DIRECTORY) // 拍照后的图片输出路径 95 | .setCameraQuality(80) // 拍照后图片输出质量 96 | .setCropConfig(...) // 设置裁剪配置, null 表示不启用裁剪功能 97 | .build() 98 | 99 | // 2. Launch camera take. 100 | CameraRequestManager.with(context) 101 | .setConfig( 102 | // 对 cameraConfig 进行二次编辑 103 | cameraConfig.rebuild() 104 | .build() 105 | ) 106 | .take { takePath -> 107 | Toast.makeText(this, takePath, Toast.LENGTH_SHORT).show() 108 | } 109 | ``` 110 | ### 裁剪 111 | ``` 112 | // 1. Create an instance of CropConfig 113 | val cropConfig = CropConfig.Builder() 114 | .setFileProviderAuthority("$packageName.FileProvider") // 指定 FileProvider 的 authority, 用于 7.0 获取文件 URI 115 | .setCropDirectory(APP_DIRECTORY) // 裁剪后的图片输出路径 116 | .setCropSize(1000, 1000) // 裁剪框的尺寸 117 | .setCropQuality(80) // 裁剪后图片输出质量 118 | .build() 119 | 120 | // 2. Launch crop page. 121 | PictureCropManager.with((Context) mView) 122 | .setConfig( 123 | // 对 cropConfig 进行二次编辑 124 | cropConfig.rebuild() 125 | .build() 126 | ) 127 | .crop(this); 128 | ``` 129 | ### 图片查看器 130 | ``` 131 | // 1. Create an instance of WatcherConfig 132 | val watcherConfig = WatcherConfig.Builder() 133 | .setThreshold(mPickerConfig.getThreshold()) // 图片查看器可选图片最大数量 134 | .setIndicatorTextColor(mPickerConfig.getIndicatorTextColor()) // 指示器文本颜色 135 | .setIndicatorSolidColor(mPickerConfig.getIndicatorSolidColor()) // 指示器填充颜色 136 | .setIndicatorBorderColor( 137 | mPickerConfig.getIndicatorBorderCheckedColor(), // 指示器边框选中的颜色 138 | mPickerConfig.getIndicatorBorderUncheckedColor() // 指示器边框未选中颜色 139 | ) 140 | .setPictureUris(mModel.getDisplayPaths(), position) // 要展示的图片集合 141 | .setUserPickedSet(mModel.getPickedPaths()) // 已经选中的图片集合, 传 null, 表示不支持图片选取功能 142 | .build() 143 | 144 | // 2. Launch picture watcher. 145 | PictureWatcherManager.with((Context) mView) 146 | .setSharedElement(sharedElement) // 共享元素动画 147 | .setPictureLoader(PictureLoader.getPictureLoader()) // 图片加载器 148 | .setConfig( 149 | // 配置二次编辑 150 | watcherConfig.rebuild() 151 | .setPictureUris(mModel.getDisplayPaths(), position) 152 | .build() 153 | ) 154 | .startForResult(this)/.start(); 155 | 156 | ``` 157 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | # Built application files 3 | *.apk 4 | *.ap_ 5 | 6 | # Files for the ART/Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Intellij 37 | *.iml 38 | .idea/workspace.xml 39 | 40 | # Keystore files 41 | *.jks -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | android { 7 | compileSdkVersion rootProject.compileSdkVersion 8 | defaultConfig { 9 | minSdkVersion rootProject.minSdkVersion 10 | targetSdkVersion rootProject.targetSdkVersion 11 | vectorDrawables.useSupportLibrary true 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation fileTree(include: ['*.jar'], dir: 'libs') 17 | kapt "com.github.bumptech.glide:compiler:$glideVersion" 18 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" 19 | implementation "com.android.support:appcompat-v7:$supportLibraryVersion" 20 | implementation "com.android.support:design:$supportLibraryVersion" 21 | implementation "com.android.support:recyclerview-v7:$supportLibraryVersion" 22 | implementation "com.github.bumptech.glide:glide:$glideVersion" 23 | implementation project(':lib-picturepicker') 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":-1},"path":"app-release.apk","properties":{"packageId":"frank.demo.photopicker","split":"","minSdkVersion":"19"}}] -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SharryChoo/PicturePicker/3c6f9c7b9d396972c3509428c42ca5d5af323304/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/sharry/demo/picturepicker/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package sharry.demo.picturepicker 2 | 3 | import android.os.Bundle 4 | import android.os.Environment 5 | import android.support.v4.content.ContextCompat 6 | import android.support.v7.app.AppCompatActivity 7 | import android.text.TextUtils 8 | import android.widget.Toast 9 | import com.bumptech.glide.Glide 10 | import com.bumptech.glide.load.engine.DiskCacheStrategy 11 | import com.bumptech.glide.request.RequestOptions 12 | import com.sharry.picturepicker.camera.CameraConfig 13 | import com.sharry.picturepicker.crop.CropConfig 14 | import com.sharry.picturepicker.picker.PickerConfig 15 | import com.sharry.picturepicker.picker.PicturePickerManager 16 | import com.sharry.picturepicker.widget.toolbar.SToolbar 17 | import kotlinx.android.synthetic.main.app_activity_main.* 18 | import java.io.File 19 | 20 | private val APP_DIRECTORY = "${Environment.getExternalStorageDirectory().absolutePath}${File.separator}PicturePicker" 21 | 22 | /** 23 | * PicturePicker 示例 Activity. 24 | * 25 | * @author Sharry Contact me. 26 | * @version 1.0 27 | * @since 12/6/2018 10:49 AM 28 | */ 29 | class MainActivity : AppCompatActivity() { 30 | 31 | private lateinit var pickerConfig: PickerConfig 32 | private lateinit var cameraConfig: CameraConfig 33 | private lateinit var cropConfig: CropConfig 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | setContentView(R.layout.app_activity_main) 38 | initTitle() 39 | initViews() 40 | initData() 41 | } 42 | 43 | private fun initTitle() { 44 | SToolbar.Builder(this) 45 | .setBackgroundColorRes(R.color.colorPrimary) 46 | .setTitleText(getString(R.string.app_name)) 47 | .apply() 48 | } 49 | 50 | private fun initData() { 51 | cameraConfig = CameraConfig.Builder() 52 | .setFileProviderAuthority("$packageName.FileProvider") // 指定 FileProvider 的 authority, 用于 7.0 获取文件 URI 53 | .setCameraDirectory(APP_DIRECTORY) // 相机文件存储路径 54 | .setCameraQuality(80) 55 | .build() 56 | 57 | cropConfig = CropConfig.Builder() 58 | .setCropDirectory(APP_DIRECTORY) // 裁剪文件存储路径 59 | .setCropSize(1000, 1000) 60 | .setCropQuality(80) 61 | .build() 62 | 63 | pickerConfig = PickerConfig.Builder() 64 | .setThreshold(etAlbumThreshold.text.toString().toInt())// 一共选中的数量 65 | .setSpanCount(etSpanCount.text.toString().toInt())// 每行展示的数目 66 | .isToolbarScrollable(cbAnimation.isChecked)// Behavior 动画 67 | .isFabScrollable(cbAnimation.isChecked) 68 | .setToolbarBackgroundColor( 69 | ContextCompat.getColor(this, R.color.colorPrimary) 70 | ) // Toolbar 背景设置 71 | .setIndicatorSolidColor( 72 | ContextCompat.getColor(this, R.color.colorPrimary) 73 | )// 选中指示器的颜色 74 | .setIndicatorBorderColor( 75 | ContextCompat.getColor(this, R.color.colorPrimary), 76 | ContextCompat.getColor(this, android.R.color.white) 77 | )// 指示器边界的颜色 78 | .setPickerItemBackgroundColor( 79 | ContextCompat.getColor(this, android.R.color.white) 80 | )// 条目背景色 81 | .build() 82 | } 83 | 84 | private fun initViews() { 85 | btnLaunchAlbum.setOnClickListener { _ -> 86 | if (TextUtils.isEmpty(etAlbumThreshold.text) || TextUtils.isEmpty(etSpanCount.text)) { 87 | return@setOnClickListener 88 | } 89 | PicturePickerManager.with(this) 90 | .setPickerConfig( 91 | pickerConfig.rebuild() 92 | .setThreshold(etAlbumThreshold.text.toString().toInt())// 一共选中的数量 93 | .setSpanCount(etSpanCount.text.toString().toInt())// 每行展示的数目 94 | .isToolbarScrollable(cbAnimation.isChecked) 95 | .isFabScrollable(cbAnimation.isChecked) 96 | .setCameraConfig( 97 | if (cbCamera.isChecked) cameraConfig else null 98 | ) 99 | .setCropConfig( 100 | if (cbCrop.isChecked) cropConfig else null 101 | ) 102 | .build() 103 | ) 104 | // 图片加载框架注入 105 | .setPictureLoader { context, uri, imageView -> 106 | val options = RequestOptions() 107 | .override(imageView.width, imageView.height) 108 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) 109 | Glide.with(context) 110 | .load(uri) 111 | .apply(options) 112 | .into(imageView) 113 | } 114 | .start { 115 | it.forEach { Toast.makeText(this, it, Toast.LENGTH_SHORT).show() } 116 | } 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_activity_main_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 14 | 17 | 20 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 26 | 27 | 28 | 29 | 34 | 35 | 46 | 47 | 48 | 49 | 53 | 54 | 59 | 60 | 66 | 67 | 73 | 74 | 75 | 76 |