GithubHelp home page GithubHelp logo

tonicartos / superslim Goto Github PK

View Code? Open in Web Editor NEW
2.1K 2.1K 298.0 1.29 MB

A layout manager for the RecyclerView with interchangeable linear, grid, and staggered displays of views, all with configurable section headers including the sticky variety as specified in the material design docs.

Home Page: http://tonicartos.nz

Java 13.05% Kotlin 86.95%
android-library kotlin superslim

superslim's People

Contributors

tonicartos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

superslim's Issues

ItemDecorator 找不到?

你好我刚学习 使用 android studio
您的 包 我是这样导入 的 compile 'com.tonicartos:superslim:0.4.+'
可是 找不到 ItemDecorator 这个类

LinearSLM GridSLM 这两个缺可以导入 我导入错误了吗??

A section without a header throws NullPointerException.

LayoutManager.java lines 88,89:
final LayoutState.View header = section.getSectionHeader(state);
final LayoutParams params = header.getLayoutParams();

section.getSectionHeader(state) returns null if a header does not exist, so we need to check if header is null prior to retrieving the layoutParams.

Improve performance while scrolling.

There is too much work being done while scrolling. Many items and sections are being handled when they can just be ignored just for scrolling. LayoutManager and SLM implementations should be careful to handle a minimum of views.

This will require considerable thought about the fill and scroll interaction between LayoutManager and SLM implementations.

Gridlayout ignores margins

Hi!

first of all: a nice library. A bit hard to setup, but the result is amazing!

I have a little issue: The GridSectionLayoutManager ignores the margin on my layouts.

I have some CardViews that use a layout_margin of 8dp in the topmost view. The default layoutmanagers in the RecyclerView support library recognize this margin and render the views accordingly. However your manager requires another view wrapped around it to make the margin visible.

LayoutParams.layoutId confusing name.

Could we consider renaming layoutId? Perhaps to sectionId, section, or sectionManager? The value refers to the id/position of the section in the SectionLayoutManager.

final LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) holder.itemView.getLayoutParams();
lp.layoutId = 1;
final LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) holder.itemView.getLayoutParams();
lp.section = 1;
lp.sectionId = 1;
lp.sectionManager = 1;

I think one of these is easier to understand/read.

Headers are displayed underneath the regular cards

Hi again!

I found another issue: Sticky headers are somehow displayed below my cards. this may have something to do with the elevation level of a card on Android 5, but I am really not sure.. Could you have a look at it and make sure that headers are always on top? (telling me what may be wrong is also an option ;) )
screenshot_2015-03-03-09-26-23

The Layoutmanager ignores visibility attributes

Hi again,

apparently the layoutmanager ignored the visibility attribute of the views. I have a solution in place that switches the headers to invisible if they are empty (but they start a new section nevertheless).

Unfortunately I have to set the height to 0 in the layout params ot make it work as expected. Perhaps consider implementing this in one of the next releases.

Decorators

Built-in decoration of items. e.g. list item dividers and padding between items. There has been an implementation of this between versions 4 and 5. It will need to be ported to the new version.

Horizontal orientation

Amazing library! How's support for horizontal orientation? It's not stated anywhere on the README or the wiki.

Bug: headers might overlap items

Like so:

device-2015-01-04-230839

BTW, please also check RTL . I remember there were issues on similar libraries when handling RTL languages, especially when the alignment changes. I didn't check this on this library yet. Hope it works well.

View "jumping" on scroll when not enough items to fill screen

When there are only a few items, so the view only fills part of the screen, and I try to scroll, the whole view jumps to the bottom of the screen (and back to the top if I scroll in the other direction).

To reproduce just remove most of the countries from the example app, so the view does not fill the screen. Then try to scroll up and down.

Only disable necessary stickiness for headers while scrolling.

If a sticky header has been targeted for a smooth scroll, a view above or below it should be selected and the final resting place of the smooth scroll offset to place the header as though it had been targeted.

This is to workaround sticky headers being attached early in scrolls towards the top.

Missing find position methods that exist in other LayoutManager implementations.

int findFirstCompletelyVisibleItemPosition()
Returns the adapter position of the first fully visible view.

