বিল্ড.gradle ফাইলটিতে কীভাবে স্থানীয় .jar ফাইল নির্ভরতা যুক্ত করবেন?


605

সুতরাং আমি আমার বিল্ড.gradle ফাইলটিতে আমার স্থানীয় .jar ফাইল নির্ভরতা যুক্ত করার চেষ্টা করেছি:

apply plugin: 'java'

sourceSets {
    main {
        java {
            srcDir 'src/model'
        }
    }
}

dependencies {
    runtime files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
} 

এবং আপনি দেখতে পাচ্ছেন যে আমি এখানে জাজার ফাইলগুলি রেফারেন্সড লাইব্রেরি ফোল্ডারে যুক্ত করেছি: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1/referdLibraries

তবে সমস্যাটি হ'ল আমি কমান্ডটি চালানোর সময়: কমান্ড লাইনে গ্রেড বিল্ড করার পরে আমি নিম্নলিখিত ত্রুটিটি পাই:

error: package com.google.gson does not exist
import com.google.gson.Gson;

এটি আমার সম্পূর্ণ রেপো: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1


আপনি কি সংকলনের পরিবর্তে রানটাইম সম্পর্কে নিশ্চিত? ফাইলগুলি সংকলন করুন (....)
গ্যাব্রিয়েল মারিওটি

3
দেখে মনে হচ্ছে এটি জারটি তৈরি না করতে পারলে এটি সংকলন নির্ভরতা। চেষ্টা করুন: ফাইলগুলি সঙ্কলন করুন ('libs / mnist-tools.jar', 'libs / gson-2.2.4.jar') যদি আপনার এখনও সমস্যা থাকে তবে অবধারিত পথগুলি চেষ্টা করুন যা ইস্যুতে পারে।
patrz jaka franca

1
এই স্ট্যাক ওভারফ্লো প্রশ্নটি শেষ পর্যন্ত আমাকে আমার প্রয়োজনীয় উত্তর দিয়েছে।
16:54

উত্তর:


455

আপনার যদি সত্যিই কোনও স্থানীয় ডিরেক্টরি থেকে .jar নেওয়ার দরকার হয়,

আপনার মডিউল গ্রেডেলের পাশে যুক্ত করুন (অ্যাপ গ্রেড ফাইল নয়):

repositories {
   flatDir {
       dirs 'libs'
   }
}


dependencies {
   implementation name: 'gson-2.2.4'
}

যাইহোক, একটি প্রকৃত মেভেন স্টোরের মধ্যে স্ট্যান্ডার্ড .jar হওয়ার কারণে আপনি কেন এটি চেষ্টা করেন না?

repositories {
   mavenCentral()
}
dependencies {
   implementation 'com.google.code.gson:gson:2.2.4'
}

4
। আমি ঠিক এই খুঁজছেন এসেছিলেন, কিন্তু আমি দেখেছি যে আমার স্থানীয় সংগ্রহস্থলের সকর্মক নির্ভরতা মীমাংসা না (যেমন minecraftforge.net দ্বারা নিষ্কাশিত 1.5.21 Gradle 2.7, উদাহরণস্বরূপ খুলুন POM হয় com.mojang: authlib)
কার্ল পৌত্তলিক

1
আপনার যদি একাধিক ডিরেক্টরিতে স্থানীয় জার ফাইল থাকে তবে আপনার সমস্তগুলি ফ্ল্যাটডিরে যুক্ত করা দরকার। উদা: - ফ্ল্যাটডির {ডায়ার্স 'লিবিজ 1', 'লিবিস 2', 'লিবিস 3'}
ধুমিল আগরওয়াল

9
আমার একটি gradle.buildফাইল রয়েছে - এই "অ্যাপ গ্রেডেল ফাইল" এবং "মডিউল গ্রেডেল" কী?
লিয়ালো

2
এই সুযোগগুলির বর্ণনা দিয়ে কেউ অফিসিয়াল গ্রেডল ডকুমেন্টেশন বিভাগের লিঙ্ক সহ উত্তরটি আপডেট করার কোনও সুযোগ আছে?
মিসানথ্রোপ

2
implementation(":gson:2.2.4")এটি করার উপায় বলে মনে হচ্ছে।
ইঞ্জিফুয়াড

697

ডকুমেন্টেশন অনুসারে , স্থানীয় জার নির্ভরতার জন্য নিম্নলিখিত হিসাবে একটি আপেক্ষিক পথ ব্যবহার করুন:

dependencies {
    implementation files('libs/something_local.jar')
}

8
@ গুব্যাট্রন এটি এখন নথিভুক্ত করেছে: গ্রেড.আর.এল
ডেভিড মোলস

7
যারা কেবল আমাদের জারে আপেক্ষিক পাথ ব্যবহার করছেন তাদের জন্য: যুক্তিগুলি নির্ভর করে depend ফাইলগুলি সঙ্কলন করুন ("libs / काहीतरी_local.jar" ie (অর্থাত্ ডাবল-কোটস একক-কোট নয়) পথটি মূল্যায়নের জন্য গ্রোভি প্রয়োজন by একক- কোট খাঁজকাটা আক্ষরিক নেয়া হয়।
specialk1st

সুতরাং আমি একই জিনিসটি ব্যবহার করছি এবং আমি সংকলন ত্রুটি পেয়েছি (দেখে মনে হচ্ছে এটি সেখানে জারটি খুঁজে পায় না))
আরভি_দেব

আমি এই সমাধানটি পছন্দ করব, তবে আমি খুঁজে পেয়েছি যে যদি ফাইলটি না থাকে তবে গ্রেডল দ্বারা কোনও ত্রুটি আউটপুট করা হয় না। আমি খুঁজে পেয়েছি এই ব্যক্তিগতভাবে বিস্তারিত জানার জন্য এই তাই প্রশ্ন দেখুন: stackoverflow.com/q/42527631/4851565
entpnerd

এই সমাধানটি ব্যবহার করার পরেও আমি একই ধরণের ত্রুটি পেয়েছিলাম। ভুলটি আমি অ্যাপ্লিকেশনগুলির মতো লিভস ফোল্ডারটি অ্যাপ্লিকেশনগুলির মতো একই স্তরে রাখি না
isষভ দুগার

314

আপনি এটি করতেও পারেন যা স্থানীয় সংগ্রহস্থলের সমস্ত জেআর অন্তর্ভুক্ত করে। এইভাবে আপনাকে প্রতিবার এটি নির্দিষ্ট করতে হবে না।

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

3
এটি lib ডিরেক্টরিতে সমস্ত জার সংকলনের জন্য ব্যবহৃত হয়। এটির সঠিক সমাধান (y)
শেরাজ আহমেদ খিলজি

1
... যদি না আপনি সেই libs ডিরেক্টরিটি বিভিন্ন মডিউলগুলির সাথে বিভিন্ন নির্ভরতার বিভিন্ন সেট, যেমন ক্লায়েন্ট কোডের সাথে সার্ভার কোড স্থাপন না করা, বা বিভিন্ন উপ-মডিউলটিতে নির্ভরতার একাধিক সংস্করণ না থাকার সাথে ভাগ করে নেওয়ার পরিকল্পনা করেন না।
আয়াক্স

এটি গ্রহণযোগ্য উত্তরের চেয়ে আমার পছন্দসই বাস্তবায়ন কারণ এটি ফাইলগুলির অবস্থান স্পষ্টভাবে উল্লেখ করে। আপনি যখন কিছু লাইব্রেরির জন্য মেভেনসেন্ট্রাল এবং অন্যের জন্য স্থানীয় অনুলিপিগুলির মতো কোনও সংগ্রহস্থল উল্লেখ করেন তখন এটি কার্যকর। সেক্ষেত্রে গ্রেড অন্যান্য সংগ্রহস্থলগুলিতে স্থানীয় গ্রন্থাগারগুলির জন্য অনুসন্ধান করতে গিয়ে পিছিয়ে থাকতে পারে।
satbot

1
দ্রষ্টব্য যে dir এছাড়াও একটি পরম পথ হতে পারে। এছাড়াও 'অন্তর্ভুক্ত' এর পরিবর্তে আমাকে 'অন্তর্ভুক্ত' ব্যবহার করতে হয়েছিল।
এরিয়েল মেরিমন

