Commit 40bc6bdf authored by 王雷's avatar 王雷

兼容gradle7.0以上版本

parent 36e5663d
GradlePlugin
\ No newline at end of file
......@@ -71,5 +71,25 @@
<option name="name" value="maven10" />
<option name="url" value="https://dl.bintray.com/umsdk/release" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/google" />
</remote-repository>
<remote-repository>
<option name="id" value="maven7" />
<option name="name" value="maven7" />
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/releases/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/jcenter" />
</remote-repository>
</component>
</project>
\ No newline at end of file
......@@ -6,22 +6,22 @@
* User Manual available at https://docs.gradle.org/6.6.1/userguide/custom_plugins.html
*/
buildscript {
ext.kotlin_version = '1.4.10'
ext.kotlin_version = '1.6.10'
repositories {
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }//阿里云镜像服务
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }//阿里云镜像服务
maven { url 'http://developer.huawei.com/repo/' }
maven { url 'https://developer.huawei.com/repo/' }
maven { url 'https://jitpack.io' }
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
url 'https://maven.aliyun.com/nexus/content/repositories/releases/'
}
maven {
......@@ -31,36 +31,37 @@ buildscript {
maven {
url 'https://hub.zmcms.cn/repository/maven-public/'
}
maven { url 'https://dl.bintray.com/umsdk/release' }
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies{
classpath "com.whl:gradle-publish-plugin:0.1.16-SNAPSHOT"
}
}
plugins {
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
id 'java-gradle-plugin'
// Apply the Groovy plugin to add support for Groovy
id 'groovy'
id 'maven'
id 'java'
id 'maven-publish'
id "org.jetbrains.kotlin.jvm" version "1.4.10"
}
apply plugin: "com.whl.gradle-publish-plugin"
repositories {
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }//阿里云镜像服务
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }//阿里云镜像服务
maven { url 'http://developer.huawei.com/repo/' }
maven { url 'https://developer.huawei.com/repo/' }
maven { url 'https://jitpack.io' }
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
url 'https://maven.aliyun.com/nexus/content/repositories/releases/'
}
maven {
......@@ -70,8 +71,6 @@ repositories {
maven {
url 'https://hub.zmcms.cn/repository/maven-public/'
}
maven { url 'https://dl.bintray.com/umsdk/release' }
maven { url 'https://developer.huawei.com/repo/' }
}
......@@ -88,9 +87,8 @@ dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
// Use the awesome Spock testing and specification framework
implementation 'com.android.tools.build:gradle:4.2.0'
implementation 'com.android.tools.build:gradle:7.0.3'
testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
implementation gradleApi()
compile 'org.json:json:20090211'
compile 'com.squareup.okhttp:okhttp:2.2.0'
......@@ -102,7 +100,6 @@ dependencies {
implementation 'com.aliyun.oss:aliyun-sdk-oss:3.10.2'
implementation "com.squareup.okhttp3:okhttp:4.9.1"
implementation 'com.google.code.gson:gson:2.8.8'
}
gradlePlugin {
......@@ -110,7 +107,7 @@ gradlePlugin {
/* plugins {
greeting {
id = 'GradlePlugin.greeting'
implementationClass = 'GradlePlugin.GradlePluginPlugin'
implementationClass = 'com.qmai.android.plugin.GradlePluginPlugin'
}
jiagu{
id = 'GradlePlugin.jiagu'
......@@ -126,7 +123,7 @@ gradlePlugin {
plugins {
buildAndPyger {
id = 'GradlePlugin.buildAndPyger'
implementationClass = 'GradlePlugin.PygerBuildAndUploadPlugin'
implementationClass = 'com.qmai.android.plugin.PygerBuildAndUploadPlugin'
}
}
plugins {
......@@ -138,7 +135,7 @@ gradlePlugin {
plugins {
pygerUpload {
id = 'GradlePlugin.pygerUpload'
implementationClass = 'GradlePlugin.PygerUploadPlugin'
implementationClass = 'com.qmai.android.plugin.PygerUploadPlugin'
}}
plugins {
hotfix {
......@@ -147,8 +144,32 @@ gradlePlugin {
}
}
}
/*
publishing{
publications{
mavenJava(MavenPublication) {
groupId = "com.qmai.android.plugin"
artifactId = "AndroidPlugins"
version = "1.46"
}
}
repositories {
maven {
allowInsecureProtocol true
url = "https://hub.zmcms.cn/repository/maven-releases/"
credentials {
username = "wanglei1"
password = "woshiwanglei123"
}
}
}
}*/
uploadArchives {
/*uploadArchives {
repositories.mavenDeployer {
repository(url: uri('https://hub.zmcms.cn/repository/maven-releases/')) {
authentication(userName: 'wanglei1', password: 'woshiwanglei123')
......@@ -156,15 +177,15 @@ uploadArchives {
}
pom.groupId = "com.qmai.android.plugin"// 唯一标识(通常为模块包名,也可以任意)
pom.artifactId = "AndroidPlugins" // 项目名称(通常为类库模块名称,也可以任意)
pom.version = "1.38" // 版本号
pom.version = "1.46" // 版本号
// pom.version = "1.48-SNAPSHOT"
/* snapshotRepository(url: 'https://hub.zmcms.cn/repository/maven-snapshots/') {
*//* snapshotRepository(url: 'https://hub.zmcms.cn/repository/maven-snapshots/') {
authentication(userName: 'wanglei1', password: 'woshiwanglei123')
}*/
}*//*
}
}
}*/
// Add a source set for the functional test suite
sourceSets {
functionalTest {
......@@ -228,7 +249,28 @@ task hot{
}}
}
group 'com.qmai.android.plugin'
version '1.90'
gradlePublish {
sourceJarEnabled = true
javaDocEnabled = false
signEnabled = false
releaseRepository {
url = "https://hub.zmcms.cn/repository/maven-releases/"
userName = "wanglei1"
password = "woshiwanglei123"
}
/* snapshotRepository {
url = "https://hub.zmcms.cn/repository/maven-snapshots/"
userName = "wanglei1"
password = "woshiwanglei123"
}*/
}
/* userName USER_NAME
userPassword USER_PASSWORD
......
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
#org.gradle.jvmargs=-Xmx4096m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
package GradlePlugin
class PygerBean {
String filePath
String key = "cd6545d205ac6cc379bb1d6e3ce71bed"
}
\ No newline at end of file
package GradlePlugin
package com.qmai.android.plugin
import org.gradle.api.Project
import org.gradle.api.Plugin
......
package GradlePlugin
package com.qmai.android.plugin
class DingDingDetailInfoModel {
String content
......
package GradlePlugin
package com.qmai.android.plugin
/*
con={"msgtype":"text","text":{"content":content}}
*/
......
/*
* This Groovy source file was generated by the Gradle 'init' task.
*/
package GradlePlugin
package com.qmai.android.plugin
import com.aliyun.oss.OSS
import com.aliyun.oss.OSSClientBuilder
import com.google.protobuf.ServiceException
import com.squareup.okhttp.OkHttpClient
import org.gradle.api.Project
import org.gradle.api.Plugin
......
package com.qmai.android.plugin
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
/***
* 自动打包且上传后指定oss的路径
*/
class OssBean {
String ossPath
@Input String ossPath
}
\ No newline at end of file
......@@ -9,7 +9,6 @@ class OssFileUploadPlugin implements Plugin<Project> {
//单独上传任务的task
OssUploadFileBean ossUploadFileBean = project.getExtensions().create("uploadOss",OssUploadFileBean.class)
project.afterEvaluate {
def uploadFile = new File(ossUploadFileBean.localPath)
println("single upload file "+uploadFile.exists() + " "+uploadFile.absolutePath)
project.getTasks().create("uploadOssFile", OssUploadTask.class, uploadFile,ossUploadFileBean.ossPath,"")
......
package com.qmai.android.plugin
import org.gradle.api.tasks.Input
/***
* oss 上传需要的参数
*/
......
package com.qmai.android.plugin
import GradlePlugin.DingDingDetailInfoModel
import GradlePlugin.DingDingInfoModel
import com.aliyun.oss.OSS
import com.aliyun.oss.OSSClientBuilder
import com.aliyun.oss.model.PutObjectRequest
......@@ -11,19 +10,19 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecSpec
import org.json.JSONObject
import javax.inject.Inject
import java.util.concurrent.TimeUnit
class OssUploadTask extends DefaultTask {
File file
String ossPath = "appfile/demo/"
String buildType;
@OutputFile File file;
@Input String ossPath = "appfile/demo/"
@Input String buildType;
@Inject
OssUploadTask(File file, String ossPath,buildType) {
......@@ -36,6 +35,7 @@ class OssUploadTask extends DefaultTask {
@TaskAction
void upload() {
println("-----------开始上传了")
def fileName = file.getName()
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "https://oss-cn-shanghai.aliyuncs.com"
......@@ -74,7 +74,6 @@ class OssUploadTask extends DefaultTask {
ossClient.shutdown()
//钉钉通知
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
JSONObject json = new JSONObject()
def gson = new Gson()
def content = "qmshopassitant: 下载地址为: " + "https://files.qmai.cn/" + ossPath + fileName+" 当前环境: "+buildType +" 当前分支: "+getBranch()
def dingDingdetail = new DingDingDetailInfoModel(content)
......@@ -102,6 +101,7 @@ class OssUploadTask extends DefaultTask {
}
@Input
boolean isInJenkins() {
Map<String, String> map = System.getenv()
if (map == null) {
......@@ -122,6 +122,7 @@ class OssUploadTask extends DefaultTask {
}
//获取当前分支
@Input
String getBranch() {
if (isInJenkins()) {
return System.getenv().GIT_BRANCH
......@@ -135,7 +136,7 @@ class OssUploadTask extends DefaultTask {
return response
}
return response
return ""
}
}
package com.qmai.android.plugin
import org.gradle.api.tasks.Input
class PygerBean {
String filePath
String key = "cd6545d205ac6cc379bb1d6e3ce71bed"
}
\ No newline at end of file
package GradlePlugin
package com.qmai.android.plugin
class PygerBuildAndUploadBean {
String filePath
......
package GradlePlugin
package com.qmai.android.plugin
import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.ApplicationVariant
......@@ -13,22 +13,8 @@ import org.gradle.api.Project
class PygerBuildAndUploadPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def map = System.getenv()
map.entrySet().forEach{
println(" name= "+it.key+ "value= "+it.value)
}
println("000000---------------------------"+System.getenv().GIT_BRANCH)
def byteOut = new ByteArrayOutputStream(
)
project.exec {
it.commandLine("git", "branch")
it.standardOutput = byteOut
}
def response = new String(byteOut.toByteArray())
println("---------git branch122"+response)
PygerBean PygerBean = project.getExtensions().create("BuildAndPygerInfo", PygerBean.class)
PygerBean pygerBean = project.getExtensions().create("BuildAndPygerInfo", PygerBean.class)
project.afterEvaluate {
// AppExtension app = project.
AppExtension app = project.getExtensions().findByType(AppExtension.class)
app.getApplicationVariants().all(new Action<ApplicationVariant>() {
@Override
......@@ -37,10 +23,8 @@ class PygerBuildAndUploadPlugin implements Plugin<Project> {
applicationVariant.outputs.all(new Action<BaseVariantOutput>() {
@Override
void execute(BaseVariantOutput baseVariantOutput) {
File flie = baseVariantOutput.getOutputFile()
def task = project.getTasks().create("buildAndPyger" + firstLetterUpper(name), PygerUploadTask.class, flie,PygerBean,firstLetterUpper(name))
def task = project.getTasks().create("BuildAndPyger" + firstLetterUpper(name), PygerUploadTask.class, baseVariantOutput.getOutputFile(),firstLetterUpper(name),pygerBean.key)
//先编译
//task.dependsOn("clean")
task.dependsOn("assemble" + firstLetterUpper(name))
}
})
......
package GradlePlugin
import com.android.tools.r8.graph.S
package com.qmai.android.plugin
class PygerInfoBean {
......
package GradlePlugin
package com.qmai.android.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
......@@ -12,7 +12,9 @@ class PygerUploadPlugin implements Plugin<Project> {
PygerBean pygerBean = project.getExtensions().create("pyger", PygerBean.class)
project.afterEvaluate {
project.getTasks().create("pygerUpload", PygerUploadTask.class, new File(pygerBean.filePath), pygerBean,"")
def uploadFile = new File(pygerBean.filePath)
println("PygerUploadPlugin file path = "+pygerBean.filePath+" file key = "+pygerBean.key)
project.getTasks().create("pygerUpload", PygerUploadTask.class, uploadFile,"1", pygerBean.key)
}
}
}
package com.qmai.android.plugin
import com.google.gson.Gson
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import java.util.concurrent.TimeUnit
class PygerUploadTask extends DefaultTask {
@OutputFile File file;
@Input String buildType;
@Input String key;
@Inject
PygerUploadTask(File file, String buildType, String key) {
this.file = file
this.buildType = buildType
this.key = key
setGroup("pyger")
}
@TaskAction
public void upload() {
println("-------执行upload")
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM)
//add part
bodyBuilder.addFormDataPart("_api_key", key)
//add file
bodyBuilder.addFormDataPart("file", file.getName(), RequestBody
.create(MediaType.parse("*/*"), file))
//request
Request request = new Request.Builder()
.url("https://www.pgyer.com/apiv2/app/upload")
.post(bodyBuilder.build())
.build()
OkHttpClient client = new OkHttpClient.Builder()
.callTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
try {
println("开始上传蒲公英")
Response response = client.newCall(request).execute()
String result = response.body().string()
Gson gson = new Gson()
PygerInfoBean payInfoBean = gson.fromJson(result, PygerInfoBean.class)
println("下载地址为: downloadUrl:" + " https://www.pgyer.com/" + payInfoBean.data.buildShortcutUrl)
println("二维码地址为:" + payInfoBean.data.buildQRCodeURL)
System.out.println("upload result: " + result)
def branch = ""
try {
branch = getBranch()
}catch (Exception e) {
e.printStackTrace();
println("getBranch error = "+e.message)
}
String content = file.name + ": 下载地址: " + " https://www.pgyer.com/" +
payInfoBean.data.buildShortcutUrl + " \n二维码地址: " + payInfoBean.data.buildQRCodeURL + " 当前环境: " + buildType + " 当前分支:" + branch
println("dingding content = ${content}")
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
JSONObject json = new JSONObject()
try {
json.put("msgtype", "text:{\"content\":$content}")
json.put("text", content)
def dingDingdetail = new DingDingDetailInfoModel(content)
def dingdingInfo = new DingDingInfoModel(dingDingdetail)
RequestBody requestBody = RequestBody.create(JSON, gson.toJson(dingdingInfo))
Request request2 = new Request.Builder()
.url("https://oapi.dingtalk.com/robot/send?access_token=9839926e22043a7d391747e3cb14cc4e0dab7add001ce60f0d184f82e50301bc")
.post(requestBody)
.build()
Response response2 = client.newCall(request2).execute()
String value = response2.body().string()
println("value= " + value)
} catch (JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace()
println("-----------------上传失败----------------")
println("错误原因: " + e.getMessage())
} catch (Exception e) {
println("-----------------上传失败----------------")
println("错误原因: " + e.getMessage())
}
}
@Input
boolean isInJenkins() {
Map<String, String> map = System.getenv()
if (map == null) {
return false
}
String str = map.get("Path")
if (str != null) {
//it's windows
return false
} else {
str = ""
Iterator it = map.iterator()
while (it.hasNext()) {
str += it.next()
}
return str.contains("jenkins")
}
return false;
}
//获取当前分支
@Input
String getBranch() {
if (isInJenkins()) {
return System.getenv().GIT_BRANCH
} else {
def byteOut = new ByteArrayOutputStream()
project.exec {
it.commandLine("git", "rev-parse", "--abbrev-ref", "HEAD")
it.standardOutput = byteOut
}
def response = new String(byteOut.toByteArray())
return response
}
}
}
package GradlePlugin
package com.qmai.android.plugin
import com.aliyun.oss.OSS
import com.aliyun.oss.OSSClientBuilder
import com.google.gson.Gson
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.OkHttp
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.gradle.api.Action
import okhttp3.*
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.impldep.com.amazonaws.services.s3.model.PutObjectRequest
import org.gradle.internal.impldep.com.google.gson.JsonObject
import org.gradle.process.ExecSpec
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import java.util.concurrent.TimeUnit
class PygerUploadTask extends DefaultTask {
File file;
PygerBean pygerBean;
String buildType;
class PygerUploadTask2 extends DefaultTask {
@OutputFile File file;
@Input String buildType;
@Input String key;
@Inject
public PygerUploadTask(File file, PygerBean pygerBean, String buildType) {
PygerUploadTask2(File file, String buildType, String key) {
this.file = file
this.pygerBean = pygerBean
this.buildType = buildType
this.key = key
setGroup("pyger")
}
@TaskAction
public void upload() {
println("-------执行upload")
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM)
//add part
bodyBuilder.addFormDataPart("_api_key", pygerBean.key)
bodyBuilder.addFormDataPart("_api_key", key)
//add file
bodyBuilder.addFormDataPart("file", file.getName(), RequestBody
.create(MediaType.parse("*/*"), file))
......@@ -66,7 +57,8 @@ class PygerUploadTask extends DefaultTask {
println("下载地址为: downloadUrl:" + " https://www.pgyer.com/" + payInfoBean.data.buildShortcutUrl)
println("二维码地址为:" + payInfoBean.data.buildQRCodeURL)
System.out.println("upload result: " + result)
String content = file.name + ": 下载地址: " + " https://www.pgyer.com/" + payInfoBean.data.buildShortcutUrl + " \n二维码地址: " + payInfoBean.data.buildQRCodeURL + " 当前环境: " + buildType + " 当前分支: " + getBranch()
String content = file.name + ": 下载地址: " + " https://www.pgyer.com/" + payInfoBean.data.buildShortcutUrl + " \n二维码地址: " + payInfoBean.data.buildQRCodeURL + " 当前环境: " + buildType + " 当前分支: "
//+ getBranch()
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
JSONObject json = new JSONObject()
try {
......@@ -99,6 +91,7 @@ class PygerUploadTask extends DefaultTask {
}
}
@Input
boolean isInJenkins() {
Map<String, String> map = System.getenv()
if (map == null) {
......@@ -116,10 +109,13 @@ class PygerUploadTask extends DefaultTask {
}
return str.contains("jenkins")
}
return false;
}
//获取当前分支
@Input
String getBranch() {
return "";
if (isInJenkins()) {
return System.getenv().GIT_BRANCH
} else {
......
class PygerBean {
var key:String?=null
}
\ No newline at end of file
package com.qmai.android.plugin.alihotfix
import com.android.repository.util.InstallerUtil.unzip
import com.qmai.android.plugin.ZipUtils
import org.apache.tools.ant.taskdefs.condition.Os
......
/*
* This Groovy source file was generated by the Gradle 'init' task.
*/
package GradlePlugin
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.api.Project
import spock.lang.Specification
/**
* A simple unit test for the 'GradlePlugin.greeting' plugin.
*/
public class GradlePluginPluginTest extends Specification {
def "plugin registers task"() {
given:
def project = ProjectBuilder.builder().build()
when:
project.plugins.apply("GradlePlugin.greeting")
then:
project.tasks.findByName("greeting") != null
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment