অনুসন্ধানভিউ-এর অনক্লোজলিস্টার কাজ করে না


101

আমি SearchViewঅ্যান্ড্রয়েড +.০+ অ্যাকশনবারে এর জন্য সমর্থন যুক্ত করার চেষ্টা করছি , তবে আমি OnCloseListenerকাজটি করতে পারি না ।

আমার কোডটি এখানে:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    searchView = (SearchView) menu.findItem(R.id.search_textbox).getActionView();
    searchView.setOnQueryTextListener(new OnQueryTextListener() {
        @Override
        public boolean onQueryTextChange(String newText) {
            searchLibrary(newText);
            return false;
        }
        @Override
        public boolean onQueryTextSubmit(String query) { return false; }
    });
    searchView.setOnCloseListener(new OnCloseListener() {
        @Override
        public boolean onClose() {
            System.out.println("Testing. 1, 2, 3...");
            return false;
        }
    });
    return true;
}

অনুসন্ধান দুর্দান্ত কাজ করে এবং প্রত্যেকে বাদে কাজ করছে OnCloseListener। লগক্যাটে কিছুই মুদ্রিত হচ্ছে না। আমি যখন "বন্ধ" বোতাম টিপছি তখন লগক্যাটটি এখানে রয়েছে:

02-17 13:01:52.914: I/TextType(446): TextType = 0x0
02-17 13:01:57.344: I/TextType(446): TextType = 0x0
02-17 13:02:02.944: I/TextType(446): TextType = 0x0

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

হালনাগাদ:

হ্যাঁ - System.out.println() না হবে। এখানে প্রমাণ:

   @Override
 public boolean onQueryTextChange(String newText) {
    System.out.println(newText + "hello");
    searchLibrary(newText);
    return false;
 }

এই লগক্যাট ফলাফল:

02-17 13:04:20.094: I/System.out(21152): hello
02-17 13:04:24.914: I/System.out(21152): thello
02-17 13:04:25.394: I/System.out(21152): tehello
02-17 13:04:25.784: I/System.out(21152): teshello
02-17 13:04:26.064: I/System.out(21152): testhello

হুম, অ্যান্ড্রয়েড 3.2 দিয়ে আমার জন্য ঠিক আছে তবে 4.0+ এর জন্য নয়
পিজেএল

10
উত্থাপিত বাগ, 25758
পিজেএল

3
আমি আনন্দিত এটি কেবল আমার সমস্যা হচ্ছে না having কারও কি নীচের একটি ব্যতীত অন্য কোন হ্যাক আছে?
bencallis

2
showAsActionসেট করা থাকলে আমি দুটি জিনিস শিখেছি always। অনুসন্ধান বাক্সটির নিজস্ব একটি ঘনিষ্ঠ বোতাম রয়েছে তবে এটি সেট করা থাকলে ifRoom | collapseActionViewঅ্যাকশন বারে প্রসারিত হয়।
বেরাকি

উত্তর:


153

আমি এই সমস্যাটিও পূরণ করি এবং আমার "অনক্লোসেলিসটনার" ছাড়ার বিকল্প নেই। পরিবর্তে, আপনি নিজের মেনু আইটেমটি পেতে পারেন setOnActionExpandListener। তারপরে অবিযুক্তি পদ্ধতিগুলিকে ওভাররাইড করুন।

@Override
public boolean onMenuItemActionExpand(MenuItem item) {
    // TODO Auto-generated method stub
    Log.d("*******","onMenuItemActionExpand");
    return true;
}

@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
    //do what you want to when close the sesarchview
    //remember to return true;
    Log.d("*******","onMenuItemActionCollapse");
    return true;
}

আমি বিশ্বাস করি আমরা কেবল
অ্যাকশনবারের সার্চভিউ

ক্লসলিস্টনার ব্যবহার করে বিরক্ত করবেন না, কেবল আপনার মেনু আইটেমটি দিয়ে এটি ব্যবহার করুন।
রবার্ট

12
আমি মনে করি আপনি পূর্ববর্তী API স্তরের জন্য MenuItemCompat.OnActionExpandListener ব্যবহার করতে পারেন: বিকাশকারী
অ্যান্ড্রয়েড

2
পূর্ণ উত্তর:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
করুনআউটস্লাইম

61

অ্যান্ড্রয়েড API 14+ এর জন্য (আইসিএস এবং আরও বেশি) এই কোডটি ব্যবহার করুন:

// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
MenuItemCompat.setOnActionExpandListener(menuItem, new OnActionExpandListener() {
    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        // Do something when collapsed
        return true;  // Return true to collapse action view
    }

    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
        // Do something when expanded
        return true;  // Return true to expand action view
    }
});

আরও তথ্যের জন্য: http://developer.android.com/guide/topics/ui/actionbar.html# অ্যাকশনভিউ

রেফ: অন্যাকশন কলাপস / অনঅ্যাকশনএক্সপ্যান্ড


31

এই সমস্যার জন্য আমি এই জাতীয় কিছু নিয়ে এসেছি,

private SearchView mSearchView;

@TargetApi(14)
@Override
public boolean onCreateOptionsMenu(Menu menu)
{

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.conversation_index_activity_menu, menu);

    mSearchView = (SearchView) menu.findItem(R.id.itemSearch).getActionView();

    MenuItem menuItem = menu.findItem(R.id.itemSearch);

    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    {
        menuItem.setOnActionExpandListener(new OnActionExpandListener()
        {

            @Override
            public boolean onMenuItemActionCollapse(MenuItem item)
            {
                // Do something when collapsed
                Log.i(TAG, "onMenuItemActionCollapse " + item.getItemId());
                return true; // Return true to collapse action view
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item)
            {
                // TODO Auto-generated method stub
                Log.i(TAG, "onMenuItemActionExpand " + item.getItemId());
                return true;
            }
        });
    } else
    {
        // do something for phones running an SDK before froyo
        mSearchView.setOnCloseListener(new OnCloseListener()
        {

            @Override
            public boolean onClose()
            {
                Log.i(TAG, "mSearchView on close ");
                // TODO Auto-generated method stub
                return false;
            }
        });
    }


    return super.onCreateOptionsMenu(menu);

}

1
আপনি যদি সর্বদা setIconofiedByDefault (মিথ্যা) ব্যবহার করে প্রসারিত করেন তবে কি হবে? এটি কাজ করে না ... :(
জোয়ান ক্যাসাডেলি

19

অ্যান্ড্রয়েড ৪.১.১ এ আমি একই সমস্যায় পড়েছি। দেখে মনে হচ্ছে এটি একটি পরিচিত বাগ: https://code.google.com/p/android/issues/detail?id=25758

যাইহোক, একটি কর্মক্ষেত্র হিসাবে আমি রাষ্ট্র পরিবর্তন শ্রোতাদের ব্যবহার করেছি (যখন অনুসন্ধানভিশনটি অ্যাকশন বার থেকে আলাদা করা হয়, এটি স্পষ্টতই বন্ধ হয়ে যায়)।

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

    @Override
    public void onViewDetachedFromWindow(View arg0) {
        // search was detached/closed
    }

    @Override
    public void onViewAttachedToWindow(View arg0) {
        // search was opened
    }
});

উপরের কোডটি আমার ক্ষেত্রে ভাল কাজ করেছে।


আমি এখানে একই উত্তর পোস্ট করি: https://stackoverflow.com/a/24573266/2162924


হ্যাঁ, আমি এই প্রশ্নটি পোস্ট করার পরে ঠিক সেই বাগটি তৈরি করা হয়েছিল। মূল প্রশ্নের মন্তব্য দেখুন।
মিশেল বাক

ওহ ঠিক আছে, এখন দেখুন। তবে যাইহোক, সম্ভবত রাষ্ট্র পরিবর্তন শোনার সাথে এই কাজটি অন্যদের জন্যও কার্যকর হতে পারে।
দারিও

হতাশাজনক যে অনক্লোজলিস্টনার আপনার ভাবা যেমন কাজ করে না, এটি আসলে একটি দুর্দান্ত, পরিষ্কার সমাধান। যশ!
welshk91

10

আমি কিছুটা হ্যাক ব্যবহার করে শেষ করেছি, যা আমার উদ্দেশ্যটির জন্য ভাল কাজ করে - নিশ্চিত নয় যে এটি সমস্ত উদ্দেশ্য নিয়ে কাজ করবে। যাইহোক, অনুসন্ধানের অনুসন্ধানটি খালি কিনা তা দেখার জন্য আমি একটি চেক করছি doing এটি সত্য যদিও SearchViewএর সাথে সম্পর্কিত নয় OnCloseListener- এটি এখনও কাজ করে না!

searchView.setOnQueryTextListener(new OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                if (newText.length() > 0) {
                    // Search
                } else {
                    // Do something when there's no input
                }
                return false;
            }
            @Override
            public boolean onQueryTextSubmit(String query) { return false; }
        });

7

ঠিক আছে, এটি আমার সমস্যার সমাধান করেছে:

সাথে মেনু আইটেম showAsAction="always"

<item
    android:id="@+id/action_search"
    android:icon="@drawable/ic_action_search"
    android:title="Search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always"/>

এবং ক্রিয়াকলাপে

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });

1
বৈশিষ্ট্যের alwaysমান নির্ধারণ করা showAsActionসমস্যার সমাধান করে। গুরুত্বপূর্ণ বিষয়টি হ'ল যখন alwaysমান is notউপস্থিত হয় showAsAction, প্রসারিত SearchViewউপস্থাপকগুলি বন্ধ বোতামটি (ক্রস আইকন) উপস্থাপন করে তবেই যদি ক্যোয়ারী SearchViewনন-নাল স্ট্রিং থাকে। SearchView.onCloseClickedহ্যান্ডলগুলি ঘনিষ্ঠ বোতাম ঘটনা যে কলব্যাক বলে যে OnCloseListenerবলা হয় শুধুমাত্র যদি ক্যোয়ারী, খালি যদি এটা নয় - এটি প্রথম সাফ - কিন্তু তারপর, ক্লিয়ারিং ক্যোয়ারী ঘনিষ্ঠ বোতাম অদৃশ্য পর এবং আমরা উদ্ধার করতে অক্ষম onCloseকরতে কলব্যাকOnCloseListener
bpawlowski

1
কেবল একটি ইঙ্গিত: ব্যবহারকারী যখন অনুসন্ধান ভিউ বন্ধ করে দেয় তখন এই পদ্ধতিটি বলা হয় (বেশ স্পষ্ট, তবে এটি বুঝতে আমার কয়েকবার সময় লেগেছিল)। এক্সটি ক্লিক করে মুছার সময়টি ব্যবহারকারী এটি মুছে ফেলবে এবং আমি আপডেটটি পেলাম না, এক্স-এর দ্বিতীয় ক্লিকে এটি অনুসন্ধানভিউ বন্ধ করে এবং অনক্লোজকে অনুরোধ করা হয়েছে। আশা করি এটা সাহায্য করবে!
ফেডেরিকো আলভারেজ

4

OnCloseListenerকাজটি করার জন্য , অনুসন্ধান মেনু আইটেমটিতে showAsActionসেট করা alwaysআছে তা নিশ্চিত করুন।

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".SearchActivity">

    <item
        android:id="@+id/search"
        android:title="@string/search"
        android:icon="@drawable/ic_search_toolbar"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

2

অনক্লোজলিস্টনার সার্চ ভিউয়ের জন্য প্রার্থনা না করায় একই সমস্যার মুখোমুখি হয়েছি। 25758-এ উত্থাপিত বাগ ইস্যু থেকে বুঝে নিন এবং ক্লাসলিস্টনারকে অনুরোধ করার জন্য আমি কিছু পোস্টিং পড়েছি, আপনাকে সেট করতে হবে:

searchView.setIconifiedByDefault(true);

তবে আমার মামলার জন্য আমি অনুসন্ধান ভিউটি খুলতে এবং সারাক্ষণ আইকনযুক্ত না করে রাখতে চেয়েছিলাম। আমি নীচে আরও একটি লাইন যুক্ত করে এটি সমাধান করতে পরিচালনা করি:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.search_bar, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    searchView.setOnQueryTextListener(queryTextListener);
    searchView.setIconifiedByDefault(true);
    searchView.setIconified(false);
    return true;
}

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