53

নিম্নলিখিতটি আমার পক্ষে কাজ করে:

compile fileTree(dir: 'libs', include: '*.jar')

পড়ুন Gradle ডকুমেন্টেশন


6
উজ্জ্বল উত্তর, একমাত্র সমাধান যা কয়েক দিনের সন্ধানের পরে আমার পক্ষে কাজ করেছিল
স্টারডাস্ট

এটি মনে রাখা গুরুত্বপূর্ণ যে এই পদ্ধতিটি আপনি যদি আপনার প্রকল্পের সাথে নির্দিষ্ট গ্রন্থাগারটি সংকলন করতে না চান তবে আপনাকে এটি libs ফোল্ডার থেকে মুছতে হবে ... আমি এই পদ্ধতিটি পছন্দ করি না কারণ আমি কোন লাইব্রেরি দেখতে পাই না আমি লাইব্রেরিতে প্রবেশ না করে যোগ করা হয়েছে
যিশু ডিম্রিক্স

1
@ নাইটওয়ালফের উত্তরের চেয়ে এটি কীভাবে আলাদা?
ট্রেনটন

2
Org.gradle.api.intern.artifacts.dsl.d
dependency.DefaultD

33

আপনি গ্রেডলের জন্য স্থানীয় স্থানীয় মাভেন সংগ্রহশালা পুনরায় ব্যবহার করার চেষ্টা করতে পারেন:

  • আপনার স্থানীয় মাভেন সংগ্রহস্থলে জারটি ইনস্টল করুন:

    mvn install:install-file -Dfile=utility.jar -DgroupId=com.company -DartifactId=utility -Dversion=0.0.1 -Dpackaging=jar

  • আপনার ~/.m2/স্থানীয় মাবেন রেপোজিটরিতে আপনি জারটি ইনস্টল করেছেন কিনা তা পরীক্ষা করুন

  • আপনার build.gradleফাইলে আপনার স্থানীয় মাভেন সংগ্রহস্থল সক্ষম করুন:

    repositories {
      mavenCentral()  
      mavenLocal()  
    }
    
    dependencies {  
      implementation ("com.company:utility:0.0.1")  
    }
    • আপনার প্রকল্পে বাস্তবায়নের জন্য এখন আপনার পাত্রটি সক্ষম করা উচিত

অন্য সবাই ব্যর্থ হলে এই আমাকে সাহায্য করেছিল!
ব্যবহারকারী 3

এটি কাজ করার সময়, এটি চারপাশের কাজ এবং স্বয়ংক্রিয় উত্পাদন / পর্যায়ে পরিবেশে ব্যবহার করা উচিত নয় কারণ এটি বিল্ড সিস্টেমে .m2 ফোল্ডার (মাভেন ইনস্টলেশন) করার অতিরিক্ত নির্ভরতা যুক্ত করে।
saurav.varma

29

গৃহীত উত্তরটি ভাল, তবে আমার একই মাল্টি-প্রজেক্ট গ্রেডল বিল্ডের মধ্যে একই তৃতীয় পক্ষের জাভা লাইব্রেরিটি ব্যবহার করার জন্য বিভিন্ন গ্রন্থাগার কনফিগারেশনগুলির দরকার পড়ে।

'যোগ করার পদ্ধতি $ rootProject.projectDir ' থেকে ' Dir আমার' মধ্যে 'পথ উপাদান allprojects বোঝানো' অবসান প্রতিটি উপ-প্রকল্পের একই 'রেফারেন্সড লিব ' ডিরেক্টরিতে, এবং না উপ-প্রকল্প থেকে একটি সংস্করণ স্থানীয়:

//gradle.build snippet
allprojects {
    ...

    repositories {
        //All sub-projects will now refer to the same 'libs' directory
        flatDir {
            dirs "$rootProject.projectDir/libs"
        }
        mavenCentral()
    }

    ...
}

কুইজির সম্পাদনা: "$ {রুটপ্রজেক্ট.প্রজেক্টডির}" কে "$ রুটপ্রজেক্ট.প্রজেক্টডির" (নতুন গ্র্যাডেল সংস্করণে কাজ করে) এ পরিবর্তন করা হয়েছে।


