L'API 'variant.getExternalNativeBuildTasks ()' è obsoleta ed è stata sostituita con 'variant.getExternalNativeBuildProviders ()


337

Utilizzo di Android Studio 3.3 Canary 11 con la versione plug-in gradle 3.3.0-alpha11. Emette il seguente errore quando si tenta di sincronizzare il gradle

WARNING: API 'variant.getExternalNativeBuildTasks()' is obsolete and has been 
replaced with 'variant.getExternalNativeBuildProviders()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration- 
avoidance
Affected Modules: app

Facendo clic sull'errore mi porta a questa riga nel file gradle

applicationVariants.all { variant ->
            variant.outputs.all {
                outputFileName = "${variant.name}-${variant.versionName}.apk"
            }
        }

Cosa devo cambiare esattamente qui?

progetto build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
        mavenCentral() // jcenter() works as well because it pulls from Maven Central
        maven { url "https://maven.google.com" }
        google()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.0-alpha11'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath "io.realm:realm-gradle-plugin:4.1.1"
        classpath 'com.google.gms:google-services:3.2.1'
        classpath 'com.google.firebase:firebase-plugins:1.1.5'
    }
}

allprojects {
    repositories {
        jcenter()
        maven { url "https://maven.google.com" }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

// Define versions in a single place
ext {
    // Sdk and tools
    minSdkVersion = 21
    targetSdkVersion = 27
    compileSdkVersion = 27
    buildToolsVersion = '27.0.3'

    // App dependencies
    supportLibraryVersion = '27.1.1'
    appCompactLibraryVersion = '27.1.1'
    playServicesVersion = '15.0.1'
    firebaseVersionCore = '16.0.1'
    firebaseVersionPerf = '16.0.0'
    firebaseVersionMessaging = '17.1.0'

    //lottie
    lottieVersion = '2.5.0'
}

app build.gradle

buildscript {
    repositories {
        maven { url 'https://maven.fabric.io/public' }
    }

    dependencies {
        classpath 'io.fabric.tools:gradle:1.25.4'
    }
    buildscript {
        repositories {
            maven { url "https://maven.google.com" }
            maven { url 'https://maven.fabric.io/public' }
            mavenCentral()

        }

        dependencies {
            // These docs use an open ended version so that our plugin
            // can be updated quickly in response to Android tooling updates

            // We recommend changing it to the latest version from our changelog:
            // https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin
            classpath 'io.fabric.tools:gradle:'
        }
    }
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.firebase-perf'
repositories {
    maven { url 'https://maven.fabric.io/public' }
}

apply plugin: 'io.fabric'
apply plugin: 'realm-android'

android {

    realm {
        syncEnabled = false
    }

    dexOptions {
        javaMaxHeapSize "4g"
    }

    compileSdkVersion rootProject.ext.compileSdkVersion

    defaultConfig {
        applicationId "example.com"
        minSdkVersion rootProject.ext.minSdkVersion
        multiDexEnabled true
        versionCode mVersionCode
        versionName mVersionName
        vectorDrawables.useSupportLibrary = true

    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    buildTypes {

        applicationVariants.all { variant ->
            variant.outputs.all {
                outputFileName = "${variant.name}-${variant.versionName}.apk"
            }
        }

        release {
            shrinkResources true
            minifyEnabled true
            useProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            lintOptions {
                disable 'MissingTranslation'
            }

            applicationVariants.all { variant ->
                variant.outputs.all {
                    outputFileName = "${variant.name}-${variant.versionName}.apk"
                }
            }

        }
        debug {
            shrinkResources true
            minifyEnabled true
            useProguard true
            debuggable true
            versionNameSuffix '-DEBUG'
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'debug-proguard-rules.pro'

            ext.enableCrashlytics = false
            crunchPngs false

        }
    }

    flavorDimensions "default"

    lintOptions {

        checkReleaseBuilds false

    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }
    buildToolsVersion '28.0.2'
}

configurations {
    implementation.exclude group: "org.apache.httpcomponents", module: "httpclient"
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')

    implementation "com.android.support:appcompat-v7:$rootProject.appCompactLibraryVersion"
    implementation "com.android.support:support-compat:$rootProject.supportLibraryVersion"
    implementation "com.android.support:mediarouter-v7:$rootProject.supportLibraryVersion"
    implementation "com.android.support:cardview-v7:$rootProject.supportLibraryVersion"
    implementation "com.android.support:design:$rootProject.supportLibraryVersion"


    api 'com.squareup.retrofit2:retrofit:2.4.0'
    api 'com.squareup.okhttp3:okhttp:3.11.0'
    api 'com.squareup.okhttp3:logging-interceptor:3.10.0'
    implementation 'com.google.code.gson:gson:2.8.2'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.picasso:picasso:2.5.2'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
    implementation 'com.android.support:multidex:1.0.3'
    implementation 'com.daimajia.easing:library:2.0@aar'
    implementation 'com.daimajia.androidanimations:library:2.3@aar'

    implementation 'com.akexorcist:googledirectionlibrary:1.0.5'
    implementation 'io.reactivex:rxandroid:1.2.1'
    implementation 'io.reactivex:rxjava:1.3.0'
    // Wifi hotspot library
    implementation 'cc.mvdan.accesspoint:library:0.2.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'org.jsoup:jsoup:1.10.3'
    api "com.airbnb.android:lottie:$rootProject.lottieVersion"
    implementation 'com.android.support:support-v4:27.1.1'
    implementation 'com.android.support:recyclerview-v7:27.1.1'
    testImplementation 'junit:junit:4.12'
    implementation 'com.jakewharton:butterknife:8.8.1'

    debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
    releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'

    implementation 'com.googlecode.libphonenumber:libphonenumber:8.2.0'

    implementation "com.google.android.gms:play-services-base:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-cast-framework:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-auth:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-identity:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-awareness:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-cast:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-drive:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-location:$rootProject.playServicesVersion"
    implementation "com.google.android.gms:play-services-maps:$rootProject.playServicesVersion"

    implementation "com.google.firebase:firebase-core:$rootProject.firebaseVersionCore"
    implementation "com.google.firebase:firebase-perf:$rootProject.firebaseVersionPerf"
    implementation "com.google.firebase:firebase-messaging:$rootProject.firebaseVersionMessaging"
    implementation "com.google.firebase:firebase-analytics:$rootProject.firebaseVersionCore"


    api('com.crashlytics.sdk.android:crashlytics:2.8.0@aar') {
        transitive = true
    }
    api('com.crashlytics.sdk.android:answers:1.4.1@aar') {
        transitive = true
    }
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
    api project(path: ':libraryBTHelper')
    api project(':bkk_rush')

    debugApi 'com.amitshekhar.android:debug-db:1.0.3'
    api "org.jdeferred:jdeferred-android-aar:1.2.6"
    implementation 'com.android.support:gridlayout-v7:27.1.1'
}

apply plugin: 'com.google.gms.google-services'

Ho ignorato alcune costanti e altre informazioni sensibili nel file app / build.gradle.


Puoi pubblicare il tuo build.gradle (app)?
Skizo-ozᴉʞS,

@ Skizo-ozᴉʞS ha aggiunto il file build.gradle del progetto
Jude Fernandes,


@alowow questo è legato a diversi problemi, messaggio che indica "API 'variant.getJavaCompile ()' è obsoleto .."
Vadim Kotov

16
Il problema esiste anche con la versione stabile
kp91,

Risposte:


286

Il problema è stato risolto nell'ultima versione 'io.fabric.tools:gradle:1.30.0'

Si prega di aggiornare entrambi gli strumenti in tessuto di grado con 1.30.0

buildscript {
  // ... repositories, etc. ...

   dependencies {
       // ...other dependencies ...
       classpath 'io.fabric.tools:gradle:1.30.0'
   }
}

Per maggiori dettagli https://github.com/firebase/firebase-android-sdk/issues/198#issuecomment-473435453


Assicurati di cambiarlo in build.gradle sia a livello di progetto che nell'app.
RJB

2
La versione 1.28.0 risolto il mio problema, la versione corrente è 1.29.0 docs.fabric.io/android/changelog.html#fabric-gradle-plugin
Alexander Hartmann,


Ricevo ancora questo avviso con classpath 'io.fabric.tools:gradle:1.31.0'e implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'. È nuovamente rotto o non risolto in tutti i casi.
Gene S,

Dove hai preso questa versione gradle di utensili in tessuto? Posso trovare solo 1.25.4 mvnrepository.com/artifact/io.fabric.tools/gradle
Lachlan Young

248

MODIFICARE

Questo problema è stato risolto in Fabric 1.28.0 . Nel build.gradlelivello del progetto, aggiungi la seguente riga:

classpath 'io.fabric.tools:gradle:1.28.1'

Risposta precedente

Succede dopo aver aggiornato Android Studio alla versione 3.3.0. apply plugin: 'io.fabric'è la causa. Ho inviato una segnalazione di bug al team di Firebase su questo problema.

Hai 3 opzioni:

  • Attendere fino al rilascio della versione successiva del plug-in Fabric. Controlla qui l'ultima versione .

  • Esegui il downgrade ad Android Studio 3.2.1 .

  • Commenta il io.fabricplugin.

Nel build.gradlemodulo della tua app:

apply plugin: 'com.android.application'
// apply plugin: 'io.fabric' <== this plugin causes the error

Tuttavia, è ancora possibile creare ed eseguire i progetti anche se viene visualizzato questo errore. Ignoralo.


2
Sarebbe possibile collegarti alla segnalazione di bug o al problema che hai aperto con Firebase? Mi piacerebbe votarlo.
Yuval,

8
Devo usare il io.fabricplugin quindi come posso rimuovere questo avviso senza cambiarlo?
0xAliHn

16
Questa è la causa, non una soluzione praticabile
Daniel Wilson,

1
Stanno dicendo che puoi usarlo fino alla fine dell'anno 2019. Per ora lo sto usando, vedremo cosa succede)
support_ms

4
Perché il downgrade? Senza senso! È solo un avvertimento, non è stato ancora rimosso e può costruire il tuo progetto (tutto l'anno 2019 ...). Credo che lo risolveranno quest'anno
user25

60

nell'applicazione build.gradle, esegui il downgrade a questa versione stabile di gradle:

classpath 'com.android.tools.build:gradle:3.2.1'

Succede dopo aver aggiornato Android Studio a 3.3, soluzione temporanea fino a quando non lo risolvono!

modifica: non è necessario eseguire il downgrade del tuo Android Studio!


2
Quindi devi anche eseguire il downgrade ad Android Studio 3.2.1. Grazie comunque
Rubén Viguera il

Ho avuto lo stesso problema dopo aver aggiornato Android Studio (AS) alla versione 3.3. Ho fatto in modo che la sincronizzazione con Gradle funzionasse di nuovo declassando Gradle alla versione 4.6 e Android Gradle Plugin alla versione 3.2.1, che era la versione che stavo usando prima dell'aggiornamento AS. Cerca la tabella qui se hai dei dubbi su come modificare le versioni per gradle e il plugin.
Rabie Jradi,

6
Ha funzionato senza declassare nulla grazie per il suggerimento
Sid

3
non è necessario eseguire il downgrade del tuo studio Android @ RubénViguera
Amer Al Ziebak,

1
Non è necessario eseguire il downgrade di qualcosa di diverso dalla versione gradle come indicato nella risposta. Questa dovrebbe essere la risposta accettata.
MD Danish Ansari,

16

AGGIORNAMENTO Da oggi puoi utilizzare classpath 'io.fabric.tools:gradle:1.28.0'per risolvere questo problema!

Se commentare il Crashlyticsplug-in io.fabricsul file di valutazione dell'app ha funzionato temporaneamente per te

//apply plugin: 'io.fabric'

Quindi l'aggiornamento delle dipendenze del livello del tessuto dal file del livello del progetto risolverà permanentemente il problema:

classpath 'io.fabric.tools:gradle:1.27.0'

NB: questo non rimuove gli avvisi ma ti consente di utilizzare Crashlytics con AS3.3 +


@RJB Stai usando Crashlytics? Se lo rimuovi dal tuo progetto funziona? Se sì, questo dovrebbe risolvere il problema. Tuttavia potresti ancora ricevere avvisi, ma il progetto verrà compilato e potrai generare il tuo apk in modo sicuro
113408,

Sì. Voglio dire, sto ancora ricevendo l'avvertimento.
RJB,

l'op e altri (incluso me) avevano questo problema e non erano in grado di compilare il progetto con crashlyticsabilitato. Quindi, per mantenere Crashlytics e continuare a spingere in avanti, puoi usare l'aggiornamento sopra menzionato anche se innesca ancora "avvertimenti".
113408,

13

Non sono sicuro di quale sia il vero problema, ma commentando le dipendenze relative a crashlytics dal problema risolto dal progetto.


11

È confermato come bug per Crashlytics e ci stanno lavorando.

https://issuetracker.google.com/issues/116408637

Citato dall'assegnatario di Google:

je ... @ google.com # 23 gen 2019 01:40 AM
Ciao a tutti,

Grazie per la vostra pazienza.

Sembra che il bug in tutti i casi provenga da crashlytics e ho presentato un bug con loro.

Ti terrò aggiornato sullo stato.

Per me, la mia app di debug funziona bene sul mio dispositivo semplicemente eseguendo e ignorando l'avviso senza commentare Crashlytics o Fabric. Non ho provato per la produzione.

Aggiornare:

Google Issue Tracker aveva contrassegnato questi problemi come Non risolvibile (non fattibile) perché tutti i problemi erano di Crashlytics e consentiva le correzioni fatte dal team di Crashlytics (nonostante siano gli stessi Googler ...).

Suggeriscono di seguire questo link per gli aggiornamenti di Crashlytics:

https://github.com/firebase/firebase-android-sdk/issues/198

Nota: sto ancora usando Android Studio 3.3 con io.fabric.tools:gradle:1.26.0 senza commentare nessuno di Craslytics e funziona benissimo sulla mia app di debug.

Aggiornare:

Posso confermare ora che funziona perfettamente sulla mia app di versione di produzione / rilascio. Come faccio a sapere che funziona? Perché mi aveva rispedito un rapporto sugli arresti anomali -_- '

Ad ogni modo, basta ignorare l'avvertimento, alla fine dovrebbero risolverlo.

Aww, ho appena letto che era stato corretto con il tessuto 1.28.0 :)


8

Ultime notizie dal 24/01/2019

inserisci qui la descrizione dell'immagine

Informazioni qui https://issuetracker.google.com/issues/116408637

Dovremo aspettare fino a quando Crashlytics non ha trovato una soluzione, ecco il problema di GitHub aperto

https://github.com/firebase/firebase-android-sdk/issues/198

L'unico modo che sto usando come adesso per non commentare il plugin io.fabric è il downgrade del mio grado e l'aggiornamento del mio percorso di classe fabric (questo funziona sulla mia app di produzione)

 dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath 'com.google.gms:google-services:4.2.0'
        classpath 'io.fabric.tools:gradle:1.27.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

Che ne dite basta aggiungere -dontwarn com.crashlytics.android.Crashlyticsinproguard-rules.pro
Mustansir

1
Se rimuovi l'avviso facendo che il problema è ancora presente e dovrai eventualmente tornare nuovamente al problema
Gastón Saillén,

Destra! È una soluzione temporanea per compilare build, ma è molto meglio che eseguire il downgrade di tutto.
Mustansir,

Sì, il downgrade farà funzionare, se si elimina l'avviso è possibile mantenere la versione aggiornata ma non funzionerà
Gastón Saillén,

@Mustansir, penso che sia un problema relativo al livello e non abbia nulla a che fare con Proguard.
WindRider


3

il tracker dei problemi potrebbe fare riferimento a "configurazione attività lazy" -

questo è almeno ciò che evita la configurazione dell'attività .

ma è possibile impedire l'accesso a questo metodo obsoleto di BaseVariantImpl, quando variant.outputs.allnon accederà a tale metodo (internamente) - o quando i controlli possono impedire l'accesso; o quando si accede alla variante in base al nome; o in qualche modo disabilitare le attività di generazione native esterne per la variante. vedere anche l' opzione di sincronizzazione del progetto a variante singola , che sembra piuttosto correlata.

oppure aspettare build-tools 3.3.0-alpha12 o 3.3.0-beta1... questo non è nemmeno un release candidate, quindi investire troppo tempo potrebbe essere inutile, tranne usarlo per presentare un altro bug report.

il nuovo feedback rapidopulsante di feedback rapido sembra ancora il più promettente.


Sì, sono d'accordo, questo tipo di errore non era presente nei precedenti strumenti di compilazione. Il prossimo RC potrebbe ripararlo
d4c0d312,

7
non è stato risolto nel rilascio
Juan Diaz,

developer.android.com/studio/releases/gradle-plugin#3-3-0 ... aggiungi android.debug.obsoleteApi=trueper vedere da dove proviene. c'erano alcuni metodi rinominati, con l' Provideraggiunta al loro nome.
Martin Zeitler,

1
@SergeyNarozhnyy in project gradle.properties
sigitbn

1
@SergeyNarozhnyy il 3.3.0rilascio ha interrotto alcune cose, poiché l'API variante era cambiata. può collegare una discussione recente: stackoverflow.com/questions/54206898/… (ha aggiunto un riepilogo come risposta lì).
Martin Zeitler,

3

Per quanto mi riguarda, ho seguito questi passaggi: 1. aggiorna la dipendenza Gradle dal build.gradle a livello di progetto.

        classpath 'io.fabric.tools:gradle:1.28.0'
  1. aggiungi questa dipendenza plug-in di seguito applica plug-in: 'com.android.application' nel build.gradle a livello di app.

        apply plugin: 'io.fabric'
  2. Sincronizza il progetto con file gradle.


2

Ciò accade a causa dell'aggiornamento di Android Studio da Android Studio 3.2.0 ad Android Studio 3.3.0. Aggiorna le tue dipendenze di livello (progetto) di IO.Fabric. Piace:

classpath 'io.fabric.tools:gradle:1.27.1'

e aggiorna anche la tua versione di Kotlin a

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20"

Questo risolverà questo problema. Grazie


1
Grazie. La tua risposta mi ha aiutato.
André Luiz Reis,

@Sean Se stai usando Kotlin e io febric.quindi Funziona diversamente per il downgrade della versione del tuo percorso di classe.
Funzionerà

Manca l'ID build di Crashlytics. Ciò si verifica quando gli strumenti di Crashlytics sono assenti dalla configurazione di build della tua app
Vishal Patoliya ツ

1

Il registro di build stampa come eseguire il debug di questo, in particolare è necessario eseguire build -Pandroid.debug.obsoleteApi=true, che stamperà lo stack-trace della chiamata all'API obsoleta e sarai in grado di capire quale plug-in / codice lo chiama.

Se finisce per essere il tuo codice , usa la nuova API del provider ( leggi il documento Lazy Task Configuration )

Se proviene da altri plug -in, segnalali con stack-trace e messaggio di avviso e magari invia una patch. Come in questo caso è relativo al io.fabricproblema.


1

questo problema è stato risolto nell'ultima versione del plugin Gradle Fabric, 1.28.0, che è stato pubblicato oggi. Tieni questo nel tuo build.gradle di livello superiore:

buildscript {
// ... repositories, etc. ...

dependencies {
    // ...other dependencies ...
    **classpath 'io.fabric.tools:gradle:1.28.0'**
}

0

Quando ho aperto il progetto, ho premuto il Run migrationspulsante visualizzato nell'angolo in basso a destra da Android Studio. È stata eseguita una migrazione e il problema è stato risolto senza commentare la Crashlyticsdipendenza.

inserisci qui la descrizione dell'immagine


0

La modifica della compatibilità dei sorgenti nel build.gradlefile del modulo in Java 8 risolve il problema

compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
}

Assicurati di ricostruire il progetto dopo aver aggiunto quelle righe


Al livello superiore build.gradleo al livello del modulo (/ app)?
Meow Cat 2012,

modulo livello (app)
jesses.co.tt

0

questo risolverà l'errore: sulla barra delle applicazioni fai clic su Strumenti-> Kotlin-> Configura Kotlin in Project


0

Nel mio caso, avevo bisogno di usare il io.fabricplugin, e la soluzione era, per aggiornare all'ultima versione gradle degli strumenti di fabric:

classpath 'com.android.tools.build:gradle:3.3.0'
classpath 'io.fabric.tools:gradle:1.27.0'

0

Per coloro che devono mantenere applicato il plug-in Fabric, la soluzione temporanea è di tornare alla versione precedente del livello a livello di progetto.

Cambia la versione del percorso di classe in com.android.tools.build:gradle:3.2.1.


0

Era un problema con l'ultima versione gradle(nel mio caso 3.3.2) e Fabric.ioplugin. Ora è risolto con la nuova versione gli utenti dovrebbero avere il loro alto livello build.gradle:

buildscript {
   // ... repositories, etc. ...

    dependencies {
        // ...other dependencies ...
        classpath 'io.fabric.tools:gradle:1.28.0'
    }
}

0

La correzione è l'aggiornamento dei file gradle di build root all'ultimo. E questa risposta è vera ora. nella fureture di nuovo i nuovi cambiamenti saranno implementati da SDK Android e Android. A volte la risposta varierà a tempo debito.

repositories {
    maven { url "https://jitpack.io" }
    maven {
        url 'https://maven.fabric.io/public'
    }
    google()
    jcenter()

}
dependencies {

    classpath 'com.android.tools.build:gradle:3.5.0'
    classpath 'com.google.gms:google-services:4.3.0'
    classpath 'io.fabric.tools:gradle:1.30.0'
}

-7

prima di tutto questo non è un errore

è un avvertimento

e viene visualizzato quando l'aggiornamento gradle a 3.3.0 si verifica spesso perché io.fabric quindi attendere fino a quando la versione corrente di aggiornamento tessuto in cui viene ancora visualizzato l'avviso è 'io.fabric.tools:gradle:1.27.1'

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.