2

app:showAsActionসর্বদা সেট সহ মেনু আইটেমটি তৈরি করুন ।

<item   
 android:id="@+id/action_search"  
 android:title="..."  
 android:icon="..."  
 app:actionViewClass="android.support.v7.widget.SearchView"  
 app:showAsAction="always"/>

যখন তৈরি SearchViewমধ্যে onCreateOptionsMenuপদ্ধতি অনুরূপ কিছু করতে

inflater.inflate(R.menu.menu_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView search = (SearchView) item.getActionView();
search.setQueryHint(getString(R.string.search_brand_item));
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
  @Override
  public boolean onQueryTextSubmit(String query) {
    // add your code
    return false;
  }

  @Override
  public boolean onQueryTextChange(String newText) {
    // add your code 
    return false;
  }
});
search.setOnCloseListener(new SearchView.OnCloseListener() {
  @Override
  public boolean onClose() {
    // add your code here
    return false;
  }
});
search.setIconifiedByDefault(true); // make sure to set this to true

search.setIconifiedByDefault(true)চাহিদা সেট হওয়ার trueকল onClose()উপর পদ্ধতি SearchView.OnCloseListener()উপরে তৈরি করা হয়েছে।



0

কারণ OnCloseListenerনা বলা হয় কারণ অ্যান্ড্রয়েড কোডে একটি বাগ আছে - শ্রোতাদের কেবল তখনই ডাকা হয় যদি আপনিও কল করেন setIconifiedByDefault(true)


7
আমি কেবল সেটআইকনডাইফাইড ডিফল্ট (সত্য) যুক্ত করার চেষ্টা করেছি তবে এটি বলা হয় না
জিউসেপ

@Joseph আর্ল: আমি একই সমস্যা এখানে হচ্ছে: stackoverflow.com/questions/43702055/... । কোন চিন্তা বা ধারণা কীভাবে ঠিক করবেন?
এজেডাব্লু

0

ইতিমধ্যে একটি পুরানো থ্রেড মনে হচ্ছে, তবে আমি ভেবেছিলাম প্রথম প্রারম্ভে আমি একই সমস্যা এপিআই 18 পেয়েছি। আশেপাশে গুগল করার পরে, এই থ্রেডটি পাওয়া গেল, আরও একটি ঘন্টা জাভাডোক পড়ার চেষ্টা করেছে এবং ভুল হয়েছে এমন কোনও কারণে যা আমি জাভাদকে পুরোপুরি বুঝতে পারি না, এখন আমার জন্য নিম্নলিখিত কাজটি:

searchView.setIconifiedByDefault(true);

   // OnQueryTextListener
   @Override
   public boolean onQueryTextSubmit(String query) {
      Log.d(tag, "onQueryTextSubmit: " + query);
      return true;
   }

   @Override
   public boolean onQueryTextChange(String query) {
      Log.d(tag, "onQueryTextChange: " + query);
      return true;
   }

   // OnCloseListener
   @Override
   public boolean onClose() {
      Log.w(tag, "onClose: ");
      return false;
   }

আমি কিছুটা সত্য / মিথ্যা দিয়ে খেলেছি, যে কোনওরকমভাবে পার্থক্য তৈরি হয় এবং এটি এখন আমার পক্ষে কাজ করে। আশা করি, এটি কারও সময় বাঁচাতে পারে।


0

এটি একটি কর্মক্ষেত্র কিন্তু আমার জন্য কাজ করেছে

  searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {

                String lastText;

                @Override
                public boolean onQueryTextChange(final String newText) {
                    if (lastText != null && lastText.length() > 1 && newText.isEmpty()) {
                        // close ctn clicked

                        return true;
                    }
}

0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

আপনি যদি ঘনিষ্ঠ অনুসন্ধান ভিউ -> এ ক্লিক করেন

ডি / ক্লিক: ক্লিক ক্লিক করুন


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

0

অনুসন্ধান ভিউয়ের প্রদর্শন / বরখাস্ত সনাক্ত করার চেষ্টা করার সময় আমি এই সমস্যার মুখোমুখি হয়েছি। আমি একটি ভিন্ন শ্রোতা ব্যবহার করে শেষ করেছি এবং এটি আমার যা প্রয়োজন তার জন্য কাজ করেছে:

        setOnQueryTextFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                // SearchView is being shown
            } else {
                // SearchView was dismissed
            }
        }