2
কিন্তু লাইব্রেরি বিল্ড.gradle ফাইলের এই লিবস ফোল্ডারটি কীভাবে উল্লেখ করবেন? যে কোনও সহায়তা।
জিভ

1
এটিকে আবার কাজ করতে কেবল "$ {রুটপ্রজেক্ট.প্রজেক্টডির}" "$ রুটপ্রজেক্ট.প্রজেক্টডির" এ পরিবর্তন করুন।
কুইজি

4
একক উদ্ধৃতিগুলির চেয়ে দ্বিগুণ উদ্ধৃতি ব্যবহার করা নিশ্চিত করুন কারণ পরেরটি ইন্টারপোল্ট হবে না।
এফপি অবাধে

1
এই পদ্ধতির সাহায্য আমাকে।
শ্রেয়াশ

1
এখানে সমস্ত উত্তর আমাকে অনেক সাহায্য করেছে। এই নিদর্শনটি আমরা ব্যবহার করছি এটি একটি এবং এটি দলে কাজ করা লোকদের পক্ষে শাখায় কাজ করার সময় সেই ডিরেক্টরিতে কেবল জেআরগুলি ফেলে রাখা সহজ করে তোলে।
লুসি

12

এটি করার একটি সহজ উপায়

compile fileTree(include: ['*.jar'], dir: 'libs')

এটি অ্যাপে আপনার libs ডিরেক্টরিতে থাকা সমস্ত .jar ফাইল সংকলন করবে।


ফাইলটি ট্রি লিব্স ফোল্ডারে সমস্ত উপ-ডিরেক্টরিতে কাজ করে। লিবস / স্পাইং / স্প্রিং.জারের ভিতরে কয়েকটি জারের উদাহরণ, এই ক্ষেত্রে এটি বসন্ত অন্তর্ভুক্ত করে? জার এছাড়াও?
মিলিগ্রাম

না, তা হয় না। প্রযুক্তিগতভাবে এটির পাশাপাশি হওয়া উচিত নয়, যেমন আমরা 'দির: লিবস' দিই bs
ZygoteInit

