Latex inline parsing WIP
This commit is contained in:
		
							parent
							
								
									a298016ac2
								
							
						
					
					
						commit
						d78b278b86
					
				@ -1,5 +1,6 @@
 | 
			
		||||
package io.noties.markwon.ext.latex;
 | 
			
		||||
 | 
			
		||||
import org.commonmark.internal.util.Parsing;
 | 
			
		||||
import org.commonmark.node.Block;
 | 
			
		||||
import org.commonmark.parser.block.AbstractBlockParser;
 | 
			
		||||
import org.commonmark.parser.block.AbstractBlockParserFactory;
 | 
			
		||||
@ -60,18 +61,30 @@ public class JLatexMathBlockParser extends AbstractBlockParser {
 | 
			
		||||
        @Override
 | 
			
		||||
        public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
 | 
			
		||||
 | 
			
		||||
            // ^\s{0,3}\$\$\s*$ as a regex to star the block
 | 
			
		||||
            final int indent = state.getIndent();
 | 
			
		||||
 | 
			
		||||
            final CharSequence line = state.getLine();
 | 
			
		||||
            final int length = line != null
 | 
			
		||||
                    ? line.length()
 | 
			
		||||
                    : 0;
 | 
			
		||||
            // check if it's an indented code block
 | 
			
		||||
            if (indent < Parsing.CODE_BLOCK_INDENT) {
 | 
			
		||||
                final int nextNonSpaceIndex = state.getNextNonSpaceIndex();
 | 
			
		||||
                final CharSequence line = state.getLine();
 | 
			
		||||
                final int length = line.length();
 | 
			
		||||
                // we are looking for 2 `$$` subsequent signs
 | 
			
		||||
                // and immediate new-line or arbitrary number of white spaces (we check for the first one)
 | 
			
		||||
                // so, nextNonSpaceIndex + 2 >= length and both symbols are `$`s
 | 
			
		||||
                final int diff = length - (nextNonSpaceIndex + 2);
 | 
			
		||||
                if (diff >= 0) {
 | 
			
		||||
                    // check for both `$`
 | 
			
		||||
                    if (line.charAt(nextNonSpaceIndex) == '$'
 | 
			
		||||
                            && line.charAt(nextNonSpaceIndex + 1) == '$') {
 | 
			
		||||
 | 
			
		||||
            if (length > 1) {
 | 
			
		||||
                if ('$' == line.charAt(0)
 | 
			
		||||
                        && '$' == line.charAt(1)) {
 | 
			
		||||
                    return BlockStart.of(new JLatexMathBlockParser())
 | 
			
		||||
                            .atIndex(state.getIndex() + 2);
 | 
			
		||||
                        if (diff > 0) {
 | 
			
		||||
                            if (!Character.isWhitespace(line.charAt(nextNonSpaceIndex + 2))) {
 | 
			
		||||
                                return BlockStart.none();
 | 
			
		||||
                            }
 | 
			
		||||
                            // consume all until new-line or first not-white-space char
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
package io.noties.markwon.ext.latex;
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
 | 
			
		||||
import org.commonmark.node.Node;
 | 
			
		||||
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
import io.noties.markwon.inlineparser.InlineProcessor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @since 4.3.0-SNAPSHOT
 | 
			
		||||
 */
 | 
			
		||||
public class JLatexMathInlineProcessor extends InlineProcessor {
 | 
			
		||||
 | 
			
		||||
    private static final Pattern RE = Pattern.compile("(\\${2})([\\s\\S]+?)\\1");
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public char specialCharacter() {
 | 
			
		||||
        return '$';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Node parse() {
 | 
			
		||||
 | 
			
		||||
        final String latex = match(RE);
 | 
			
		||||
        if (latex == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final JLatexMathNode node = new JLatexMathNode();
 | 
			
		||||
        node.latex(latex.substring(2, latex.length() - 2));
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,9 +3,9 @@ package io.noties.markwon.ext.latex;
 | 
			
		||||
import org.commonmark.node.CustomNode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @since 4.2.1-SNAPSHOT
 | 
			
		||||
 * @since 4.3.0-SNAPSHOT
 | 
			
		||||
 */
 | 
			
		||||
public class JLatexMathInline extends CustomNode {
 | 
			
		||||
public class JLatexMathNode extends CustomNode {
 | 
			
		||||
 | 
			
		||||
    private String latex;
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,6 @@ import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.annotation.Px;
 | 
			
		||||
import androidx.annotation.VisibleForTesting;
 | 
			
		||||
 | 
			
		||||
import org.commonmark.node.Node;
 | 
			
		||||
import org.commonmark.parser.InlineParserFactory;
 | 
			
		||||
import org.commonmark.parser.Parser;
 | 
			
		||||
 | 
			
		||||
@ -33,7 +32,6 @@ import io.noties.markwon.image.AsyncDrawableScheduler;
 | 
			
		||||
import io.noties.markwon.image.AsyncDrawableSpan;
 | 
			
		||||
import io.noties.markwon.image.ImageSizeResolver;
 | 
			
		||||
import io.noties.markwon.image.ImageSizeResolverDef;
 | 
			
		||||
import io.noties.markwon.inlineparser.InlineProcessor;
 | 
			
		||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
 | 
			
		||||
import ru.noties.jlatexmath.JLatexMathDrawable;
 | 
			
		||||
 | 
			
		||||
@ -132,8 +130,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 | 
			
		||||
        // if it's $$\\dhdsfjh$$ -> inline
 | 
			
		||||
 | 
			
		||||
//        builder.customBlockParserFactory(new JLatexMathBlockParser.Factory());
 | 
			
		||||
        final InlineParserFactory factory = MarkwonInlineParser.factoryBuilderNoDefaults()
 | 
			
		||||
                .addInlineProcessor(new LatexInlineProcessor())
 | 
			
		||||
        final InlineParserFactory factory = MarkwonInlineParser.factoryBuilder()
 | 
			
		||||
                .addInlineProcessor(new JLatexMathInlineProcessor())
 | 
			
		||||
                .build();
 | 
			
		||||
        builder.inlineParserFactory(factory);
 | 
			
		||||
    }
 | 
			
		||||
@ -155,6 +153,33 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 | 
			
		||||
 | 
			
		||||
                final MarkwonConfiguration configuration = visitor.configuration();
 | 
			
		||||
 | 
			
		||||
                final AsyncDrawableSpan span = new AsyncDrawableSpan(
 | 
			
		||||
                        configuration.theme(),
 | 
			
		||||
                        new AsyncDrawable(
 | 
			
		||||
                                latex,
 | 
			
		||||
                                jLatextAsyncDrawableLoader,
 | 
			
		||||
                                jLatexImageSizeResolver,
 | 
			
		||||
                                null),
 | 
			
		||||
                        AsyncDrawableSpan.ALIGN_CENTER,
 | 
			
		||||
                        false);
 | 
			
		||||
 | 
			
		||||
                visitor.setSpans(length, span);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        builder.on(JLatexMathNode.class, new MarkwonVisitor.NodeVisitor<JLatexMathNode>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void visit(@NonNull MarkwonVisitor visitor, @NonNull JLatexMathNode jLatexMathNode) {
 | 
			
		||||
                final String latex = jLatexMathNode.latex();
 | 
			
		||||
 | 
			
		||||
                final int length = visitor.length();
 | 
			
		||||
 | 
			
		||||
                // @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
 | 
			
		||||
                // because Android will draw formula for each line of text, thus
 | 
			
		||||
                // leading to formula duplicated (drawn on each line of text)
 | 
			
		||||
                visitor.builder().append(prepareLatexTextPlaceholder(latex));
 | 
			
		||||
 | 
			
		||||
                final MarkwonConfiguration configuration = visitor.configuration();
 | 
			
		||||
 | 
			
		||||
                final AsyncDrawableSpan span = new AsyncDrawableSpan(
 | 
			
		||||
                        configuration.theme(),
 | 
			
		||||
                        new AsyncDrawable(
 | 
			
		||||
@ -170,76 +195,76 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class LatexInlineProcessor extends InlineProcessor {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public char specialCharacter() {
 | 
			
		||||
            return '$';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Nullable
 | 
			
		||||
        @Override
 | 
			
		||||
        protected Node parse() {
 | 
			
		||||
 | 
			
		||||
            final int start = index;
 | 
			
		||||
 | 
			
		||||
            index += 1;
 | 
			
		||||
            if (peek() != '$') {
 | 
			
		||||
                index = start;
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // must be not $
 | 
			
		||||
            index += 1;
 | 
			
		||||
            if (peek() == '$') {
 | 
			
		||||
                return text("$");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // find next '$$', but not broken with 2(or more) new lines
 | 
			
		||||
 | 
			
		||||
            boolean dollar = false;
 | 
			
		||||
            boolean newLine = false;
 | 
			
		||||
            boolean found = false;
 | 
			
		||||
 | 
			
		||||
            index += 1;
 | 
			
		||||
            final int length = input.length();
 | 
			
		||||
 | 
			
		||||
            while (index < length) {
 | 
			
		||||
                final char c = peek();
 | 
			
		||||
                if (c == '\n') {
 | 
			
		||||
                    if (newLine) {
 | 
			
		||||
                        // second new line
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    newLine = true;
 | 
			
		||||
                    dollar = false; // cannot be on another line
 | 
			
		||||
                } else {
 | 
			
		||||
                    newLine = false;
 | 
			
		||||
                    if (c == '$') {
 | 
			
		||||
                        if (dollar) {
 | 
			
		||||
                            found = true;
 | 
			
		||||
                            // advance
 | 
			
		||||
                            index += 1;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        dollar = true;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        dollar = false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                index += 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (found) {
 | 
			
		||||
                final JLatexMathBlock block = new JLatexMathBlock();
 | 
			
		||||
                block.latex(input.substring(start + 2, index - 2));
 | 
			
		||||
                index += 1;
 | 
			
		||||
                return block;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
//    private static class LatexInlineProcessor extends InlineProcessor {
 | 
			
		||||
//
 | 
			
		||||
//        @Override
 | 
			
		||||
//        public char specialCharacter() {
 | 
			
		||||
//            return '$';
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        @Nullable
 | 
			
		||||
//        @Override
 | 
			
		||||
//        protected Node parse() {
 | 
			
		||||
//
 | 
			
		||||
//            final int start = index;
 | 
			
		||||
//
 | 
			
		||||
//            index += 1;
 | 
			
		||||
//            if (peek() != '$') {
 | 
			
		||||
//                index = start;
 | 
			
		||||
//                return null;
 | 
			
		||||
//            }
 | 
			
		||||
//
 | 
			
		||||
//            // must be not $
 | 
			
		||||
//            index += 1;
 | 
			
		||||
//            if (peek() == '$') {
 | 
			
		||||
//                return text("$");
 | 
			
		||||
//            }
 | 
			
		||||
//
 | 
			
		||||
//            // find next '$$', but not broken with 2(or more) new lines
 | 
			
		||||
//
 | 
			
		||||
//            boolean dollar = false;
 | 
			
		||||
//            boolean newLine = false;
 | 
			
		||||
//            boolean found = false;
 | 
			
		||||
//
 | 
			
		||||
//            index += 1;
 | 
			
		||||
//            final int length = input.length();
 | 
			
		||||
//
 | 
			
		||||
//            while (index < length) {
 | 
			
		||||
//                final char c = peek();
 | 
			
		||||
//                if (c == '\n') {
 | 
			
		||||
//                    if (newLine) {
 | 
			
		||||
//                        // second new line
 | 
			
		||||
//                        break;
 | 
			
		||||
//                    }
 | 
			
		||||
//                    newLine = true;
 | 
			
		||||
//                    dollar = false; // cannot be on another line
 | 
			
		||||
//                } else {
 | 
			
		||||
//                    newLine = false;
 | 
			
		||||
//                    if (c == '$') {
 | 
			
		||||
//                        if (dollar) {
 | 
			
		||||
//                            found = true;
 | 
			
		||||
//                            // advance
 | 
			
		||||
//                            index += 1;
 | 
			
		||||
//                            break;
 | 
			
		||||
//                        }
 | 
			
		||||
//                        dollar = true;
 | 
			
		||||
//                    } else {
 | 
			
		||||
//                        dollar = false;
 | 
			
		||||
//                    }
 | 
			
		||||
//                }
 | 
			
		||||
//                index += 1;
 | 
			
		||||
//            }
 | 
			
		||||
//
 | 
			
		||||
//            if (found) {
 | 
			
		||||
//                final JLatexMathBlock block = new JLatexMathBlock();
 | 
			
		||||
//                block.latex(input.substring(start + 2, index - 2));
 | 
			
		||||
//                index += 1;
 | 
			
		||||
//                return block;
 | 
			
		||||
//            }
 | 
			
		||||
//
 | 
			
		||||
//            return null;
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
 | 
			
		||||
@ -383,7 +408,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 | 
			
		||||
                                        .textSize(config.textSize)
 | 
			
		||||
                                        .background(backgroundProvider != null ? backgroundProvider.provide() : null)
 | 
			
		||||
                                        .align(config.align)
 | 
			
		||||
                                        .fitCanvas(config.fitCanvas)
 | 
			
		||||
                                        .fitCanvas(false /*config.fitCanvas*/)
 | 
			
		||||
                                        .padding(
 | 
			
		||||
                                                config.paddingHorizontal,
 | 
			
		||||
                                                config.paddingVertical,
 | 
			
		||||
 | 
			
		||||
@ -24,26 +24,26 @@ public class LatexActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
        final TextView textView = findViewById(R.id.text_view);
 | 
			
		||||
 | 
			
		||||
        String latex = "\\begin{array}{l}";
 | 
			
		||||
        latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
 | 
			
		||||
        latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
 | 
			
		||||
        latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
 | 
			
		||||
        latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
 | 
			
		||||
        latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty  {\\sum\\limits_{m = 1}^{2^n  - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
 | 
			
		||||
        latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
 | 
			
		||||
        latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
 | 
			
		||||
        latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
 | 
			
		||||
        latex += "\\end{array}";
 | 
			
		||||
//        String latex = "\\begin{array}{l}";
 | 
			
		||||
//        latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
 | 
			
		||||
//        latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
 | 
			
		||||
//        latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
 | 
			
		||||
//        latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
 | 
			
		||||
//        latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty  {\\sum\\limits_{m = 1}^{2^n  - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
 | 
			
		||||
//        latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
 | 
			
		||||
//        latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
 | 
			
		||||
//        latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
 | 
			
		||||
//        latex += "\\end{array}";
 | 
			
		||||
 | 
			
		||||
//        String latex = "\\text{A long division \\longdiv{12345}{13}";
 | 
			
		||||
//                String latex = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
 | 
			
		||||
        String latex = "\\text{A long division \\longdiv{12345}{13}";
 | 
			
		||||
//        String latex = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
 | 
			
		||||
 | 
			
		||||
//        String latex = "\\begin{array}{cc}";
 | 
			
		||||
//        latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
 | 
			
		||||
//        latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
 | 
			
		||||
//        latex += "\\end{array}";
 | 
			
		||||
 | 
			
		||||
        final String markdown = "# Example of LaTeX\n\n$$"
 | 
			
		||||
        final String markdown = "# Example of LaTeX\n\nhello there: $$"
 | 
			
		||||
                + latex + "$$\n\n something like **this**";
 | 
			
		||||
 | 
			
		||||
        final Markwon markwon = Markwon.builder(this)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user