int findFirstVisibleItemPosition()
Returns the adapter position of the first visible view.

int findLastCompletelyVisibleItemPosition()
Returns the adapter position of the last fully visible view.

int findLastVisibleItemPosition()
Returns the adapter position of the last visible view.

superslim layoutmanager provide loadmore method?

hi,
I'm using superslim in my project but I face a big problem to load more item when i am scrolling to the end of my data.

In recyclerview to trigger loadmore method we need Layoutmanger to tell us some infomation
for example
int lastVisibleItem = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
int totalItemCount = mLayoutManager.getItemCount();
//lastVisibleItem >= totalItemCount - 4

            if (lastVisibleItem >= totalItemCount - 4 && dy > 0) {
                loadPage(currentQueryMap);
            }

can you provide some method for me? thanks

Bug when 'fling' scrolled to the recycler` top or bottom edge

I test it both in the raw-sample-app and my app, the bug still exist.
I describe it as follows:
When 'flying' to the edge, the recylerview becomes imperfect.
If the Itemheight is enough tall ,which lead to the 'flying' speed enough slow, the bug wont occured.

Screen shots(initial, 'flying' to the top edge of the screen, flying agin):

1
2
3

Why it occured?

Coord: layoutId change

Issue to coordinate code and wiki changes, but to ensure wiki changes are only done at release time.

  • refactor code with new name. #28.
  • update [getting started guide](../wiki/Getting Started).
  • update [attr reference](../wiki/Content View Attributes and Parameters).

onCreateViewHolder is being spammed again

I noticed this after updating to the 0.4.0 release - onCreateViewHolder gets called rapidly on scroll. Reverting to 0.2.4 fixes it.

I'm assuming this is a regression of either issue #15 or issue #13 or both.

compatibility with twoway-view?

I am very interested by your library as i am looking for an equivalent of the UICollectionView.

While looking i stubbled upon twoway-view which also brings a lot to RecycleView

It would be amazing for both to work together ;)

Cache section data for scroll indicator computation

Caching section data for use in the scroll indicator computation will allow for people to only need to reference SLMs in the first items in a section.

However, there aren't any significant advantages to this change. The API would be just a little more flexible for reusing xml layouts. In some cases there might be a little less coding.

Null Pointer exception

Hello,

I have downloaded your example. when I try to run the example, it got crashed with Null Pointer exception. you can have a look on the crash log below.

01-07 13:51:55.819 1224-1224/com.tonicartos.superslim.example E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.tonicartos.superslim.example, PID: 1224
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.ViewGroup$LayoutParams android.view.View.getLayoutParams()' on a null object reference
at android.support.v7.widget.RecyclerView$LayoutManager.getPosition(RecyclerView.java:5017)
at com.tonicartos.superslim.LayoutManager.computeVerticalScrollOffset(LayoutManager.java:700)
at android.support.v7.widget.RecyclerView.computeVerticalScrollOffset(RecyclerView.java:1115)
at android.view.View.canScrollVertically(View.java:12724)
at android.support.v4.view.ViewCompatICS.canScrollVertically(ViewCompatICS.java:34)
at android.support.v4.view.ViewCompat$ICSViewCompatImpl.canScrollVertically(ViewCompat.java:907)
at android.support.v4.view.ViewCompat.canScrollVertically(ViewCompat.java:1192)
at android.support.v7.widget.RecyclerView$LayoutManager.onInitializeAccessibilityEvent(RecyclerView.java:6322)
at android.support.v7.widget.RecyclerView$LayoutManager.onInitializeAccessibilityEvent(RecyclerView.java:6301)
at android.support.v7.widget.RecyclerViewAccessibilityDelegate.onInitializeAccessibilityEvent(RecyclerViewAccessibilityDelegate.java:66)
at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateJellyBeanImpl$1.onInitializeAccessibilityEvent(AccessibilityDelegateCompat.java:228)
at android.support.v4.view.AccessibilityDelegateCompatJellyBean$1.onInitializeAccessibilityEvent(AccessibilityDelegateCompatJellyBean.java:56)
at android.view.View.onInitializeAccessibilityEvent(View.java:5415)
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:5288)
at android.view.View$AccessibilityDelegate.sendAccessibilityEventUnchecked(View.java:20706)
at android.support.v4.view.AccessibilityDelegateCompatIcs.sendAccessibilityEventUnchecked(AccessibilityDelegateCompatIcs.java:117)
at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateIcsImpl.sendAccessibilityEventUnchecked(AccessibilityDelegateCompat.java:210)
at android.support.v4.view.AccessibilityDelegateCompat.sendAccessibilityEventUnchecked(AccessibilityDelegateCompat.java:358)
at android.support.v4.view.AccessibilityDelegateCompat$AccessibilityDelegateJellyBeanImpl$1.sendAccessibilityEventUnchecked(AccessibilityDelegateCompat.java:255)
at android.support.v4.view.AccessibilityDelegateCompatJellyBean$1.sendAccessibilityEventUnchecked(AccessibilityDelegateCompatJellyBean.java:82)
at android.view.View.sendAccessibilityEventUnchecked(View.java:5273)
at android.view.ViewRootImpl$SendWindowContentChangedAccessibilityEvent.run(ViewRootImpl.java:6831)
at android.view.ViewRootImpl$SendWindowContentChangedAccessibilityEvent.runOrPost(ViewRootImpl.java:6857)
at android.view.ViewRootImpl.postSendWindowContentChangedCallback(ViewRootImpl.java:6051)
at android.view.ViewRootImpl.notifySubtreeAccessibilityStateChanged(ViewRootImpl.java:6164)
at android.view.ViewGroup.notifySubtreeAccessibilityStateChanged(ViewGroup.java:2788)
at android.view.ViewGroup.notifySubtreeAccessibilityStateChanged(ViewGroup.java:2788)
at android.view.ViewGroup.notifySubtreeAccessibilityStateChanged(ViewGroup.java:2788)
at android.view.ViewGroup.notifySubtreeAccessibilityStateChanged(ViewGroup.java:2788)
at android.view.ViewGroup.notifySubtreeAccessibilityStateChanged(ViewGroup.java:2788)
at android.view.View.notifySubtreeAccessibilityStateChangedIfNeeded(View.java:7978)
at android.view.ViewGroup.addViewInner(ViewGroup.java:3941)
at android.view.ViewGroup.addView(ViewGroup.java:3733)
at android.view.ViewGroup.addView(ViewGroup.java:3678)
at android.support.v7.widget.RecyclerView$4.addView(RecyclerView.java:334)
at android.support.v7.widget.ChildHelper.addView(ChildHelper.java:79)
at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:4955)
at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:4913)
at com.tonicartos.superslim.LinearSectionLayoutManager.addView(LinearSectionLayoutManager.java:356)

Request: add fast-scroller

As the title says.
It's like on the ListView and as shown on the contacts app, so that the user could scroll easily and go through the sections.

Scrolling issues

Hi,

I think I found another issue:

I have a grid layout with variable size cards. If the first card in the last line is bigger than the rest it is cut off. Also I can't scroll back to the top in this case.

The layout item is completely displayed if I first scroll down and then turn the display (probably repainting the view)

Edit: I am using the width-based version of the grid layout.
Edit 2: If I scroll fast enough I will get the complete item visible

Section declaration is subpar

Update

Okay, so the plan is to implement 2.a only.

Here are the changes that will happen.

Constructors:

// Basic constructor to use if you don't have the adapter constructed already. Using this
// constructor requires that RecyclerView#setLayoutManager(LayoutManager lm) must 
// be called before RecyclerView#setAdapter(Adapter a). Failure to do so will result in a
// runtime exception.
public LayoutManager(Context context);

// Standard constructor.
public LayoutManager(Context context, SectionAdapter adapter);

When RecyclerView#setAdapter(Adapter a); is called, if the adapter does not implement the SectionAdapter interface, a ExpectedSectionAdapterRuntimeException is thrown. It will print an error log message along the lines of, "Expected SectionAdapter but received Adapter instead."

If LayoutManager#onLayoutChildren(…) is called before LayoutManager has pulled the section data from an adapter, a AdapterNotSetRuntimeException is thrown. It will print an error log message along the lines of, "Adapter not set before layout. Instances of LayoutManager created with the LayoutManager(Context context) constructor must be added to a recycler view before the adapter is set."

New interface in LayoutManager:

interface SectionAdapter {
    List<Integer> getSectionStartPositions();
}

Proposal

I've been working on the data change animation support and one thing I've decided is that having to update section first position on all the items is really annoying. I mean, the data change notification range isn't even limited to the same section.

The biggest restriction on the API is that the first section item has to be found in some way. This is because section layouts are dynamic and derived from the header state. This means there is no loss to keeping section configuration in the layout params, which gives us the nicety of embedding configuration in xml.

Bearing that in mind, here are my thoughts on the API changes to reduce the adapter burden:

1. Let SuperSLiM find section start positions

1.a Section start indicator

Only the first item in a section is marked. SuperSLiM has to do a linear search to look for this marker to properly load section data. This isn't so bad because it will only have to be done once per layout call, possibly less. However, linear search sucks, especially when you have to inflate a whole bunch of views to do it.

In just the first item.

slm_sectionStart="true"

or

params.setSectionStart(true);

Pros

  • Trivial to use.

Cons

  • Performance for large sections may be compromised for fresh layouts and scrolling upwards.
  • Have to manage the first item in a section.

1.b Section ids

In addition to the above, add unique section ids to each item, and let SuperSLiM look for the first item. Better than the above because a binary search can be used.

In all section items.

slm_sectionId="56"

or

params.sectionId=56

Pros

  • Simpler to use than the current system.
  • Better performance than 1.a.

Cons

  • Must mark up all items.
  • Still have to manage the first item in a section.

2. Provide section start positions

2.a Out-of-band channel

Provide section start positions in a second channel. This means you would have to implement an interface in your adapter and pass it in the LayoutManager constructor. Also, if you change the adapter on the RecyclerView, LayoutManager gets updated with it automatically so there is no need to manually update it.

interface SectionAdapter {
    List<Integer> getSectionStartPositions();
}

The LayoutManager would pull the data from this just once for each adapter change. It would then keep it up to date according to your notify data change calls.

Pros

  • Don't need to mark up any items.
  • No performance loss.
  • Can switch to this method during runtime with an adapter change.

Cons

  • Still have to manually generate section first positions.

2.b Status quo

The current situation where you have to update and notify for the current item and any later if you are removing or adding items.


Now, I am thinking of implementing all three of these suggested changes. This means you would start with using 1.a or 1.b, and if you have performance problems, consider using 2.a.

If you have any ideas, or an opinion, please comment.

Initialization thoughts.

I'd like to discuss the initialization process. Right now, the initialization code for SuperSLiM is a bit verbose:

layoutManager = new LayoutManager();
headerManager = new LinearSectionLayoutManager(layoutManager);
layoutManager.registerSectionLayoutManager(0, headerManager);
gridManager = new GridSectionLayoutManager(layoutManager, getActivity());
gridManager.setNumColumns(3);
layoutManager.registerSectionLayoutManager(1, gridManager);
recyclerView.setLayoutManager(layoutManager);

We currently have to initialize the all SLM's (including the default SLM's) ourselves, keep track of the index and correctly match these in our view binding/xml.

I would love to be able to do something like:

layoutManager = LayoutManager.enableLinearSLM().enableGridSLM(context, 3).addCustomSLM(new MySLM()).build()
recyclerView.setLayoutManager(layoutManager);

We could then use some sort of tag so then

final LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) holder.itemView.getLayoutParams();
lp.sectionManager = 0

would become something like

lp.setSLM(LinearSLM.tag)

I'm not sure how this would work via XML, but this shows exactly what SLM is being used without having to switch from your adapter to recyclerview implementation to match up ids.

Crashes when there is no element or one element

I love this library and the ability to switch from 3 elements per row to 1 element dynamically.
However, when there is zero elements or no elements in the array adapter I get a nullpointerexception:

java.lang.NullPointerException: Attempt to invoke virtual method
'android.view.ViewGroup$LayoutParams android.view.View.getLayoutParams()'
on a null object reference

Is there any workaround for this or is it simply a bug?

onCreateViewHolder being called frequently and rapidly

I noticed this in the app I'm working on, and it seems to be an issue in the example app as well. When I add logging statements to onCreateViewHolder (for example, in the CountryNamesAdapter in the example), I can see the method being called extremely frequently. Even a very slight scrolling movement will trigger tons of calls - as if it's happening for every redraw. onBindViewHolder is called with the same frequency.

Since onCreateViewHolder is where the expensive operations (xml inflation, findViewById, etc) are supposed to live, this seems like a big performance hit.

TextView measurement error after rebinding ViewHolder.

Sometimes view measurement doesn't update.

bugged measurement

               Fetched  D  position 82
                        D  82 was cached true
                        D  height 161
           measurement  D  params height -2
                        D  height 161

Correct measurement

               Fetched  D  position 82
                        D  82 was cached true
                        D  height 161
           measurement  D  params height -2
                        D  height 218

Maybe related to #55.


Further investigation reveals sometimes the views are just not being measured, though the call through recycler view is being made. There must be some residual state stopping measurement. What can stop measurement?

IndexOutOfBoundsException after restoring instance state

In my app, I was getting consistent crashes after rotating my device, due to an IndexOutOfBoundsException. The culprit seems to be LayoutManger's onRestoreInstanceState(), which does this: mRequestPosition = ((SavedState) state).anchorPosition.

In the case of rotating the device, my app rebuilds the cursor that backs the adapter peace-meal and calls notifyDataSetChanged() - but that happens after onRestoreInstanceState is called, so the max index ends up often being less than mRequestPosition.

The workaround of course is to not do that - so I'm being careful to wait until the adapter's state is fully restored before notifyDataSetChanged() is called - but I feel like SuperSLiM still probably shouldn't throw an IndexOutOfBoundsException in this case - though I'm not sure what the proper behavior should be (maybe mRequestPosition should be the maximum possible index if it ends up in this state?)

java.lang.IndexOutOfBoundsException: Invalid item position 46(46). Item count:45
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3345)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
at com.tonicartos.superslim.LayoutState.getView(LayoutState.java:66)
at com.tonicartos.superslim.SectionData.(SectionData.java:38)
at com.tonicartos.superslim.LayoutManager.determineAnchorPosition(LayoutManager.java:532)
at com.tonicartos.superslim.LayoutManager.onLayoutChildren(LayoutManager.java:182)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1988)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
at android.view.View.layout(View.java:15596)
at android.view.ViewGroup.layout(ViewGroup.java:4966)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
at android.widget.FrameLayout.onLayout(FrameLayout.java:508)

Always test first position.

Remove params.getFirstPosition(), and refactor params.getTestedFirstPosition() to params.getFirstPosition().

findFirstVisibleItemPosition() was not found in LayoutManager

Sir.

I want to implement "Load More" via SuperSLiM

like this:

mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);

    visibleItemCount = mRecyclerView.getChildCount();
    totalItemCount = mLayoutManager.getItemCount();
    firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

    if (loading) {
        if (totalItemCount > previousTotal) {
            loading = false;
            previousTotal = totalItemCount;
        }
    }
    if (!loading && (totalItemCount - visibleItemCount) 
        <= (firstVisibleItem + visibleThreshold)) {
        // End has been reached

        Log.i("...", "end called");

        // Do something

        loading = true;
    }
}});

but there is no the method "mLayoutManager.findFirstVisibleItemPosition()",

How can I get the "firstVisibleItem" to implements "Load More",

or are there other ways to resovle my question?

Thank you~

Nested Sticky Headers

Is it possible to have a second header stick below another header?

Double Sticky
)

I'd like the white sections (above each square image) to stick below the sticky navigation bar, and have the image scroll under. Is this currently possible?

v0.3 is broken. Use v0.2.4 or v0.4.0 snapshot.

Updated

0.4.0-SNAPSHOT available.

repositories {
    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
dependencies {
    compile 'com.tonicartos:superslim:0.4.0-SNAPSHOT'
}

I know this and I am working on fixing it ASAP. For now I recommend using v0.2.4.

Getting Started - Documentation bug

"It is important to note that setting the layout id and first position of each section is required"
Should be something like
"It is important to note that setting the section manager and first position of each section is required"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.