এই ক্ষেত্রে কিভাবে ন্যূনতম কাজগুলো সঙ্গে সাবডিরেক্টরি থেকে সমস্ত লাইব্রেরি পেতে (কারণ আমাদের প্রকল্পের অনেক সাবডিরেক্টরি থাকে।
Mgr

আরে @ মল্লিকগ্রাম দেরী জবাবের জন্য দুঃখিত, আপনি কি সঙ্কলিত ফাইলটি গাছের মতো দির পথে ওয়াইল্ডকার্ড যুক্ত করার চেষ্টা করেছিলেন (অন্তর্ভুক্ত: ['.জার '], দির: '
লিবিস

2
@ নাইটওয়ালফের উত্তরের চেয়ে এটি কীভাবে আলাদা?
ট্রেনটন

10

কোটলিন ডিএসএল ব্যবহারকারীদের জন্য একটি সমাধান

এখনও অবধি যুক্ত সমাধানগুলি ওপির পক্ষে দুর্দান্ত, তবে কোটলিন ডিএসএল এর সাথে প্রথমে অনুবাদ না করে ব্যবহার করা যাবে না। আমি কীভাবে কোটলিন ডিএসএল ব্যবহার করে আমার বিল্ডে একটি স্থানীয়। জেআর যুক্ত করেছি তার একটি উদাহরণ এখানে:

dependencies {
    compile(files("/path/to/file.jar"))
    testCompile(files("/path/to/file.jar"))
    testCompile("junit", "junit", "4.12")
}

মনে রাখবেন যে আপনি যদি উইন্ডোজ ব্যবহার করেন তবে আপনার ব্যাকস্ল্যাশগুলি এড়াতে হবে:

...
compile(files("C:\\path\\to\\file.jar"))
...

এবং এও মনে রাখবেন যে উদ্ধৃতি চিহ্নগুলি একক উদ্ধৃতি নয়, ডাবল উদ্ধৃতি হতে হবে।


2020 এর জন্য সম্পাদনা করুন:

Gradle আপডেট অবচিত হয়েছে compileএবং testCompileএর পক্ষে implementationএবং testImplementation। সুতরাং উপরের নির্ভরতা ব্লকটি বর্তমান গ্রেডল সংস্করণগুলির জন্য দেখতে এইরকম হবে:

dependencies {
    implementation(files("/path/to/file.jar"))
    testImplementation(files("/path/to/file.jar"))
    testImplementation("junit", "junit", "4.12")
}

1
+1 আমার পক্ষে কাজ করেছে! আপনি কি জানেন যে জার ফাইলটি তৈরি না করেও কীভাবে এটি করা যায় (যদি আমি জারটি তৈরির ক্ষেত্রে ঘটি)?
করিম জিরোদি

2
@KareemJeiroudi আমি তোমার প্রশ্ন ভুল বুঝা যেতে পারে, কিন্তু আপনি একটি মডিউল প্রকল্পের নির্ভরশীলতার উপার্জন বিষয়ে কথা হয়, আপনি এই ভালো কিছু করতে চাই: compile(project(":MyProject")), যেখানে "MyProject" আপনার সংজ্ঞায়িত করা হয় settings.gradleভালো কিছু ফাইল include("MyProject")
জোনাথন ল্যান্ড্রাম

8

আমি উপরের পরামর্শটি https://stackoverflow.com/a/20956456/1019307 এ কাজ করতে পারি না । এটি যদিও আমার পক্ষে কাজ করেছিল। এই প্রকল্পের মূলটিতে secondstring-20030401.jarআমি একটি libs/ডিরেক্টরিতে সঞ্চয় করেছিলাম এমন একটি ফাইলের জন্য :

repositories {
    mavenCentral()
    // Not everything is available in a Maven/Gradle repository.  Use a local 'libs/' directory for these.
    flatDir {
       dirs 'libs'
   }
}

...

compile name: 'secondstring-20030401'

ধন্যবাদ! কেন জানি না তবে কেবল এটিই আমার পক্ষে কাজ করেছিল। আমার প্রকল্পের মূলটিতে একটি 'libs' ফোল্ডার তৈরি করেছে, সেখানে .jar shoved করে এবং আপনার 'সংকলন নাম' এন্ট্রি অনুলিপি করেছে। .Jar এক্সটেনশনটি অবশ্যই পড়েছে।
anon58192932

নাহ, এটি আমার কাজ করে না এটি খুঁজে পাওয়া যায়নি: মাইলেআউটআউট-কোর:। নিম্নলিখিত অবস্থানগুলিতে অনুসন্ধান করা হয়েছে: ফাইল: / ব্যবহারকারীর /পাথ / টো / মিগলেআউট-कोर.জার
ওয়েল স্মিথ

আপনি যদি কোনও ফাইল ডিরেক্টরি সংগ্রহস্থল হিসাবে যুক্ত করতে চান তবে এই কাজটি করুন: docs.gradle.org/current/userguide/…
গ্রুবার্ট

7

প্রশ্নের ইতিমধ্যে বিশদে উত্তর দেওয়া হয়েছে। আমি এখনও এমন কিছু যুক্ত করতে চাই যা আমার কাছে খুব অবাক লাগে:

"গ্রেড নির্ভরতা" টাস্ক কোনও ফাইল নির্ভরতা তালিকাভুক্ত করে না। যদিও আপনি সম্ভবত এটি ভাবতে পারেন, কারণ সেগুলি সর্বোপরি "নির্ভরতা" ব্লকে নির্দিষ্ট করা হয়েছে ..

সুতরাং আপনার রেফারেন্সড স্থানীয় lib ফাইলগুলি সঠিকভাবে কাজ করছে কিনা তা পরীক্ষা করার জন্য এটির ফলাফলের উপর নির্ভর করবেন না।


6

যে সমাধানটি আমার পক্ষে কাজ করেছে তা হ'ল বিল্ড.gradle ফাইলটিতে ফাইলট্রি ব্যবহার। লিবার্স ফোল্ডারে নির্ভরতা হিসাবে যুক্ত করার জন্য .ar রাখুন। বিল্ড.gradle এ নির্ভরশীল ব্লকগুলিতে নীচের কোডটি দিন:

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

5

এটি করার সর্বোত্তম উপায় হ'ল এটি আপনার বিল্ড.gradle ফাইলটিতে যুক্ত করুন এবং সিঙ্ক বিকল্পটি হিট করুন

dependency{
    compile files('path.jar')
}

3

আপনি করণীয় যোগ করতে পারেন:

গ্রেডের জন্য কেবল নিম্নলিখিত কোডগুলি রাখুন build.gradle:

dependencies {
...
compile fileTree(dir: 'lib', includes: ['suitetalk-*0.jar'])
...
}

এবং মাভেনের জন্য কেবল পদক্ষেপগুলি অনুসরণ করুন:

ইন্টেলিজের জন্য: ফাইল-> প্রকল্প কাঠামো-> মডিউল-> নির্ভরতা ট্যাব-> ক্লিক করুন + সাইন-> জার এবং নির্ভরতা-> আপনি যে আমদানি করতে চান তা নির্বাচন করুন-> ঠিক আছে-> প্রয়োগ করুন (দৃশ্যমান হলে) -> ঠিক আছে

মনে রাখবেন যে java.lang.NoClassDefFoundError: Could not initialize classরানটাইমটিতে আপনি যদি কোনও ব্যতিক্রম পেয়ে থাকেন তবে এর অর্থ হ'ল জারে নির্ভরতাগুলি ইনস্টল করা হয়নি যার জন্য আপনাকে প্যারেন্ট প্রোজেক্টে সমস্ত নির্ভরশীলতা যুক্ত করতে হবে।


0

গোটো ফাইল -> প্রকল্পের কাঠামো -> মডিউলগুলি -> অ্যাপ্লিকেশন -> নির্ভরতা ট্যাব -> + (বোতাম) -> ফাইল নির্ভরতা নির্বাচন করুন -> লিব ফোল্ডারে জার ফাইলটি নির্বাচন করুন

এই পদক্ষেপগুলি স্বয়ংক্রিয়ভাবে গ্রেডের সাথে আপনার নির্ভরতা যুক্ত করবে

খুব সহজ


3
এটি কিছু জাভা আইডিই মেনুগুলির মধ্য দিয়ে যেতে পারে? সম্ভবত আইডিয়া?
উতগারদা

1
হ্যাঁ, এটি ইন্টেলিজ আইডিইএর জন্য কোনও কিছুর মতো দেখায় এবং আমার মনে হয় না এটি কার্যকর হবে। অথবা, দেখে মনে হবে এটি গ্রেডল সেটআপে পরিবর্তন না আসা পর্যন্ত এটি কাজ করে যা একটি "সিঙ্ক্রোনাইজেশন" হয়ে থাকে এবং সিঙ্ক্রোনাইজেশন গ্রেডল থেকে ইন্টেলিজি সেটিংসে একমুখী হয়। এটি অন্যভাবে সিঙ্ক্রোনাইজ করে না - কমপক্ষে আমি এটি মনে করি না।
রেনিপিট

1
আপনি যদি স্বয়ংক্রিয়ভাবে আমদানি নির্বাচিত হন তবে ম্যানুয়ালি আমদানি করা হয়েছে J জার পরবর্তী পরিবর্তনতে সরানো হবে build.gradle
জোনাথন ল্যান্ড্রাম

-1

আপনি যদি অবিচ্ছিন্ন ইন্টিগ্রেশন ব্যবহার করে থাকেন তবে সাবধান হন, আপনাকে অবশ্যই আপনার বিল্ড সার্ভারে আপনার পাঠাগারগুলিকে একই পথে যুক্ত করতে হবে।

এই কারণে, আমি বরং স্থানীয় সংগ্রহস্থলে জার যুক্ত করব এবং অবশ্যই বিল্ড সার্ভারে এটি করব।


-3

অন্য উপায়:

ট্রি ভিউটিতে লাইব্রেরি যুক্ত করুন। এই এক ডান ক্লিক করুন। মেনু নির্বাচন করুন "পাঠাগার হিসাবে যুক্ত করুন"। একটি কথোপকথন উপস্থিত হবে, আপনাকে মডিউলটি নির্বাচন করতে দিন। ঠিক আছে এবং এটি সম্পন্ন হয়েছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.