From 57730ee5e7712043f8f00481d0a486e3482c87a2 Mon Sep 17 00:00:00 2001 From: Johann Bernhardt Date: Thu, 2 Dec 2021 10:14:36 +0100 Subject: [PATCH] Migrated to unified build script --- .gitattributes | 16 - .github/scripts/test-no-crash-reports.sh | 9 + .github/workflows/build-and-test.yml | 45 ++ .github/workflows/release-tags.yml | 45 ++ .gitignore | 66 +-- build.gradle | 593 +++++++++++++++++------ dependencies.gradle | 18 + eclipseFormat.xml | 295 ----------- gradle.properties | 68 ++- gradle/wrapper/gradle-wrapper.jar | Bin 55627 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 22 +- gradlew.bat | 18 +- jitpack.yml | 2 + repositories.gradle | 14 + settings.gradle | 1 - src/api/resources/nei_at.cfg | 13 - src/main/java/team/chisel/Chisel.java | 2 +- src/main/resources/mcmod.info | 8 +- 19 files changed, 697 insertions(+), 540 deletions(-) delete mode 100644 .gitattributes create mode 100644 .github/scripts/test-no-crash-reports.sh create mode 100644 .github/workflows/build-and-test.yml create mode 100644 .github/workflows/release-tags.yml create mode 100644 dependencies.gradle delete mode 100644 eclipseFormat.xml create mode 100644 jitpack.yml create mode 100644 repositories.gradle delete mode 100644 settings.gradle delete mode 100644 src/api/resources/nei_at.cfg diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index eb046c03..00000000 --- a/.gitattributes +++ /dev/null @@ -1,16 +0,0 @@ -# text stuff -*.java text -*.sh text eol=lf -*.bat text eol=crlf -*.md text - -#binary -*.dat binary -*.bin binary -*.png binary -*.exe binary -*.dll binary -*.zip binary -*.jar binary -*.7z binary -*.db binary \ No newline at end of file diff --git a/.github/scripts/test-no-crash-reports.sh b/.github/scripts/test-no-crash-reports.sh new file mode 100644 index 00000000..c67e342c --- /dev/null +++ b/.github/scripts/test-no-crash-reports.sh @@ -0,0 +1,9 @@ +directory="run/crash-reports" +if [ -d $directory ]; then + echo "Crash reports detected:" + cat $directory/* + exit 1 +else + echo "No crash reports detected" + exit 0 +fi diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..a60a2b64 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,45 @@ +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Build and test + +on: + pull_request: + branches: [ master, main ] + push: + branches: [ master, main ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup the workspace + run: ./gradlew setupCIWorkspace + + - name: Build the mod + run: ./gradlew build + + - name: Run server for 1 minute + run: | + mkdir run + echo "eula=true" > run/eula.txt + timeout 60 ./gradlew runServer || true + + - name: Test no crashes happend + run: | + chmod +x .github/scripts/test-no-crash-reports.sh + .github/scripts/test-no-crash-reports.sh diff --git a/.github/workflows/release-tags.yml b/.github/workflows/release-tags.yml new file mode 100644 index 00000000..25c354b2 --- /dev/null +++ b/.github/workflows/release-tags.yml @@ -0,0 +1,45 @@ +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Release tagged build + +on: + push: + tags: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set release version + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup the workspace + run: ./gradlew setupCIWorkspace + + - name: Build the mod + run: ./gradlew build + + - name: Release under current tag + uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "${{ env.RELEASE_VERSION }}" + prerelease: false + title: "${{ env.RELEASE_VERSION }}" + files: build/libs/*.jar diff --git a/.gitignore b/.gitignore index c2c3c13d..558ad12d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,28 @@ -#eclipse -.project +.gradle +.settings +/.idea/ +/run/ +/build/ +/eclipse/ .classpath -.metadata -org.* -bin - -#idea -.idea +.project +/bin/ +/config/ +/crash-reports/ +/logs/ +options.txt +/saves/ +usernamecache.json +banned-ips.json +banned-players.json +eula.txt +ops.json +server.properties +servers.dat +usercache.json +whitelist.json +/out/ *.iml *.ipr *.iws -out -classes - -#gradle -build -.gradle - -#runtime -eclipse -run - -#mac -.DS_Store -*.command - -#windows -Thumbs.db - -#workspace -saves -asm -logs -screenshots -mods -lib -libs -#config I assume you want to keep your minecraft config and world out -#world this is taken care of with the run folder up at runtime you are actually removing the packages - -*.json -/server.properties -*.dat -*.psd -*.bat +src/main/resources/mixins.*.json diff --git a/build.gradle b/build.gradle index e3c2301c..a380f6c7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,34 @@ +//version: ffe7b130f98fdfa1ac7c6ba4bd34722a55ab28d4 +/* +DO NOT CHANGE THIS FILE! + +Also, you may replace this file at any time if there is an update available. +Please check https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/build.gradle for updates. + */ + + +import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +import java.util.concurrent.TimeUnit + buildscript { repositories { - mavenCentral() maven { - name = "gt" - url = "https://gregtech.overminddl1.com/" + name = "forge" + url = "https://maven.minecraftforge.net" } maven { name = "sonatype" url = "https://oss.sonatype.org/content/repositories/snapshots/" } maven { - name = "jitpack.io" - url = "https://jitpack.io" + name = "Scala CI dependencies" + url = "https://repo1.maven.org/maven2/" } maven { - name = 'ajoberstar-backup' - url = 'https://ajoberstar.org/bintray-backup/' + name = "jitpack" + url = "https://jitpack.io" } } dependencies { @@ -24,207 +37,481 @@ buildscript { } plugins { - // project.grgit is not available and the repository we're working in is not - // interacted with: - id 'org.ajoberstar.grgit' version '4.0.2' apply false + id 'idea' + id 'scala' + id("org.ajoberstar.grgit") version("3.1.1") + id("com.github.johnrengelman.shadow") version("4.0.4") + id("com.palantir.git-version") version("0.12.3") } -// An explicit import is necessary because the plugin was not applied: -import org.ajoberstar.grgit.Grgit apply plugin: 'forge' -apply plugin: 'java' -apply plugin: 'idea' -apply plugin: 'signing' -apply plugin: 'java-library' -apply plugin: 'maven-publish' -compileJava { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - options.encoding = "UTF-8" +def projectJavaVersion = JavaLanguageVersion.of(8) + +java { + toolchain { + languageVersion.set(projectJavaVersion) + } } -def repo = Grgit.open() -project.ext.gitHash = repo.log().find().abbreviatedId -def branchname = repo.branch.getCurrent().fullName -if (branchname.contains('HEAD')) { - branchname = System.getenv("GIT_BRANCH") +idea { + module { + inheritOutputDirs = true + downloadJavadoc = true + downloadSources = true + } } -branchname = branchname.substring(branchname.lastIndexOf('/') + 1) -boolean dev = System.getenv("RELEASE") == null || System.getenv("RELEASE").equalsIgnoreCase("false") +if(JavaVersion.current() != JavaVersion.VERSION_1_8) { + throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current()) +} -ext.buildnumber = 0 -project.buildnumber = System.getenv('BUILD_NUMBER') == null ? "CUSTOM" : System.getenv('BUILD_NUMBER') +checkPropertyExists("modName") +checkPropertyExists("modId") +checkPropertyExists("modGroup") +checkPropertyExists("autoUpdateBuildScript") +checkPropertyExists("minecraftVersion") +checkPropertyExists("forgeVersion") +checkPropertyExists("replaceGradleTokenInFile") +checkPropertyExists("gradleTokenModId") +checkPropertyExists("gradleTokenModName") +checkPropertyExists("gradleTokenVersion") +checkPropertyExists("gradleTokenGroupName") +checkPropertyExists("apiPackage") +checkPropertyExists("accessTransformersFile") +checkPropertyExists("usesMixins") +checkPropertyExists("mixinPlugin") +checkPropertyExists("mixinsPackage") +checkPropertyExists("coreModClass") +checkPropertyExists("containsMixinsAndOrCoreModOnly") +checkPropertyExists("usesShadowedDependencies") +checkPropertyExists("developmentEnvironmentUserName") -version = dev ? "${branchname}-${buildnumber}-${project.ext.gitHash}" : "${mod_version}.${buildnumber}" -group = "team.chisel" // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = "Chisel" +def checkPropertyExists(String propertyName) { + if (project.hasProperty(propertyName) == false) { + throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/gradle.properties") + } +} + + +String javaSourceDir = "src/main/java/" +String scalaSourceDir = "src/main/scala/" + +String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") +String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") +if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { + throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala) +} + +if(apiPackage) { + targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { + throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala) + } +} + +if(accessTransformersFile) { + String targetFile = "src/main/resources/META-INF/" + accessTransformersFile + if(new File(targetFile).exists() == false) { + throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) + } +} + +if(usesMixins.toBoolean()) { + if(mixinsPackage.isEmpty() || mixinPlugin.isEmpty()) { + throw new GradleException("\"mixinPlugin\" requires \"mixinsPackage\" and \"mixinPlugin\" to be set!") + } + + targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") + targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") + if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { + throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala) + } + + String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" + String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala" + String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" + if((new File(targetFileJava).exists() || new File(targetFileScala).exists() || new File(targetFileScalaJava).exists()) == false) { + throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava) + } +} + +if(coreModClass) { + String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" + String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala" + String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" + if((new File(targetFileJava).exists() || new File(targetFileScala).exists() || new File(targetFileScalaJava).exists()) == false) { + throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava) + } +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) + + // Make sure GregTech build won't time out + System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String) + System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String) +} + +// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version +'git config core.fileMode false'.execute() +// Pulls version from git tag +try { + version = minecraftVersion + "-" + gitVersion() +} +catch (Exception e) { + throw new IllegalStateException("This mod must be version controlled by Git AND the repository must provide at least one tag!"); +} +group = modGroup +archivesBaseName = modId minecraft { - version = "${minecraft_version}-${forge_version}" + version = minecraftVersion + "-" + forgeVersion + "-" + minecraftVersion runDir = "run" - replaceIn "Chisel.java" - replace "@VERSION@", project.version + if (replaceGradleTokenInFile) { + replaceIn replaceGradleTokenInFile + if(gradleTokenModId) { + replace gradleTokenModId, modId + } + if(gradleTokenModName) { + replace gradleTokenModName, modName + } + if(gradleTokenVersion) { + replace gradleTokenVersion, versionDetails().lastTag + } + if(gradleTokenGroupName) { + replace gradleTokenGroupName, modGroup + } + } } +if(file("addon.gradle").exists()) { + apply from: "addon.gradle" +} + +apply from: 'repositories.gradle' + configurations { - shade - compile.extendsFrom shade - compile.extendsFrom exportedCompile + implementation.extendsFrom(shadowImplementation) } repositories { maven { - name = "gt" + name = "Overmind forge repo mirror" url = "https://gregtech.overminddl1.com/" } - - maven { - name 'Chicken Bones Repo' - url "http://chickenbones.net/maven/" + if(usesMixins.toBoolean()) { + maven { + name = "sponge" + url = "https://repo.spongepowered.org/repository/maven-public" + } + maven { + url = "https://jitpack.io" + } } - - maven { - name 'Prof Mobius Repo' - url "http://mobiusstrip.eu/maven" - } - - maven { - name 'Chisel Repo' - url "http://maven.tterrag.com/" - } - maven { - name = "jitpack.io" - url = "https://jitpack.io" - } - ivy { - name = "gtnh_download_source_ee3" - artifactPattern("http://downloads.gtnewhorizons.com/Mods_for_Jenkins/[module]-[revision].[ext]") - } - - } dependencies { - compile "mcp.mobius.waila:Waila:${waila_version}_${minecraft_version}:dev" - compile "com.github.GTNewHorizons:CodeChickenLib:master-SNAPSHOT:dev" - compile "com.github.GTNewHorizons:CodeChickenCore:master-SNAPSHOT:dev" - compile "com.github.GTNewHorizons:NotEnoughItems:master-SNAPSHOT:dev" - compile "com.github.GTNewHorizons:ForgeMultipart:master-SNAPSHOT:dev" - compile "com.pahimar.ee3:EquivalentExchange3:1.7.10-0.3.505:dev" - - shade ("team.chisel.ctmlib:CTMLib:${ctmlib_version}") { - transitive = false + if(usesMixins.toBoolean()) { + annotationProcessor("org.ow2.asm:asm-debug-all:5.0.3") + annotationProcessor("com.google.guava:guava:24.1.1-jre") + annotationProcessor("com.google.code.gson:gson:2.8.6") + annotationProcessor("org.spongepowered:mixin:0.8-SNAPSHOT") + // using 0.8 to workaround a issue in 0.7 which fails mixin application + compile("org.spongepowered:mixin:0.7.11-SNAPSHOT") { + // Mixin includes a lot of dependencies that are too up-to-date + exclude module: "launchwrapper" + exclude module: "guava" + exclude module: "gson" + exclude module: "commons-io" + exclude module: "log4j-core" + } + compile("com.github.GTNewHorizons:SpongeMixins:1.3.3:dev") } } -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version +apply from: 'dependencies.gradle' - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' +def mixingConfigRefMap = "mixins." + modId + ".refmap.json" +def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap +def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg" - // replace version and mcversion - expand 'version': project.version, 'mcversion': project.minecraft.version +task generateAssets { + if(usesMixins.toBoolean()) { + new File(projectDir.toString() + "/src/main/resources/", "mixins." + modId + ".json").text = """{ + "required": true, + "minVersion": "0.7.11", + "package": "${modGroup}.${mixinsPackage}", + "plugin": "${modGroup}.${mixinPlugin}", + "refmap": "${mixingConfigRefMap}", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} + +""" + } +} + +task relocateShadowJar(type: ConfigureShadowRelocation) { + target = tasks.shadowJar + prefix = modGroup + ".shadow" +} + +shadowJar { + manifest { + attributes(getManifestAttributes()) } - // copy everything else, that's not the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - } + minimize() // This will only allow shading for actually used classes + configurations = [project.configurations.shadowImplementation] + dependsOn(relocateShadowJar) } jar { - configurations.shade.each { dep -> - from(project.zipTree(dep)){ - exclude 'META-INF', 'META-INF/**', '*.info' + manifest { + attributes(getManifestAttributes()) + } + + if(usesShadowedDependencies.toBoolean()) { + dependsOn(shadowJar) + enabled = false + } +} + +reobf { + if(usesMixins.toBoolean()) { + addExtraSrgFile mixinSrg + } +} + +afterEvaluate { + if(usesMixins.toBoolean()) { + tasks.compileJava { + options.compilerArgs += [ + "-AreobfSrgFile=${tasks.reobf.srg}", + "-AoutSrgFile=${mixinSrg}", + "-AoutRefMapFile=${refMap}", + // Elan: from what I understand they are just some linter configs so you get some warning on how to properly code + "-XDenableSunApiLintControl", + "-XDignore.symbol.file" + ] } } +} + +runClient { + def arguments = [] + + if(usesMixins.toBoolean()) { + arguments += [ + "--mods=../build/libs/$modId-${version}.jar", + "--tweakClass org.spongepowered.asm.launch.MixinTweaker" + ] + } + + if(developmentEnvironmentUserName) { + arguments += [ + "--username", + developmentEnvironmentUserName + ] + } + + args(arguments) +} + +runServer { + def arguments = [] + + if (usesMixins.toBoolean()) { + arguments += [ + "--mods=../build/libs/$modId-${version}.jar", + "--tweakClass org.spongepowered.asm.launch.MixinTweaker" + ] + } + + args(arguments) +} + +tasks.withType(JavaExec).configureEach { + javaLauncher.set( + javaToolchains.launcherFor { + languageVersion = projectJavaVersion + } + ) +} + +processResources + { + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand "minecraftVersion": project.minecraft.version, + "modVersion": versionDetails().lastTag, + "modId": modId, + "modName": modName + } + + if(usesMixins.toBoolean()) { + from refMap + } + + // copy everything else, thats not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } + } + +def getManifestAttributes() { + def manifestAttributes = [:] + if(containsMixinsAndOrCoreModOnly.toBoolean() == false && (usesMixins.toBoolean() || coreModClass)) { + manifestAttributes += ["FMLCorePluginContainsFMLMod": true] + } + + if(accessTransformersFile) { + manifestAttributes += ["FMLAT" : accessTransformersFile.toString()] + } + + if(coreModClass) { + manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass] + } + + if(usesMixins.toBoolean()) { + manifestAttributes += [ + "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", + "MixinConfigs" : "mixins." + modId + ".json", + "ForceLoadAsMod" : containsMixinsAndOrCoreModOnly.toBoolean() == false + ] + } + return manifestAttributes +} + +task sourcesJar(type: Jar) { + from (sourceSets.main.allJava) + from (file("$projectDir/LICENSE")) + getArchiveClassifier().set('sources') +} + +task shadowDevJar(type: ShadowJar) { + from sourceSets.main.output + getArchiveClassifier().set("dev") manifest { - attributes 'FMLAT': 'chisel_compile_at.cfg' + attributes(getManifestAttributes()) + } + + minimize() // This will only allow shading for actually used classes + configurations = [project.configurations.shadowImplementation] +} + +task relocateShadowDevJar(type: ConfigureShadowRelocation) { + target = tasks.shadowDevJar + prefix = modGroup + ".shadow" +} + +task circularResolverJar(type: Jar) { + dependsOn(relocateShadowDevJar) + dependsOn(shadowDevJar) + enabled = false +} + +task devJar(type: Jar) { + from sourceSets.main.output + getArchiveClassifier().set("dev") + + manifest { + attributes(getManifestAttributes()) + } + + if(usesShadowedDependencies.toBoolean()) { + dependsOn(circularResolverJar) + enabled = false } } -// Create deobf dev jars -task deobfJar(type: Jar) { - from sourceSets.main.output - classifier = 'deobf' -} - -// Create API jar with sources and compiled files task apiJar(type: Jar) { - from sourceSets.main.allSource - from sourceSets.main.output - include 'com/cricketcraft/chisel/api/**/*' - classifier = 'api' -} + from (sourceSets.main.allJava) { + include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString() + '/**' + } -// Create source attachment for dev jar -task sourcesJar(type: Jar) { - from sourceSets.main.allJava - classifier = 'sources' + from (sourceSets.main.output) { + include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString() + '/**' + } + + from (sourceSets.main.resources.srcDirs) { + include("LICENSE") + } + + getArchiveClassifier().set('api') } artifacts { - archives deobfJar archives sourcesJar - archives apiJar -} - -publishing { - tasks.publish.dependsOn 'build' - publications { - mavenJava(MavenPublication) { - artifact jar - artifact deobfJar - artifact sourcesJar - artifact apiJar - } - } - - repositories { - if (project.hasProperty('mavendir')) { - maven { url mavendir } - } + archives devJar + if(apiPackage) { + archives apiJar } } -println('Changelog:\n' + getChangelogText()) +// Updating +task updateBuildScript { + doLast { + if (updateBuildScript()) return -String getChangelogText() { - def changelogFile = file('changelog.txt') - String str = '' - int lineCount = 0 - boolean done = false - changelogFile.eachLine { - if (done || it == null) { - return - } - if (it.size() > 1) { - def temp = it - if (lineCount == 0) { - temp = "Chisel ${version}" - temp = "