0

আমি সার্চভিউ বন্ধ বোতামটি ব্যবহার করেছি এবং এটিতে একটি সেটঅনক্লিকলিস্টনার সেট করেছি

searchView.findViewById<ImageView>(R.id.search_close_btn).setOnClickListener {
    searchView.setQuery("", false)
    searchView.clearFocus()
}

-2

লগ ইন করার জন্য অ্যান্ড্রয়েডে কোনও কনসোল নেই। পরিবর্তে, অ্যান্ড্রয়েড লগিং ফ্রেমওয়ার্কটি ব্যবহার করুন:

Log.d("Test Tag", "Testing.  1, 2, 3...");

এই প্রশ্নটি আরও দেখুন: কেন "System.out.println" অ্যান্ড্রয়েডে কাজ করে না?


2
সত্য নয়, এটি ঠিক কাজ করে। দয়া করে আমার আপডেট হওয়া প্রশ্নটি দেখুন - এটি প্রমাণ করার জন্য আমি onQueryTextChange পদ্ধতিতে একটি লাইন যুক্ত করেছি। লগ.ড () যোগ করার চেষ্টাও করেছিলেন তবে এটি কোনও কিছুই প্রদর্শন করে না।
মিশেল বাক

ওহ! আমার দুরবস্থা! দেখে মনে হচ্ছে যে তারা কোথাও লগ.আইতে System.out.println আউটপুট করার সিদ্ধান্ত নিয়েছে along শুভকামনা
ক্রিস নাইট

-3

এর জন্য দুটি সাধারণ নিদর্শন রয়েছে SearchView.setOnCloseListener()। এটি সমস্ত শ্রোতার ক্ষেত্রে সত্যই সত্য তবে আমি আপনার প্রশ্নটি বিশেষভাবে সম্বোধন করছি। প্রথম উপায় হ'ল শ্রোতার ফাংশন তৈরি করা এবং এটি একটি সদস্য ভেরিয়েবলের সাথে সংযুক্ত করা এবং দ্বিতীয়টি হ'ল ক্লাসটিকে ইন্টারফেসটি বাস্তবায়িত করা এবং হ্যান্ডলারের সদস্য ফাংশন হওয়া।

শ্রোতা অবজেক্ট তৈরি করা দেখে মনে হচ্ছে:

private SearchView mSearchView;
private final SearchView.OnCloseListener mOnCloseListener = 
    new SearchView.OnCloseListener() {
        public boolean onClose() {
            doStuff();
            return myBooleanResult;
        }
    };
mSearchView.setOnCloseListener(mOnCloseListener);

শ্রেনী শ্রেনীতে শ্রোতা প্রয়োগকারী এরকম দেখাচ্ছে:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

    public MyClass(...) {
        mSearchView.setOnCloseListener(this);
    }

    @Override
    public boolean onClose() {
        doStuff();
        return false;
    }
}

OnCloseListenerঅ্যাড-হক তৈরির কোনও উদাহরণ আমি দেখিনি , যেমনটি আপনি আপনার প্রশ্নে করেছিলেন।


আরে স্পার্কি, এ সম্পর্কে মন্তব্য করার জন্য ধন্যবাদ। কীভাবে যে কোনও কিছু পরিবর্তন করা উচিত তা আমি সত্যিই দেখছি না। নেস্টেড শ্রোতা এটিকেও তৈরি করার একটি বৈধ উপায় এবং আপনি এখানে দেওয়া মন্তব্যের উপর ভিত্তি করে দেখতে পাচ্ছেন এটি হানিকম্বের জন্য কাজ করে। আমি ছাড়াও আইসিএসে নেস্টেড শ্রোতাদের সাথে আমার কোনও সমস্যা হয়নি - যা আবার হানিকম্বের জন্য কাজ করে।
মিশেল বাক

নেস্টেড শ্রোতাদের দ্বারা আমি বেনামে অভ্যন্তরীণ ক্লাস বোঝায়।
মিশেল বাক

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

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