cache;
+
+    SampleItemView(@NonNull Markwon markwon) {
+        this.markwon = markwon;
+        this.factory = new NoCopySpannableFactory();
+        this.cache = new EnumMap<>(SampleItem.class);
+    }
+
+    @NonNull
+    @Override
+    public SampleHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
+
+        final SampleHolder holder = new SampleHolder(inflater.inflate(
+                R.layout.adapt_sample_item,
+                parent,
+                false));
+
+        // set Spannable.Factory so when TextView will receive a new content
+        // it won't create new Spannable and copy all the spans but instead
+        // re-use existing Spannable thus improving performance
+        holder.textView.setSpannableFactory(factory);
+
+        return holder;
+    }
+
+    @Override
+    public void bindHolder(@NonNull SampleHolder holder, @NonNull SampleItem item) {
+
+        // retrieve an item from cache or create new one
+        // simple lazy loading pattern (cache on first call then re-use)
+        Spanned spanned = cache.get(item);
+        if (spanned == null) {
+            spanned = markwon.toMarkdown(context(holder).getString(item.textResId()));
+            cache.put(item, spanned);
+        }
+
+        holder.textView.setText(spanned);
+    }
+
+    static class SampleHolder extends Holder {
+
+        final TextView textView;
+
+        SampleHolder(@NonNull View view) {
+            super(view);
+
+            this.textView = requireView(R.id.text);
+        }
+    }
+
+    private static class NoCopySpannableFactory extends Spannable.Factory {
+        @Override
+        public Spannable newSpannable(CharSequence source) {
+            return source instanceof Spannable
+                    ? (Spannable) source
+                    : new SpannableString(source);
+        }
+    }
+}
diff --git a/sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java b/sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java
new file mode 100644
index 00000000..79687390
--- /dev/null
+++ b/sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java
@@ -0,0 +1,208 @@
+package ru.noties.markwon.sample.core;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.commonmark.node.Heading;
+import org.commonmark.node.Node;
+import org.commonmark.node.Paragraph;
+
+import ru.noties.markwon.AbstractMarkwonPlugin;
+import ru.noties.markwon.Markwon;
+import ru.noties.markwon.MarkwonPlugin;
+import ru.noties.markwon.MarkwonSpansFactory;
+import ru.noties.markwon.MarkwonVisitor;
+import ru.noties.markwon.core.CorePlugin;
+import ru.noties.markwon.core.MarkwonTheme;
+
+public class CoreActivity extends Activity {
+
+    private TextView textView;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        textView = new TextView(this);
+        setContentView(textView);
+
+        step_1();
+
+        step_2();
+
+        step_3();
+
+        step_4();
+
+        step_5();
+
+        step_6();
+
+        step_7();
+    }
+
+    /**
+     * Create a simple instance of Markwon with only Core plugin registered
+     * this will handle all _natively_ supported by commonmark-java nodes:
+     * 
+     * - StrongEmphasis
 
+     * - Emphasis
 
+     * - BlockQuote
 
+     * - Code
 
+     * - FencedCodeBlock
 
+     * - IndentedCodeBlock
 
+     * - ListItem (bullet-list and ordered list
 
+     * - Heading
 
+     * - Link
 
+     * - ThematicBreak
 
+     * - Paragraph (please note that there is no default span for a paragraph registered)
 
+     * 
+     * 
+     * and basic core functionality:
+     * 
+     * - Append text
 
+     * - Insert new lines (soft and hard breaks)
 
+     * 
+     */
+    private void step_1() {
+
+        // short call
+        final Markwon markwon = Markwon.create(this);
+
+        // this is the same as calling
+        final Markwon markwon2 = Markwon.builder(this)
+                .usePlugin(CorePlugin.create())
+                .build();
+    }
+
+    /**
+     * To simply apply raw (non-parsed) markdown call {@link Markwon#setMarkdown(TextView, String)}
+     */
+    private void step_2() {
+
+        // this is raw markdown
+        final String markdown = "Hello **markdown**!";
+
+        final Markwon markwon = Markwon.create(this);
+
+        // this will parse raw markdown and set parsed content to specified TextView
+        markwon.setMarkdown(textView, markdown);
+    }
+
+    /**
+     * To apply markdown in a different context (other than textView) use {@link Markwon#toMarkdown(String)}
+     * 
+     * Please note that some features won't work unless they are used in a TextView context. For example
+     * there might be misplaced ordered lists (ordered list must have TextPaint in order to properly measure
+     * its number). But also images and tables (they belong to independent modules now). Images and tables
+     * are using some work-arounds in order to be displayed in relatively limited context without proper way
+     * of invalidation. But if a Toast for example is created with a custom view
+     * ({@code new Toast(this).setView(...) }) and has access to a TextView everything should work.
+     */
+    private void step_3() {
+
+        final String markdown = "*Toast* __here__!\n\n> And a quote!";
+
+        final Markwon markwon = Markwon.create(this);
+
+        final Spanned spanned = markwon.toMarkdown(markdown);
+
+        Toast.makeText(this, spanned, Toast.LENGTH_LONG).show();
+    }
+
+    /**
+     * To apply already parsed markdown use {@link Markwon#setParsedMarkdown(TextView, Spanned)}
+     */
+    private void step_4() {
+
+        final String markdown = "This **is** pre-parsed [markdown](#)";
+
+        final Markwon markwon = Markwon.create(this);
+
+        // parse markdown to obtain a Node
+        final Node node = markwon.parse(markdown);
+
+        // create a spanned content from parsed node
+        final Spanned spanned = markwon.render(node);
+
+        // apply parsed markdown
+        markwon.setParsedMarkdown(textView, spanned);
+    }
+
+    /**
+     * In order to apply paragraph spans a custom plugin should be created (CorePlugin will take care
+     * of everything else).
+     * 
+     * Please note that when a plugin is registered and it depends on CorePlugin, there is no
+     * need to explicitly specify it. By default all plugins that extend AbstractMarkwonPlugin do declare
+     * it\'s dependency on CorePlugin ({@link MarkwonPlugin#priority()}).
+     * 
+     * Order in which plugins are specified to the builder is of little importance as long as each
+     * plugin clearly states what dependencies it has
+     */
+    private void step_5() {
+
+        final String markdown = "# Hello!\n\nA paragraph?\n\nIt should be!";
+
+        final Markwon markwon = Markwon.builder(this)
+                .usePlugin(new AbstractMarkwonPlugin() {
+                    @Override
+                    public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
+                        builder.setFactory(Paragraph.class, (configuration, props) ->
+                                new ForegroundColorSpan(Color.GREEN));
+                    }
+                })
+                .build();
+
+        markwon.setMarkdown(textView, markdown);
+    }
+
+    /**
+     * To disable some nodes from rendering another custom plugin can be used
+     */
+    private void step_6() {
+
+        final String markdown = "# Heading 1\n\n## Heading 2\n\n**other** content [here](#)";
+
+        final Markwon markwon = Markwon.builder(this)
+                .usePlugin(new AbstractMarkwonPlugin() {
+                    @Override
+                    public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
+                        // for example to disable rendering of heading:
+                        // try commenting this out to see that otherwise headings will be rendered
+                        builder.on(Heading.class, null);
+                    }
+                })
+                .build();
+
+        markwon.setMarkdown(textView, markdown);
+    }
+
+    /**
+     * To customize core theme plugins can be used again
+     */
+    private void step_7() {
+
+        final String markdown = "`A code` that is rendered differently\n\n```\nHello!\n```";
+
+        final Markwon markwon = Markwon.builder(this)
+                .usePlugin(new AbstractMarkwonPlugin() {
+                    @Override
+                    public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
+                        builder
+                                .codeBackgroundColor(Color.BLACK)
+                                .codeTextColor(Color.RED);
+                    }
+                })
+                .build();
+
+        markwon.setMarkdown(textView, markdown);
+    }
+}
diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java
new file mode 100644
index 00000000..1b35c0c7
--- /dev/null
+++ b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java
@@ -0,0 +1,6 @@
+package ru.noties.markwon.sample.customextension;
+
+import android.app.Activity;
+
+public class CustomExtensionActivity extends Activity {
+}
diff --git a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java
new file mode 100644
index 00000000..179113ea
--- /dev/null
+++ b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java
@@ -0,0 +1,15 @@
+package ru.noties.markwon.sample.latex;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+public class LatexActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+
+    }
+}
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..26bc9906
--- /dev/null
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,15 @@
+
+
+
+    
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/layout/adapt_sample_item.xml b/sample/src/main/res/layout/adapt_sample_item.xml
new file mode 100644
index 00000000..3dfe4e21
--- /dev/null
+++ b/sample/src/main/res/layout/adapt_sample_item.xml
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/values-v21/styles.xml b/sample/src/main/res/values-v21/styles.xml
new file mode 100644
index 00000000..191be162
--- /dev/null
+++ b/sample/src/main/res/values-v21/styles.xml
@@ -0,0 +1,6 @@
+
+
+
+    
+
+
diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml
new file mode 100644
index 00000000..230c3557
--- /dev/null
+++ b/sample/src/main/res/values/strings-samples.xml
@@ -0,0 +1,10 @@
+
+
+
+    
+
+    # \# Core\n\nSimple usage example
+    # \# LaTeX\n\nShows how to display a **LaTeX** formula in a Markwon powered application
+    # \# Custom extension\n\nShows how to create a custom extension to display an icon referenced in markdown as `@ic-android-black-24`
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
index 9785e0c9..76d400a3 100644
--- a/sample/src/main/res/values/styles.xml
+++ b/sample/src/main/res/values/styles.xml
@@ -1,8 +1,7 @@
 
 
-    
-    
+    
+
+    
 
 
diff --git a/sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java b/sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java
new file mode 100644
index 00000000..dec6b07e
--- /dev/null
+++ b/sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java
@@ -0,0 +1,25 @@
+package ru.noties.markwon.sample;
+
+import android.content.Context;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class MainActivityTest {
+
+    @Test
+    public void all_sample_items_have_activity_associated() {
+        final Context context = RuntimeEnvironment.application;
+        for (SampleItem item : SampleItem.values()) {
+            // we assert as not null, but in case of an error this method should throw
+            assertNotNull(MainActivity.sampleItemIntent(context, item));
+        }
+    }
+}
\ No newline at end of file