$temp

" - } else if (it.startsWith('-')) { - temp = "   $temp" - } else { - temp = "

$temp

" - } - str += "$temp
" - lineCount++ - return - } else { - done = true - } + print("Build script already up-to-date!") } - return str } -idea { module { inheritOutputDirs = true } } +if (isNewBuildScriptVersionAvailable()) { + if (autoUpdateBuildScript.toBoolean()) { + updateBuildScript() + } else { + println("Build script update available! Run 'gradle updateBuildScript'") + } +} +static URL availableBuildScriptUrl() { + new URL("https://raw.githubusercontent.com/SinTh0r4s/ExampleMod1.7.10/main/build.gradle") +} + +static boolean updateBuildScript() { + if (isNewBuildScriptVersionAvailable()) { + def buildscriptFile = new File("build.gradle") + availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } + print("Build script updated. Please REIMPORT the project or RESTART your IDE!") + return true + } + return false +} + +static boolean isNewBuildScriptVersionAvailable() { + Map parameters = ["connectTimeout": 2000, "readTimeout": 2000] + + String currentBuildScript = new File("build.gradle").getText() + String currentBuildScriptHash = getVersionHash(currentBuildScript) + String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() + String availableBuildScriptHash = getVersionHash(availableBuildScript) + + boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash + return !isUpToDate +} + +static String getVersionHash(String buildScriptContent) { + String versionLine = buildScriptContent.find("^//version: [a-z0-9]*") + if(versionLine != null) { + return versionLine.split(": ").last() + } + return "" +} + +configure(updateBuildScript) { + group = 'forgegradle' + description = 'Updates the build script to the latest version' +} diff --git a/dependencies.gradle b/dependencies.gradle new file mode 100644 index 00000000..cd570044 --- /dev/null +++ b/dependencies.gradle @@ -0,0 +1,18 @@ +// Add your dependencies here + +dependencies { + shadowImplementation("team.chisel.ctmlib:CTMLib:MC1.7.10-1.4.1.5") + + compile("com.github.GTNewHorizons:NotEnoughItems:master-SNAPSHOT:dev") + + compileOnly("com.github.GTNewHorizons:waila:master-SNAPSHOT:dev") { + transitive = false + } + compileOnly("com.github.GTNewHorizons:ForgeMultipart:master-SNAPSHOT:dev") { + transitive = false + } + + compileOnly("curse.maven:ee3-65509:2305023") { // https://www.curseforge.com/minecraft/mc-mods/ee3/files/2305023 + transitive = false + } +} diff --git a/eclipseFormat.xml b/eclipseFormat.xml deleted file mode 100644 index cedf6acd..00000000 --- a/eclipseFormat.xml +++ /dev/null @@ -1,295 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gradle.properties b/gradle.properties index cc2be1e6..9156b748 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,60 @@ -mod_version=1.7.10-2.9.9-GTNH -minecraft_version=1.7.10 -forge_version=10.13.4.1614-1.7.10 +modName = Chisel -ctmlib_version=MC1.7.10-1.4.1.5 -ccl_version=1.1.3.140 -ccc_version=1.0.7.46 -nei_version=1.0.5.111 -waila_version=1.5.10 -fmp_version=1.2.0.344 +# This is a case-sensitive string to identify your mod. Convention is to use lower case. +modId = chisel -projectId=235279 +modGroup = team.chisel + +# WHY is there no version field? +# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the +# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/ + +# Will update your build.gradle automatically whenever an update is available +autoUpdateBuildScript = false + +minecraftVersion = 1.7.10 +forgeVersion = 10.13.4.1614 + +# Select a username for testing your mod with breakpoints. You may leave this empty for a random user name each time you +# restart Minecraft in development. Choose this dependent on your mod: +# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name +# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty +developmentEnvironmentUserName = "Developer" + +# Define a source file of your project with: +# public static final String VERSION = "GRADLETOKEN_VERSION"; +# The string's content will be replaced with your mods version when compiled. You should use this to specify your mod's +# version in @Mod([...], version = VERSION, [...]) +# Leave these properties empty to skip individual token replacements +replaceGradleTokenInFile = Chisel.java +gradleTokenModId = +gradleTokenModName = +gradleTokenVersion = GRADLETOKEN_VERSION +gradleTokenGroupName = + +# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise you can +# leave this property empty. +# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api +apiPackage = + +# Specify the configuration file for Forge's access transformers here. I must be placed into /src/main/resources/META-INF/ +# Example value: mymodid_at.cfg +accessTransformersFile = chisel_compile_at.cfg + +# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! +usesMixins = false +# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. +mixinPlugin = +# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +mixinsPackage = +# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! +# This parameter is for legacy compatability only +# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin +coreModClass = +# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class +# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! +containsMixinsAndOrCoreModOnly = false + +# If enabled, you may use 'shadowImplementation' for dependencies. They will be integrated in your jar. It is your +# responsibility check the licence and request permission for distribution, if required. +usesShadowedDependencies = true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 75ae3ac7c980652b3eac33db80678f118e97613d..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 17603 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 delta 17598 zcmaKU1yo&2(lroVgF6IwcXxMpcXtipBEdZucXta8!9BQ3uwcP05G=@llkd&EFmL8> zIBT7zc2!qZ%Q>t2Y`W`Sjn=&qRF-=M2@eJa3kHVki=hJcM}Y&~D@dq|FvuuMGW~*K zfMBq{VWZ&vfg&KWW`eK+rRi{QWBPvDKJItd3s-Qkmq?W7J}r(@@v;D6SmT{K_Rk6rnpvH#Y8IEkz&0y(k^x~PHE@5q5>KDB@96Z&So z`m^5u?%+lH%>gQqf7olFt*BR#2+B&eO5R~7%;FNR4_1s zU!eM{Fmf1-zr7;w@60a(S-FA+_5@G?Cui~N9plPgv`g~g=ZiXJ67&l{Ia4pe|FD=p zcq35(ve*O#oOnkCG|ob-cTR77VSy=Y_eGs3SN2b*oyWD2)<72QK#mLjjx1w=sJ4I)~1^Z_my&La^n_PV(FS-X|U>qDYF#bKX6CR2Fa|F7VT>AoKqNUVOeQ!CwXpGTholXx}G7OiQ@?6 zjTZu=bnxA1#`szyLNKt@v{_g5kds|jL?Ak2F!8-`26IAON^{uAA0Dv8>ger)Hccs_ z2ac{!W0jq56~$3&NGtfiY|*ms`7@W{n?$+d%bt2HerY2y1rTbsCP((X!yOV$B3rkG z>&2i`oeyr?YLtc~9LP|}3&O5Lm-?`nJOQ7GQ+z1u^tyvg!{H6~NUF*7q}KW+3V(PA za%iwD=P4`wEg3>hvi#zLVS>pi!JFWEnw4_e1+m$;_uLxHg8GFlGI)F5rm6PUYxL|2 zT~2zU%Po8P0e}F;3#YBrQ7|C=7i|xlHWc}UFis*CjHfeJ+&Zd3MG8wv&hhvIR5GH) z;BiN}D1%TqHf##GvQLPk{uW^Q8aRt`cl9KpRAK?o(&L%232+RfNYx98Tjrz(d(ESW ztt1ppqn5q1WMBIEJMgf-$#t^^Lw11iLN&}FGB>$`9RcVZ=*{*bryZ}(*;;1k98`{c^h1N~pp#`D!C$Tt=m~7_6vfD3 zU~Yt9U?jkJGAtkf1{T0*W^dx=mZbw{OrYiSV=&f?%5|&% z1Jg37pBd5`x5>?H$g4WiH7ufuGe<9 zw;mk&T74C^Ke*%{EMbkhop5hYUW?vly*BJS3q9xdS3>Hl@qQ9U0^syoJ|qMRah_9= z(Dz`A!EP&w-7-JPGd#EAb((LDlK8;_@bdIb zj+nzw4C%Qd^jWR%xneWJ)?4i0iUEBC*#wNOxEq6|koJAnZ9C1ppKJiVYJsIln@sd; z-+uNY&i8v1=CWBN$)xicGsYvNudtD95I>v3Wz@Yd8BrAjB;(etCSn#>vXh&Rl)nx& zZ=|u4*QuB=kW$!zR?9E0J`MURp&qVO2<+F!@4Z>3!(3stU$YgF5A zJ+T=rly-68K9v2{RU>F61yk$o>av7bI+6`bAz(h9Q|t@UL2jqb+d14Tv>*>RzYd#f zp@aDMB+aUv@766!(EHrBTgyyazTxLVVB;}%vh9qN37lF-p1X`F@~t$Tx`cT^t*)w* z)YHzpZKrPUar%T20Qe=0s%bYbGpEUmJa!g_op{n)yX|%iJ6s#M{SMi=%1Y_JoP>1< zGyziNsjDq0^asRgnH`x-5D$l4>+;RRB!>(;x=Zb`=q*)HtUffIAz}%*nC%86W>g96 z*`~5l`RunQO4;>V3?0~G(mRxUi%L(25_pM&yBVBPphQJkr9?Iu(`Jdye^GBsY#GJ3 z{19eZ7R_~Bie~1BjrPeP%WRW=y*MR-_z^1|~2i{BK4qiDY_6t!p0~>efE+?I_CeT7-p2T__?bZIUIgQh1@~!h6gV zMJ?gdR8c0I&{!rimR)+4ZxYF!CK+I553*rZZ%MQX)2tW2bCgMO*Q?XJKCjd529pC^ zj|j?L%f*qv(DP7tBonB95u|(I0*EoqXo8o3uLQb)K)4yo%mF;yd zo;@=EO=1YPvxIU%eoB+Mc4{zo>9a&+uD>36ge*2ofpFFEevxVCz{J&}=?kq~AlW1|T+IW*VwHwD*CYW8&xyu@6j#E|`Bi(TP&cN0b9NoeFKcS-KO&-d4x_~mJp632inUel`hl9K23Ec=ryUA$tehU$K$VFk>A9)&05_+)y_H zu4HEn7^1JXUi~`N{Yt-=*yznUAi{l4;cnX9(v?+$P%^(z0aYj;CKUO=kHR{{jbb*N z30Fg}Jzyl_(PvdHa8%n>QzH+$?z-MbyZ*bAPm6Bi+pN?goHF;f$P!|iNeK=}_7z;k ze4NDv3iz{pS6vDeYH|~weN1IS;Lnx~jx81#-y3HjaHI_3<$DzU%qrIE1gOegbTgPR zG3>0@?Qrv+7ESEpRnHgA6J@x*`{^f>nxfI(G~(tI`HrM${v%@eK*Lzh%*|pDh#xK9g-Uy_vZR&zWeXmMzO;jsep*bL7$e6$3-m zStOd8oL+~%(44_~;EbogB^3W!_5yp>zG_X31x>=4K3n#8%gv51o7(R9f-%edtqG&eS`T&YL^$l`v75XKd z3>!mU$c=QXf)A1xY&Mb3Ly1*#->xiSkg2omCVb#>;H;;b1q32h$DK50!hmHBwrM!P zrSp~o=fSUj0NRs1%SXuWhcV4ORvx|&E*Q`i`CpEf&CuH-GW^t9S#xGCgB{d3ArI8} z(z4OZ{p>2s%T5%2>;vxXG=Eh3U*xNK+N!HCuCX_ZttX7$vMxo8S&eedT-8LXKefbc zh?NC_VFG)lx;rqhGgF&Ot`dE6FzLEh@E%j0CyOVTue>zRwf?W zYs~ZRp&bmlr6PxOeu_IC8d7W0{b>4eRqj#4lm`sEnFuW8qCmiiREk2B z@Cd!ig_r46N^JiGTfqc1(RXMjA~btPC4_s6m~cZs;le-JEHd||+seT$s-a0iEPHlH z-e!CX-lQLbmOebE?ZK=Z4^_T ztJy##mj|sSC>`)^fezNSCpGC4GW1XewZp5)m2l|Q=%N-VRCW^vP8)-!Z;JGXb=9S# zybhL0*#d0qXwDyN$e+jgZNq;}xYHv7vUb0~UB5S|&6G<&BI;z5u#+Q=t_5 zQ*~9Vo$be7)`mKwTV&o;5Ra}g=G4X+CO|LL+(3_1cdx}?R2a2S)vBAdhB3_YD{D@ zgHjaDbd1PT2fj}TyUCF=$6&hOjVO|#!Ag-zVpWg^(rbDx&^z{8jVY>iRIOo^uNi86 z>JU^#XQ>BhV{d5c{lK8C-U_A9k26~?sTK4y!{RdN3-$KiW_R?r@p-KKf^dC(zw2?Y z)7&1bl2Q6@188mI4?e%CpuJ z!A*n3G*MYAGMg$;LTbf>9q4*g-%{qLvg;vMC4~j(xXM&)TRi7AxaRFF&S{PB%%Oo= z?fIeTx+-zAF%G#bb0~m#)qyy|cr1+l>{$Twb}FvJ{ZiLI2IzrwYLMc64HLOnn-vKkPXhjgXGhT74)2@_MIftzpS??$7k}Ow7Th?cGCDT~iFmY0ficZ`Ob3mB1T9fM; z3bTl>ZDw2_IE19ndQS363Fo#p5IopF9&C3EP%DVNg*N^}!F^nL_N$+y=p14djb31W zR3Md=wsXv-COlxc+a&Z_oxi!zS^h^awVg&T$JQ zK#uCdKz?iCd~LCoO)%zd?~UchiZtcb0V}Mv$_X9*5t9Nr0af>Ta>4@>sA-0g#P*C- zzNlHgDDJxYa5BCN7wA+)(|drZ*)|`$rB+8E@1V8KbU2dvR6Erm>;NVR?;pQqKw zJ!Ly@C#;{nKP!Zyvgwhp8beXaZ`Q#!0NeAMVk~HUuN-=RbkZYxEr>%T;4xkgROt0S z>JX6hZKkj|r}4#=X9e%_k%5=>ui>_Y=6T8MI+tG}WzaKW1CqtBPp7926UnSMq0`NHkiCwpolV-K4fA-?Vd6rhTf zTakFrI*$3UE81w&KH!Z@8e7ORc2s9)>ElRp@a_)+K?%a7Fg;}sv5R?LE*<#Eip1FQ zb454|8FFjd=Jo)(JGn!&4RvO&uhIN>_dw;UCXslS(Oh9#dJkS`1NL#Wc- z0B1BDi1HEW5+|W$Q3_R3?OQ*8)Lnr|Y}$n3@r3Se@|}CHR3^pDziNF5#`gT`qjx}D zx^|`wS`-XfCT@Z;y<=1VR!om3vZUTIt)yiIvlf(+>SRgjrqt3Gzr?kkA#Knf>Xp1D zSDJ)Ml-HZy#BR>=vSPh*QCPvE1oM+z!Rm4J)AWK>(VX7nuGr*RIY+Y+aqX<6c%~h6 z$JYo^*{zgBKkUL8LcRZw9TDI#&bL1{MCw~`AEE!OcfDzY_+u-GqK1&<7PKYTjsuJ# zV*~i1FXBE6(f{1JG{MJ3B>ft0qc`Z;3(o?{+yo92*b~J~P7>y~1fgS9h+d#WXfu;Q z$&e-EHOr}x(M0ZG!KEn5J6rs=@aqDhW0N@d-Yxd`Q^Wsm#Y`^QxA+SoU zBMtjO8_ZqrMtwuFlto(atVmTj#(^Wub`e0&n&Im906xW61={uKX73A4ruE{lC$!}h zrX1@eC}$cMitTbepESnYx^K#sVsE6IZbo-ITzzsPVb1-bh?UPpm?osBf@u%WvwrOUKQTKNOupn!&c>JqPrG+9EVc50+{zo+U?_+GSN6RT|w4DCLl(+UD2 zl*(?|vz0G!{WJ%Fx0ykcbhkl~NVoZsdKVN-o%C>>TLW5{ehN$X){&z`VV__PRMnJr9Z9ANsLSN`!B7Qooh3G%Ojo zOlV1Oa=>Dz97l;1D2(c3r3HBFRa(I|T0$99=al=YLI}Yi5r%=3b_F9sqH-L90x2dK zA{*H)b*5Z2A@w5_kLPgs%~4o>sQL`z(X@yFQNmC5DYFjsj=}D%mXlP`3EU7#a3*i`!&7THCJlxy3w2WkXQ3gwf&4Z31W< z-nu+QTt3zk(eK~GQoGDH@RId2;4f~&1q&sAJH(BZ)a4ud$RfZ=AG2n+9k1fE6irA) zCR1A-pL?d>%Q|>%DY47EKOCO`2s4e*_=@f zTLep5vx%Las4L}RB~9uWW`HO88Sk!PBfTg?mf0Y`#pKnukrPL;w(h}dZ$4Hw9TtZ0 z?v1mHm_Pe>FV@;}vcc(=YOs!v%*k#uUv@@H9jQexCDT5rezfQ9N38J31vF<^1-WAF zf&Ww-pno)9z|k>%mrNwsrbpaduhZl7nTo+@DxAuG(2dO$q5QHX_-i6;V-!9d8!ig| z3EURWeQI}mW!u`vi^AOinQ}r|$^5fg5I(_zWv z=4@fAcw|Dy3*>2$0KGYw4-$Pw7hGEe=+pwq(Kzns>CXl4IUWd~r_PlghEPC1qJkzO6 zRn&+rQCt)it-V?O#R33niT=e+KJKM-?8F}uO3 znFv?r;)pe^A6944RwdhHD3NF_mcR8QKepG%q|t{!14!zG0( zs4y4a8kt%Wq03@~iU45W#74k$Nub1v7`PhriA;*koJd(WAB&8}T^9S?rHGC#$G{&} z)=mjw8qxg?SpbWzs=HQ%YzSvvn7f<`ZTm{=Yb`EH;XAai@6fmjxP~B14Bv%ay+Kj zrWJh{aeXW8Iu@>jt;#T}rHB(oM)sN8L0@IAA}S^U+qz7kZ)^^4k%TO4%rUTiKoXJe zCe|Rn^*C|}nL+>)&OW2(Z93nF@nzVIwgT0Aq}S?`F^Yk-E?u>w!Axj{)>pdZ?PL&Uv8S`X2XB6G#@t*L zt+sM(e$QZ)c9g5NAC!wQ+N4 zj>Z-iqWN8Nbb!*iu~=Vp?>^_n{A6_EH!TG*zMYWmCFvu2Ly}{#tl~>}-So01NHgp> z?GjxC7wV?d2b@^qos99crQ21yE#7ys{s-+6huK||4IZ(B?&3IpVwMN~bv`n=~ zIA$YM8L)c}Y8NQ_`9?wCN^-TiA^sq;vecXU>dRQ9A%F8l&5tD~!>jXq(Pk;lPyh3W zgOs!F-l&RF5jMp37S@#1is1c6g=$&DaIfohJsvjs&h7p5tLI(k3>~i>0dKKlA9fza zI4=D)?r;DF^^heP(Jf2(-H0F3nobEy?mf0~E`rno$ecgXr~_RU^~$=`XYL=ejo~>Q zEP$yi#kZKEqs7c|)QvP_N+y9hR8O2W8!P+~A+ByJdUxeA^tNh`w$AWTVGp}%rQ3&} zywL*T=+k;crMk#Ck;OT~KEZ~34dfu2aE@HZ0%IfMW-Ef!+25CoARu0e}iz8f5 z+h}b9RPQa35JizI}N`$!*Fi0S9f1D24t$ov#zXKHp+ zh2M9X=Mru8xnfWxdI`mn%2vK(W(masEo9GZpNpaikiX(=DO1;H6&z5vC$=Tmd?atp zD)t|833B1F8AV+h-|(w0>LaAA(Ro;yEl{%t;K1MGQN7L-N6$)w=GYA=CRCFd2vD5M zjjCRD#Md~g?L|_DxUL~mZq2W$SW}$1tC6>C|TZ49KFcDujM*^C^-mT6vdopz+e6~SNpRL8daN?Bp#niuM zAHiJ3GcLUo_dI@0hr6ztk9a%sj*!Ov6aX(6xZG525F50Tw#Fx_Fz0Fotl zSFxFpc?u*h%sX57w`UU=;9Ngd_mg@u#dF3=KV()m<7AR!)m0X=RZK8SNoAphhhUg( zRyU-AwxN^M_Ni`UBh$NuP4d^{`zWhf#}&UOaV}Im!Mr>~y5GY2Rt`EAUIAUCzt51e zMp1x;4Ap;}|$k@JueSJqo;u(52Hjn$~SEl1)}__))o#^8oW8_0Vv5leRog znL!aGbo^Fu=;mGa+0XWR!1E1V4a8CqS8^T-as0R78Jrn;X<$lmyf{{I=&TI6GGLB5 zO&qOQo*p+###q)@PqVnlrO>5_hQbA&ShiP;2i!=Lw$7C^&@JCpFap6_Ra0;^HtuTy z>3O1jj^hxu;6kj~Z3}yj^jBb=A4`PN=Bx|>rd7##8l+%G_n!H!k4@*Bdn0+Y?s%b1NeofIV5gj7$ZIdBggQ$uBvVs1SZY8ZCOn0U}J^(iiM+3W2<(*uUSd(r93 zGf}iK!&X`Ts9(R%!zwuCseVo9ju3tSJ##meEa?Dlmd{dNnyAh7L-Ka0)#vsmoFp~c z{k~YS%O(}ZjLd3-E%GC-%PAFI(`4RRf$`4@_p?QWn$q1i1?R&I%y7}-bn@M{Pto_Xp*t8J7? zfg#3Tv*JUgPCF&YctyezeH2JWv*#W`>t2FR$&m6oeOwr)WyBoeH+d0kmWFTW@f#y! zH?{cNR_e8liNIXBj4t?RFY1F4vs>%}sdx@G+uLymWots(mHJa>-YEjsJxArQL}qi` z5%997FBJGI3W)hU><6(3^@@COR^07}$avR72zjB;8NQ^S$qrc@t7*^6=XPL@GNxw7 z?wvajZuEGi^$L2)4qdVmci*`C5erRSh}js%H)3CqAu%1a1QFBq-^+&X9o`$)iTp4x<&J4^Mvl`uRT z=s6ii`}67WWaP5;snefK#3s-_C~W)nr*dYLty71au52cqC^VPyM++tTFeZ_VVskxw-Ew3QKt1o#lh^4+I?Ot&Lqp4V$gqh){v z?_*m{$VbVGnL=kkj1Lx_rLPIzf7S!g)W#LacQ%#Cygbt%O40~8nBHGx6d74hi zvSNqHgE(d@7M_|-vd0(DI}8v$UnfXV7Rj0}v2JQmr^QViy#Z>{*u|306vKwB*QukE z!IY+O7KgRXPfkk;BT+f&?>W3YKFwa<9BHMqekoKTVwt=IcuHpFR=o1o2D@5^1IyoV z&bZ-gN4+$f^f_}426)h~K#nG?bhG9_HoMszAvZ+@XFcCEPx-0Et-7ohR)<))_VZK8 zX%C^y(PMCutS{3zk$3ysRqe^)Uir}nXP;S2U5e~B`@Zi2KhD2)j8)7>!utushHsV2 ziZY(dFv}MVkfy}U5@82Mj=xEk8L)aisULRDO0jb8*yM5;{6uWAGR~pfO@s*1Bh7z7 zCrw0kI<2%46&^wSV@82o(Y!jZD$;^0f!~GjWK+H-zu<_GQ-i*1;*7LfvRvB**N#(j z+5>k@U%3v)aaADdZFOk6!K6r(p$L0j)a5?CW^83AAi9j=(S7pnAg(xHqY@AMsNP#o zp@B{!aGmzFNE!1cB%@-$kJk5<9jUa0n4R6wQLUv508l%c(k7G~xz@dcDJ1Rrd7m)S z$v0nUeP;)pS7yK``L)8h3awz&k8Q1|OWkqT%1AHGG~)a1xD5RCvBENAZ@96w_~a_~OyLj9Pw9tY|BgMTIb(?-$fYC?0(*i7G`XjQHeNQQW23J>kAYVRH!F zXy<#>&u#|!r~da5s%~WKeJc7(s@v+i0wF^!fa3G_ya6TzZz|wznTV)n$*yjoT?oY! zleLWByRs1ECoA4LpD~{hZI0;nZ-^_3an0R_!Gwm#ki_OD0i zAJ0eQ-KCXZTTi-lU|?_l?>h`e7$6NNBB1rTbIg?ri11z*wvU%I@YqBuIG+SE0tp;0 z3LMjkmFx2`y~{Ub8G1&CkJ=}uRl3t{OxjThq;NQx4o8kvniWlrjn_Ik@01))j^5UE z=KDOKt$sHDfC%v|CG+i>PUj`Vvl9;$li$-mx;T5>#*Hf1(M{ z{yT!bB2%Iom(JkZA5l=vR_W>b#4$2=P1O;Qa%;Ns=% zZ>Aag#v^cK?-t4MugIaeBwS(0spY$rr4(O!Go`q+rj)me3epv&k&Uks@D5+HXP<3C z;V~uRMzynNV9Pzr5DDsJYxJI?;qn0nb@!%{{r8|($MDmvPu?b^Nds$Hs5u*{gE ztKz>Q+GxUu@a8!ehjoz({J^W3Y3b>!5NMa=o%lX;(5{&-$<)zv#BO+2l*GT@hriRR zlHO`4n32K0UU*@d<{q1(dD&`c`}LB2eXB@vxjAt1rj~?wd}eIEWk61WU}_0)HDihF z-7??jK;($+AH3`b?u1z;N`yShMmi?WaeA&=VO^KRG?o{~L#d!|HY%s*Q^XFJ)}pYj z81t!pj>N5Cl>vbfO{D9vsO!7u-72FKc9cSsogW;~5IZ9EV|qMlT!stf#`iCn^G8RE z4myU5EshRrbw7>{HM#6{)H)mi6l#W#P=lNWtmfihXz{DGnP-~b+o&tBqcul|H}=3% z$fFpI>>x|5d>O-;-MP1}tg2(MgcP;3uo~OnXEsavVf&g+Akf;19D@TwewJ0CQZJhz z#ef&Fq63dUG($|(N3s~oZf4JTn!LV(A~77MIgKueq`s|aAbLm(7gg*6pqUmSdV-1_ zkohywnB1Ddg12TLVdvgdCU(N}0-DlFf!&xjrVK@LEL6N@Il79CnHnp+2`3LplAe0w zvtr3S(fi$E^Hm*tbojuxPI6=H^lm=Pjx1T3DnT*V=+F*GO%$e~n9-8S7%P$}l5`SO zrjf~4F2!4Blu!{6OM+PT0L9^(d+l(W1_eP=-K3+%1ru5S`@}&{v-Mtym&23LV7j2|jcX}T zgM4RkvQ^js*02KieU@ktj?_C!PJeVR>b;lzV#`G$z@SGY>XtP$^cwQJc< zfpuK#aDWJD7SFb52nf7Tws@yZW8AB3w10|o4)a{wT7tOdaDW!$Wqik(@mOfJ(2&8P zw{6-SB0+{LST5|W%V4hud(WX;`5sl3dN@`J{Uer|iNMhDA+sJmTdpKO3BF_eL=G-( z@Qke=k2DAL3TbFkcp8}pzuy3Cn#nY4woYPS07P9KXXE>8JNh#+?!Xar=$uM8_3qglhDjub9 zQxyh%I7XNWpO-{4VZ$sXjAXFtPPET6V1IoJFL_$cJqPeE8Pu|VV0eF?ANW3y4y-KZNGLA_6obF zuZ&UVDHMPqhg0`v+&7K4Ek#KKF|?j5Q;Wb$TJv;8rCB!K$A~9|5~(t!l8u=&ci#`$ zGY5889$Ab#)I%g*(0ngRHJ0ExU(zcP)~8 z#OIB?Mnj9Fgv2_fX>K7)KX{+xodRGF(0Z%zwKM@K1-jEd*c-4Lio^dFC?e(2BA zdl`3FSx&nvuMJpJknlFDFA4ohCcG}zcsKe!6}4*Z5ns;pZb&(iU?W!RXM}6_)TTu) z%kSmn?VOh^zIs{?xmbP@o{RoTrZO7$eU>!{wF~uNumK0nRy|)Qq>D4n;8AmKBU1R3 z>r*@+Tx{*BwajM?lbQnh#%RqCyv^eY?hI96t>*HTAJ=TFlsRdu7lEGm<0jKk-~`Hd zG2S)N=EL?B;sqb#hTfC%boi!Hu;aLTes<5*MVzhLuyO7 z5}5uhviE6GKV5QoROc~inJDCC33j6Y zoPx$vueXW$8@&6XLmRx8+JXj>;O zxwqVrs{J3mH$}4m@F?I(IR_7J{F64^`9JNk$K+ zIx#u3cRrnfZX+oSSMGDG;qmL#38wQXK<|v)%!6sTuWCs41k>ewDMmlemUI_EDrbZ7 z>>Xwr=Sh?uXYq%0Yf=nle>Uo^@*HQWa94qQ}yLrzoH4i zH@(-Yahc%Cx5!uFB?bE#UJqg0;2E@iMLKrhu?bXWUE&RqVu^GUa*bE{+sX0ydZR-3 zg{o97@N&u`33|`kuC*Ix1#$DsQvj-MrPYer^>G*L5cFH!eCoul5(9lqjFiY3iJq9u zoz&Z#8vu4WW(S_^sB|WeqXe#K2aiFS2rg?3rf)@z!k&Hy`Szs?u{ted^Z6^%*=^-) z**O@x@pa%z1cQ|$c+6D7IIfsxi(s#rVIXMXNEzat9Ygg3whHt=a|d<=dhbiE!Ffh@*M$7vA z(bH9BeE6=6E~}1AF3F~CC=&TR4{Ez{6B&U@*{dS*@z9+;Xz5!*`uMQFKc(c(H#VYn zX#&h99Fn&qs*abU{dc#_w66dwpIg@it5;(6)(GN4(UNJZnc0!N3a$gZc;mxn&Ttn3 zGJ0mew;--5ONIG`>;#P*!_x+TfgVhWtXp>dM5e92NH;)cs;|i0>6c3mi69Bq#CNfe zZM8&-%{q^hU=2B7I*es2suF4kjd=*RmpWtKMhe5E-JnQjO_EYkKg|LlG5b0*=+$3e zL-3_Qc+7fN$%du%4MQnnM^$F(U8pcQ4i|S~yYC0XIB(sKHY48M7G>_OWZB*?<$+Or zaNu?yLYQVN%~U^s0GD5;Q6Q~c^{sM}f9xW6Fph9NySJv=!lzB?5t!LCUlkLRG4-r+ z6bL$+EBo2h;&2%4rP!GdaK}XKIKiED?AMYovve3nBvXc{<3X(-mGwuSG@=oj%VqrO zKSsE2yD@tYJ7Sn)@PCXGU(B;@yq|U}O|mZt};6&K$|4 z#8axOLVKZBxsjXM{SMnOx@kpHt}nRS2PGHoq~57Av!$<{>i21*6PMTzR;~z1e^By& z^hK|(o69)g6+ZJic)O44h#a57&YzNeJ(a3q4f+V5C~w*uS8w-<=Ph;32t}NWhT~P- z_tu}*ergeuCvHhe$$%SGe-s7p5AZ~IgH|l&^x(U!=eml(GKkDc6~F2RFS(1>#OmU+ zU^471`Nb&|;Q={>eck=Vz(xvp!ZonZlwuPG?qrtZxis$R>#J8}m7b=%A?J+z8=q_6c z?q0hdo<7}-_*&~?7G|!`$vx4Ie;fv$U9{%31b>Sz^3UPhV0-@X%3V~WiRn|ACAU)n zK~6GXNtoj5{%oP$w?RUp^|j|ZrK3Dil_;??3#b^0x139k`78}^Q%i{G*H;uC)?%=sry}2euy_&Gzf|?u96c)2-4e^d8e8Xg- zC3C(!Yj6}j9JPmxZTKU&Vk`SZUy%I2Q!Cz>hM=>HUYWI_*cwC{0D`!$=Q9ep`?>0=@&>OO+PlVYdOU?swW=csoeNwL}SguLK;dt?7 zjp4P#?nKfDnD_bx)7KKUcKk9UGYBkVU|^9|d|?YLV5yoZ!$!kU_>fg4uqase~@sLJ-2EH||aVmA(WoYsJ6(W+VGyW{{GK_Zt^y z>j-|vs$hw<=B{rl7Az??FUnMY2hCCpYu?WOl^9m+brpb+sS@XhqW`M2Hk zyoyAw*6EU2v-pt^Osd)K1_K$Rj1Qg3*~-&$>-|7L-P{Vvt_w=(?cg&+k2_CJVaW&A z&e#%eXAfeA(BMpR)a@MucH+45(C<`OJcLpDcg`RAhK;h%(zSN4Ti;rLW}F%II}LW1 z#d28P40_wH#%bMQ6Zy3f?A)Vv{fD}^ka%Sac)O8ONni{(0#;ARsd{$YiQ0@hmBT@g z-$!Fjz(|niB=}XhI`H#!93|9FFy3Qg-utrW_uWEjn@4-MZ_~3s_PJ}qagInn{|s0w z`!w9z90#8+dzpMaV^h(R7pLgtDx^5C5Zi9SY;A}%23Nu8bX=s%=U6Sg`d(zRB|%aA z>)gFH#g#^imnF(OiLp2-l=+*f^0kKiIK1?GYk&uE%xG55>c@<3gm8>@ZM7^qQnge0 zcYZM_K?bMb6BI!uGZcr_aBqshZ^xl)>^A|R#r*0>yooS#JCG#X2x&XeKOZxWwZNROC}^a1A)*%Iek?#&*=8-hr}cf^ z;|*Z4zA|+uHXR|mdcA(rgJYU2n7Z?tu&{Yk006B#&`ua&OQnCUQWU32tmc%9B@FzxOjI~2V}=B zcPWCuqp)~;PvQiRep|J$?;f-M=03XEb`FrMvTc$cdg?Fp<=`?r*=EkYSTdv0RM{W6 zE?a!#=@%iVFtXwrFab!7CbF$&8n-*h6J9XbaXoc8mTC3M-nxDLdG`_Wc1iq=$`wmb zaeSh9$@CTeZe4F<*lQ;$co-emvz*l*VC-Le-CW9Co8kG#G-8X?M&nx)sa2*JGI#+f zOD7a1&LI1r)`Y7Iy% zI~2OYUKgOcQNZ!kT4Fs0uB$-ME2f#UJgTILLgGloPFgoeo_(KF5+Rp+ic64RuQ7GI zXtld9)tK?jK-%$?!4(1hw(ECKEdVrEK8b!R6@E_#jAQOU%7e|^Y7~s@E#OTLjs7tc z(t#mHxa}sZwYqmoA=gg#F++0MKl$7y%=5;GF2fP180UNGgM1PazekEPq@MqAZZ;~n z9epzE>pLsiK%{Pba1=vrD(u4x5fQe$c-GRd>b}^U_X5hk#0`SE)Q?b!g2I6GdxYbk z#JM*l@C|XoCt{F4;$F`QX^t2obc~7rI49yC44I$(__Seiq3=BoqkZ%`t0?gu67}-I z3EsU@$XlA)V;{rYxv<=0^7kZX94N%7au*EAMZ zKl%=<=P>*l%JclSCphdWnsB56WD3UH==X0~V^*UD1MN1osch>)XI$q@6{0e^ruXYy zH6lDtPoH7Ck3}0~5sSt6rU60M#M02uF{UE~NvmFqTxwF9VdSAhC)~^4F5EV@QXRL;C4`G2D#fKj99oY~JWihg z=I?-0d@8>Xp7hk%Hc5dOzqY}%;;K#moT-!6d}r#mo@%LR93qgJC4-xpc8!`SqC+oX zgta#%K`UiW0=pu#c!_}__3-@igs$FJHva|t5K95#Ps$>p?9vt%h_0vyVuDfr-hC7t zN3Yjb!h`wq^Ef|E=s)>{_0f74FN}s6s=xs-KulT?-|L^7xb}u*t2H4-M$A9yCK{(J~|0qw z|EZ|)FEr=`_K%YEQq#=d21GD^8QA=)P&Ge@(5eOn2FCJ-Di~NVIM8L1o9d6GEe1E% zYlEUW26YwR3#{C*=6;eR8Jtx@Rz z(}tQQ{5%BcfZ6KT5Ps3{6~b>NglW`29eu%Peu3vj1L4WAS^kd%`Je3o-%bDWl>+@2 z2&m|b_YY5saK#JqLFu9dO(?b(mdCJuD^bi~|LIBL(9l;A5D4xmLH-8#Zhm;d6 z2ZhoPO02*OLo{?ik#riM&>a4s_*9CoW1m3yauA;D1)h-+7&s^RCw9kDEVTqQ_zGTu zfpNdU3bOpRjWUn*!cpe=UykyzfrK3Y%tyj+DHkV5$^=}U$9$ps@LNd9^E*bRTvTAd zEYu5t{=zTYzI?v{84F~8I%=+)F^7c)24+w5pChY55QHbi`X2*@aPgN-WECJuHz`nW z5#dFHF29BNIv^qAKSq$g=b)$`C^ZP6)cm!e{goggec;}r$e-T9PjU?9 z;iiG%fzHc5E=V4FZ=`aR-*PU%SR--;`^Z~mbafBc@_2NYc> zC_080jwS#=O8CI@5!^p}^6$^hLDTUCULy#Er~hZ?*pL3|oTQlFE@X{j{AumQ2RARQ z0b+mS0gV4#L|>djzEJv@^p_IM|H$om7w@$bC|Y*VL*nJr@>Th7)fidCf27FC5f`-y zGPJ;QTXmr14*&f2#fqh4W%^nfw-FHvJanXc7Wz#$QhNuHOKP zPrm`@&I^pnj2qH=TdsVSuU==vtsf^k1(!f4-^wde!;6ydC=A bFFwk0P@pjd2F42dF#`REiv