text:
package org.b3log.symphony.processor;

import com.qiniu.util.Auth;
import jodd.util.Base64;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.ioc.Inject;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
import org.b3log.latke.model.User;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.After;
import org.b3log.latke.servlet.annotation.Before;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.AbstractFreeMarkerRenderer;
import org.b3log.latke.util.Paginator;
import org.b3log.latke.util.Requests;
import org.b3log.latke.util.Stopwatchs;
import org.b3log.latke.util.Strings;
import org.b3log.symphony.cache.DomainCache;
import org.b3log.symphony.model.*;
import org.b3log.symphony.processor.advice.*;
import org.b3log.symphony.processor.advice.stopwatch.StopwatchEndAdvice;
import org.b3log.symphony.processor.advice.stopwatch.StopwatchStartAdvice;
import org.b3log.symphony.processor.advice.validate.ArticleAddValidation;
import org.b3log.symphony.processor.advice.validate.ArticleUpdateValidation;
import org.b3log.symphony.processor.advice.validate.UserRegisterValidation;
import org.b3log.symphony.service.*;
import org.b3log.symphony.util.*;
import org.json.JSONObject;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.*;
import java.util.List;

/**
 * Article processor.
 *

 *
Shows an article (/article/{articleId}), GET

 *
Shows article pre adding form page (/pre-post), GET

 *
Shows article adding form page (/post), GET

 *
Adds an article (/post) locally, POST

 *
Shows an article updating form page (/update) locally, GET

 *
Updates an article (/article/{id}) locally, PUT

 *
Markdowns text (/markdown), POST

 *
Rewards an article (/article/reward), POST

 *
Gets an article preview content (/article/{articleId}/preview), GET

 *
Sticks an article (/article/stick), POST

 *
Gets an article's revisions (/article/{id}/revisions), GET

 *
Gets article image (/article/{articleId}/image), GET

 *
Checks article title (/article/check-title), POST

 *
Removes an article (/article/{id}/remove), POST

 *

 *

 * The 'locally' means user post an article on Symphony directly rather than receiving an article from
 * externally (for example Rhythm).
 *

 *
 * @author Liang Ding
 * @author Zephyr
 * @version 1.27.2.5, Aug 10, 2018
 * @since 0.2.0
 */
@RequestProcessor
public class ArticleProcessor {

    /**
     * Logger.
     */
    private static final Logger LOGGER = Logger.getLogger(ArticleProcessor.class);

    /**
     * Revision query service.
     */
    @Inject
    private RevisionQueryService revisionQueryService;

    /**
     * Short link query service.
     */
    @Inject
    private ShortLinkQueryService shortLinkQueryService;

    /**
     * Article management service.
     */
    @Inject
    private ArticleMgmtService articleMgmtService;

    /**
     * Article query service.
     */
    @Inject
    private ArticleQueryService articleQueryService;

    /**
     * Comment query service.
     */
    @Inject
    private CommentQueryService commentQueryService;

    /**
     * User query service.
     */
    @Inject
    private UserQueryService userQueryService;

    /**
     * User management service.
     */
    @Inject
    private UserMgmtService userMgmtService;

    /**
     * Language service.
     */
    @Inject
    private LangPropsService langPropsService;

    /**
     * Follow query service.
     */
    @Inject
    private FollowQueryService followQueryService;

    /**
     * Reward query service.
     */
    @Inject
    private RewardQueryService rewardQueryService;

    /**
     * Vote query service.
     */
    @Inject
    private VoteQueryService voteQueryService;

    /**
     * Liveness management service.
     */
    @Inject
    private LivenessMgmtService livenessMgmtService;

    /**
     * Referral management service.
     */
    @Inject
    private ReferralMgmtService referralMgmtService;

    /**
     * Character query service.
     */
    @Inject
    private CharacterQueryService characterQueryService;

    /**
     * Domain query service.
     */
    @Inject
    private DomainQueryService domainQueryService;

    /**
     * Domain cache.
     */
    @Inject
    private DomainCache domainCache;

    /**
     * Data model service.
     */
    @Inject
    private DataModelService dataModelService;

    /**
     * Removes an article.
     *
     * @param context  the specified context
     * @param request  the specified request
     * @param response the specified response
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/{id}/remove", method = HTTPRequestMethod.POST)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class, PermissionCheck.class})
    @After(adviceClass = {StopwatchEndAdvice.class})
    public void removeArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response,
                              final String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        final String currentUserId = currentUser.optString(Keys.OBJECT_ID);
        final JSONObject article = articleQueryService.getArticle(id);
        if (null == article) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);
        if (!authorId.equals(currentUserId)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        context.renderJSON();
        try {
            articleMgmtService.removeArticle(id);

            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.SUCC);
            context.renderJSONValue(Article.ARTICLE_T_ID, id);
        } catch (final ServiceException e) {
            final String msg = e.getMessage();

            context.renderMsg(msg);
            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.ERR);
        }
    }

    /**
     * Checks article title.
     *
     * @param context the specified context
     * @param request the specified request
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/check-title", method = HTTPRequestMethod.POST)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class})
    @After(adviceClass = {StopwatchEndAdvice.class})
    public void checkArticleTitle(final HTTPRequestContext context, final HttpServletRequest request) throws Exception {
        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        final String currentUserId = currentUser.optString(Keys.OBJECT_ID);
        final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse());
        String title = requestJSONObject.optString(Article.ARTICLE_TITLE);
        title = StringUtils.trim(title);
        String id = requestJSONObject.optString(Article.ARTICLE_T_ID);

        final JSONObject article = articleQueryService.getArticleByTitle(title);
        if (null == article) {
            context.renderJSON(true);

            return;
        }

        if (StringUtils.isBlank(id)) { // Add
            final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);

            String msg;
            if (authorId.equals(currentUserId)) {
                msg = langPropsService.get("duplicatedArticleTitleSelfLabel");
                msg = msg.replace("{article}", "" + title + "");
            } else {
                final JSONObject author = userQueryService.getUser(authorId);
                final String userName = author.optString(User.USER_NAME);

                msg = langPropsService.get("duplicatedArticleTitleLabel");
                msg = msg.replace("{user}", "" + userName + "");
                msg = msg.replace("{article}", "" + title + "");
            }

            final JSONObject ret = new JSONObject();
            ret.put(Keys.STATUS_CODE, false);
            ret.put(Keys.MSG, msg);

            context.renderJSON(ret);
        } else { // Update
            final JSONObject oldArticle = articleQueryService.getArticle(id);
            if (oldArticle.optString(Article.ARTICLE_TITLE).equals(title)) {
                context.renderJSON(true);

                return;
            }

            final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);

            String msg;
            if (authorId.equals(currentUserId)) {
                msg = langPropsService.get("duplicatedArticleTitleSelfLabel");
                msg = msg.replace("{article}", "" + title + "");
            } else {
                final JSONObject author = userQueryService.getUser(authorId);
                final String userName = author.optString(User.USER_NAME);

                msg = langPropsService.get("duplicatedArticleTitleLabel");
                msg = msg.replace("{user}", "" + userName + "");
                msg = msg.replace("{article}", "" + title + "");
            }

            final JSONObject ret = new JSONObject();
            ret.put(Keys.STATUS_CODE, false);
            ret.put(Keys.MSG, msg);

            context.renderJSON(ret);
        }
    }

    /**
     * Gets article image.
     *
     * @param context   the specified context
     * @param articleId the specified article id
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/{articleId}/image", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class})
    @After(adviceClass = {StopwatchEndAdvice.class})
    public void getArticleImage(final HTTPRequestContext context, final String articleId) throws Exception {
        final JSONObject article = articleQueryService.getArticle(articleId);
        final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);

        final Set<JSONObject> characters = characterQueryService.getWrittenCharacters();
        final String articleContent = article.optString(Article.ARTICLE_CONTENT);

        final List<BufferedImage> images = new ArrayList<>();
        for (int i = 0; i < articleContent.length(); i++) {
            final String ch = articleContent.substring(i, i + 1);
            final JSONObject chRecord = org.b3log.symphony.model.Character.getCharacter(ch, characters);
            if (null == chRecord) {
                images.add(org.b3log.symphony.model.Character.createImage(ch));

                continue;
            }

            final String imgData = chRecord.optString(org.b3log.symphony.model.Character.CHARACTER_IMG);
            final byte[] data = Base64.decode(imgData.getBytes());
            final BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
            final BufferedImage newImage = new BufferedImage(50, 50, img.getType());
            final Graphics g = newImage.getGraphics();
            g.setClip(0, 0, 50, 50);
            g.fillRect(0, 0, 50, 50);
            g.drawImage(img, 0, 0, 50, 50, null);
            g.dispose();

            images.add(newImage);
        }

        final int rowCharacterCount = 30;
        final int rows = (int) Math.ceil((double) images.size() / (double) rowCharacterCount);

        final BufferedImage combined = new BufferedImage(30 * 50, rows * 50, Transparency.TRANSLUCENT);
        int row = 0;
        for (int i = 0; i < images.size(); i++) {
            final BufferedImage image = images.get(i);

            final Graphics g = combined.getGraphics();
            g.drawImage(image, (i % rowCharacterCount) * 50, row * 50, null);

            if (0 == (i + 1) % rowCharacterCount) {
                row++;
            }
        }

        ImageIO.write(combined, "PNG", new File("./hp.png"));

        String url = "";

        final JSONObject ret = new JSONObject();
        ret.put(Keys.STATUS_CODE, true);
        ret.put(Common.URL, url);

        context.renderJSON(ret);
    }

    /**
     * Gets an article's revisions.
     *
     * @param context the specified context
     * @param id      the specified article id
     */
    @RequestProcessing(value = "/article/{id}/revisions", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class, PermissionCheck.class})
    @After(adviceClass = {StopwatchEndAdvice.class})
    public void getArticleRevisions(final HTTPRequestContext context, final String id) {
        final List<JSONObject> revisions = revisionQueryService.getArticleRevisions(id);
        final JSONObject ret = new JSONObject();
        ret.put(Keys.STATUS_CODE, true);
        ret.put(Revision.REVISIONS, (Object) revisions);

        context.renderJSON(ret);
    }

    /**
     * Shows pre-add article.
     *
     * @param context  the specified context
     * @param request  the specified request
     * @param response the specified response
     */
    @RequestProcessing(value = "/pre-post", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class})
    @After(adviceClass = {CSRFToken.class, PermissionGrant.class, StopwatchEndAdvice.class})
    public void showPreAddArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
        final AbstractFreeMarkerRenderer renderer = new SkinRenderer(request);
        context.setRenderer(renderer);

        renderer.setTemplateName("home/pre-post.ftl");
        final Map<String, Object> dataModel = renderer.getDataModel();

        dataModel.put(Common.BROADCAST_POINT, Pointtransfer.TRANSFER_SUM_C_ADD_ARTICLE_BROADCAST);

        dataModelService.fillHeaderAndFooter(request, response, dataModel);
    }

    /**
     * Fills the domains with tags.
     *
     * @param dataModel the specified data model
     */
    private void fillDomainsWithTags(final Map<String, Object> dataModel) {
        final List<JSONObject> domains = domainQueryService.getAllDomains();
        dataModel.put(Common.ADD_ARTICLE_DOMAINS, domains);
        for (final JSONObject domain : domains) {
            final List<JSONObject> tags = domainQueryService.getTags(domain.optString(Keys.OBJECT_ID));

            domain.put(Domain.DOMAIN_T_TAGS, (Object) tags);
        }

        final JSONObject user = (JSONObject) dataModel.get(Common.CURRENT_USER);
        if (null == user) {
            return;
        }

        try {
            final JSONObject followingTagsResult = followQueryService.getFollowingTags(
                    user.optString(Keys.OBJECT_ID), 1, 28);
            final List<JSONObject> followingTags = (List<JSONObject>) followingTagsResult.opt(Keys.RESULTS);
            if (!followingTags.isEmpty()) {
                final JSONObject userWatched = new JSONObject();
                userWatched.put(Keys.OBJECT_ID, String.valueOf(System.currentTimeMillis()));
                userWatched.put(Domain.DOMAIN_TITLE, langPropsService.get("notificationFollowingLabel"));
                userWatched.put(Domain.DOMAIN_T_TAGS, (Object) followingTags);

                domains.add(0, userWatched);
            }
        } catch (final Exception e) {
            LOGGER.log(Level.ERROR, "Get user [name=" + user.optString(User.USER_NAME) + "] following tags failed", e);
        }
    }

    /**
     * Shows add article.
     *
     * @param context  the specified context
     * @param request  the specified request
     * @param response the specified response
     */
    @RequestProcessing(value = "/post", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class})
    @After(adviceClass = {CSRFToken.class, PermissionGrant.class, StopwatchEndAdvice.class})
    public void showAddArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
        final AbstractFreeMarkerRenderer renderer = new SkinRenderer(request);
        context.setRenderer(renderer);
        renderer.setTemplateName("home/post.ftl");
        final Map<String, Object> dataModel = renderer.getDataModel();

        // Qiniu file upload authenticate
        final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey"));
        final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket"));
        dataModel.put("qiniuUploadToken", uploadToken);
        dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain"));

        if (!Symphonys.getBoolean("qiniu.enabled")) {
            dataModel.put("qiniuUploadToken", "");
        }

        final long imgMaxSize = Symphonys.getLong("upload.img.maxSize");
        dataModel.put("imgMaxSize", imgMaxSize);
        final long fileMaxSize = Symphonys.getLong("upload.file.maxSize");
        dataModel.put("fileMaxSize", fileMaxSize);

        String tags = request.getParameter(Tag.TAGS);
        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);

        if (StringUtils.isBlank(tags)) {
            tags = "";

            dataModel.put(Tag.TAGS, tags);
        } else {
            tags = Tag.formatTags(tags);
            final String[] tagTitles = tags.split(",");

            final StringBuilder tagBuilder = new StringBuilder();
            for (final String title : tagTitles) {
                final String tagTitle = title.trim();

                if (StringUtils.isBlank(tagTitle)) {
                    continue;
                }

                if (Tag.containsWhiteListTags(tagTitle)) {
                    tagBuilder.append(tagTitle).append(",");

                    continue;
                }

                if (!Tag.TAG_TITLE_PATTERN.matcher(tagTitle).matches()) {
                    continue;
                }

                if (tagTitle.length() > Tag.MAX_TAG_TITLE_LENGTH) {
                    continue;
                }

                if (!Role.ROLE_ID_C_ADMIN.equals(currentUser.optString(User.USER_ROLE))
                        && ArrayUtils.contains(Symphonys.RESERVED_TAGS, tagTitle)) {
                    continue;
                }

                tagBuilder.append(tagTitle).append(",");
            }
            if (tagBuilder.length() > 0) {
                tagBuilder.deleteCharAt(tagBuilder.length() - 1);
            }

            dataModel.put(Tag.TAGS, tagBuilder.toString());
        }

        final String type = request.getParameter(Common.TYPE);
        if (StringUtils.isBlank(type)) {
            dataModel.put(Article.ARTICLE_TYPE, Article.ARTICLE_TYPE_C_NORMAL);
        } else {
            int articleType = Article.ARTICLE_TYPE_C_NORMAL;

            try {
                articleType = Integer.valueOf(type);
            } catch (final Exception e) {
                LOGGER.log(Level.WARN, "Gets article type error [" + type + "]", e);
            }

            if (Article.isInvalidArticleType(articleType)) {
                articleType = Article.ARTICLE_TYPE_C_NORMAL;
            }

            dataModel.put(Article.ARTICLE_TYPE, articleType);
        }

        String at = request.getParameter(Common.AT);
        at = StringUtils.trim(at);
        if (StringUtils.isNotBlank(at)) {
            dataModel.put(Common.AT, at + " ");
        }

        dataModelService.fillHeaderAndFooter(request, response, dataModel);

        String rewardEditorPlaceholderLabel = langPropsService.get("rewardEditorPlaceholderLabel");
        rewardEditorPlaceholderLabel = rewardEditorPlaceholderLabel.replace("{point}",
                String.valueOf(Pointtransfer.TRANSFER_SUM_C_ADD_ARTICLE_REWARD));
        dataModel.put("rewardEditorPlaceholderLabel", rewardEditorPlaceholderLabel);
        dataModel.put(Common.BROADCAST_POINT, Pointtransfer.TRANSFER_SUM_C_ADD_ARTICLE_BROADCAST);

        String articleContentErrorLabel = langPropsService.get("articleContentErrorLabel");
        articleContentErrorLabel = articleContentErrorLabel.replace("{maxArticleContentLength}",
                String.valueOf(ArticleAddValidation.MAX_ARTICLE_CONTENT_LENGTH));
        dataModel.put("articleContentErrorLabel", articleContentErrorLabel);

        fillPostArticleRequisite(dataModel, currentUser);
        fillDomainsWithTags(dataModel);
    }

    private void fillPostArticleRequisite(final Map<String, Object> dataModel, final JSONObject currentUser) {
        boolean requisite = false;
        String requisiteMsg = "";

//        if (!UserExt.updatedAvatar(currentUser)) {
//            requisite = true;
//            requisiteMsg = langPropsService.get("uploadAvatarThenPostLabel");
//        }

        dataModel.put(Common.REQUISITE, requisite);
        dataModel.put(Common.REQUISITE_MSG, requisiteMsg);
    }

    /**
     * Shows article with the specified article id.
     *
     * @param context   the specified context
     * @param request   the specified request
     * @param response  the specified response
     * @param articleId the specified article id
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/{articleId}", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, AnonymousViewCheck.class})
    @After(adviceClass = {CSRFToken.class, PermissionGrant.class, StopwatchEndAdvice.class})
    public void showArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response,
                            final String articleId) throws Exception {
        final AbstractFreeMarkerRenderer renderer = new SkinRenderer(request);
        context.setRenderer(renderer);
        renderer.setTemplateName("article.ftl");
        final Map<String, Object> dataModel = renderer.getDataModel();

        final int avatarViewMode = (int) request.getAttribute(UserExt.USER_AVATAR_VIEW_MODE);

        final JSONObject article = articleQueryService.getArticleById(avatarViewMode, articleId);
        if (null == article) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        dataModelService.fillHeaderAndFooter(request, response, dataModel);

        final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);
        final JSONObject author = userQueryService.getUser(authorId);
        Escapes.escapeHTML(author);

        if (Article.ARTICLE_ANONYMOUS_C_PUBLIC == article.optInt(Article.ARTICLE_ANONYMOUS)) {
            article.put(Article.ARTICLE_T_AUTHOR_NAME, author.optString(User.USER_NAME));
            article.put(Article.ARTICLE_T_AUTHOR_URL, author.optString(User.USER_URL));
            article.put(Article.ARTICLE_T_AUTHOR_INTRO, author.optString(UserExt.USER_INTRO));
        } else {
            article.put(Article.ARTICLE_T_AUTHOR_NAME, UserExt.ANONYMOUS_USER_NAME);
            article.put(Article.ARTICLE_T_AUTHOR_URL, "");
            article.put(Article.ARTICLE_T_AUTHOR_INTRO, "");
        }
        dataModel.put(Article.ARTICLE, article);

        article.put(Common.IS_MY_ARTICLE, false);
        article.put(Article.ARTICLE_T_AUTHOR, author);
        article.put(Common.REWARDED, false);
        article.put(Common.REWARED_COUNT, rewardQueryService.rewardedCount(articleId, Reward.TYPE_C_ARTICLE));
        article.put(Article.ARTICLE_REVISION_COUNT, revisionQueryService.count(articleId, Revision.DATA_TYPE_C_ARTICLE));

        articleQueryService.processArticleContent(article, request);

        String cmtViewModeStr = request.getParameter("m");
        JSONObject currentUser;
        String currentUserId = null;
        final boolean isLoggedIn = (Boolean) dataModel.get(Common.IS_LOGGED_IN);
        if (isLoggedIn) {
            currentUser = (JSONObject) dataModel.get(Common.CURRENT_USER);
            currentUserId = currentUser.optString(Keys.OBJECT_ID);
            article.put(Common.IS_MY_ARTICLE, currentUserId.equals(article.optString(Article.ARTICLE_AUTHOR_ID)));

            final boolean isFollowing = followQueryService.isFollowing(currentUserId, articleId, Follow.FOLLOWING_TYPE_C_ARTICLE);
            dataModel.put(Common.IS_FOLLOWING, isFollowing);

            final boolean isWatching = followQueryService.isFollowing(currentUserId, articleId, Follow.FOLLOWING_TYPE_C_ARTICLE_WATCH);
            dataModel.put(Common.IS_WATCHING, isWatching);

            final int articleVote = voteQueryService.isVoted(currentUserId, articleId);
            article.put(Article.ARTICLE_T_VOTE, articleVote);

            if (currentUserId.equals(author.optString(Keys.OBJECT_ID))) {
                article.put(Common.REWARDED, true);
            } else {
                article.put(Common.REWARDED, rewardQueryService.isRewarded(currentUserId, articleId, Reward.TYPE_C_ARTICLE));
            }

            if (StringUtils.isBlank(cmtViewModeStr) || !Strings.isNumeric(cmtViewModeStr)) {
                cmtViewModeStr = currentUser.optString(UserExt.USER_COMMENT_VIEW_MODE);
            }
        } else if (StringUtils.isBlank(cmtViewModeStr) || !Strings.isNumeric(cmtViewModeStr)) {
            cmtViewModeStr = "0";
        }

        final int cmtViewMode = Integer.valueOf(cmtViewModeStr);
        dataModel.put(UserExt.USER_COMMENT_VIEW_MODE, cmtViewMode);

        final JSONObject viewer = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null != viewer) {
            livenessMgmtService.incLiveness(viewer.optString(Keys.OBJECT_ID), Liveness.LIVENESS_PV);
        }

        if (!(Boolean) request.getAttribute(Keys.HttpRequest.IS_SEARCH_ENGINE_BOT)) {
            final long created = System.currentTimeMillis();
            final long expired = DateUtils.addMonths(new Date(created), 1).getTime();
            final String ip = Requests.getRemoteAddr(request);
            final String ua = Headers.getHeader(request, Common.USER_AGENT, "");
            final String referer = Headers.getHeader(request, "Referer", "");
            final JSONObject visit = new JSONObject();
            visit.put(Visit.VISIT_IP, ip);
            visit.put(Visit.VISIT_CITY, "");
            visit.put(Visit.VISIT_CREATED, created);
            visit.put(Visit.VISIT_DEVICE_ID, "");
            visit.put(Visit.VISIT_EXPIRED, expired);
            visit.put(Visit.VISIT_REFERER_URL, referer);
            visit.put(Visit.VISIT_UA, ua);
            visit.put(Visit.VISIT_URL, "/article/" + articleId);
            visit.put(Visit.VISIT_USER_ID, "");
            if (null != viewer) {
                visit.put(Visit.VISIT_USER_ID, viewer.optString(Keys.OBJECT_ID));
            }

            articleMgmtService.incArticleViewCount(visit);
        }

        dataModelService.fillRelevantArticles(avatarViewMode, dataModel, article);
        dataModelService.fillRandomArticles(dataModel);
        dataModelService.fillSideHotArticles(dataModel);

        // Qiniu file upload authenticate
        final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey"));
        final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket"));
        dataModel.put("qiniuUploadToken", uploadToken);
        dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain"));

        if (!Symphonys.getBoolean("qiniu.enabled")) {
            dataModel.put("qiniuUploadToken", "");
        }

        final long imgMaxSize = Symphonys.getLong("upload.img.maxSize");
        dataModel.put("imgMaxSize", imgMaxSize);
        final long fileMaxSize = Symphonys.getLong("upload.file.maxSize");
        dataModel.put("fileMaxSize", fileMaxSize);

        // Fill article thank
        Stopwatchs.start("Fills article thank");
        try {
            article.put(Common.THANKED, rewardQueryService.isRewarded(currentUserId, articleId, Reward.TYPE_C_THANK_ARTICLE));
            article.put(Common.THANKED_COUNT, rewardQueryService.rewardedCount(articleId, Reward.TYPE_C_THANK_ARTICLE));
            final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID);
            if (Article.ARTICLE_TYPE_C_QNA == article.optInt(Article.ARTICLE_TYPE)) {
                article.put(Common.OFFERED, rewardQueryService.isRewarded(articleAuthorId, articleId, Reward.TYPE_C_ACCEPT_COMMENT));
                final JSONObject offeredComment = commentQueryService.getOfferedComment(avatarViewMode, cmtViewMode, articleId);
                article.put(Article.ARTICLE_T_OFFERED_COMMENT, offeredComment);
                if (null != offeredComment) {
                    final String offeredCmtId = offeredComment.optString(Keys.OBJECT_ID);
                    offeredComment.put(Common.REWARED_COUNT, rewardQueryService.rewardedCount(offeredCmtId, Reward.TYPE_C_COMMENT));
                    offeredComment.put(Common.REWARDED, rewardQueryService.isRewarded(currentUserId, offeredCmtId, Reward.TYPE_C_COMMENT));
                }
            }
        } finally {
            Stopwatchs.end();
        }

        // Fill previous/next article
        final JSONObject previous = articleQueryService.getPreviousPermalink(articleId);
        final JSONObject next = articleQueryService.getNextPermalink(articleId);
        dataModel.put(Article.ARTICLE_T_PREVIOUS, previous);
        dataModel.put(Article.ARTICLE_T_NEXT, next);

        String stickConfirmLabel = langPropsService.get("stickConfirmLabel");
        stickConfirmLabel = stickConfirmLabel.replace("{point}", Symphonys.get("pointStickArticle"));
        dataModel.put("stickConfirmLabel", stickConfirmLabel);
        dataModel.put("pointThankArticle", Symphonys.get("pointThankArticle"));
        final int pageNum = Paginator.getPage(request);
        final int pageSize = Symphonys.getInt("articleCommentsPageSize");
        final int windowSize = Symphonys.getInt("articleCommentsWindowSize");

        final int commentCnt = article.getInt(Article.ARTICLE_COMMENT_CNT);
        final int pageCount = (int) Math.ceil((double) commentCnt / (double) pageSize);

        final List<Integer> pageNums = Paginator.paginate(pageNum, pageSize, pageCount, windowSize);
        if (!pageNums.isEmpty()) {
            dataModel.put(Pagination.PAGINATION_FIRST_PAGE_NUM, pageNums.get(0));
            dataModel.put(Pagination.PAGINATION_LAST_PAGE_NUM, pageNums.get(pageNums.size() - 1));
        }

        dataModel.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, pageNum);
        dataModel.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
        dataModel.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
        dataModel.put(Common.ARTICLE_COMMENTS_PAGE_SIZE, pageSize);

        dataModel.put(Common.DISCUSSION_VIEWABLE, article.optBoolean(Common.DISCUSSION_VIEWABLE));
        if (!article.optBoolean(Common.DISCUSSION_VIEWABLE)) {
            article.put(Article.ARTICLE_T_COMMENTS, (Object) Collections.emptyList());
            article.put(Article.ARTICLE_T_NICE_COMMENTS, (Object) Collections.emptyList());

            return;
        }

        final List<JSONObject> niceComments = commentQueryService.getNiceComments(avatarViewMode, cmtViewMode, articleId, 3);
        article.put(Article.ARTICLE_T_NICE_COMMENTS, (Object) niceComments);

        double niceCmtScore = Double.MAX_VALUE;
        if (!niceComments.isEmpty()) {
            niceCmtScore = niceComments.get(niceComments.size() - 1).optDouble(Comment.COMMENT_SCORE, 0D);

            for (final JSONObject comment : niceComments) {
                String thankTemplate = langPropsService.get("thankConfirmLabel");
                thankTemplate = thankTemplate.replace("{point}", String.valueOf(Symphonys.getInt("pointThankComment")))
                        .replace("{user}", comment.optJSONObject(Comment.COMMENT_T_COMMENTER).optString(User.USER_NAME));
                comment.put(Comment.COMMENT_T_THANK_LABEL, thankTemplate);

                final String commentId = comment.optString(Keys.OBJECT_ID);
                if (isLoggedIn) {
                    comment.put(Common.REWARDED, rewardQueryService.isRewarded(currentUserId, commentId, Reward.TYPE_C_COMMENT));
                    final int commentVote = voteQueryService.isVoted(currentUserId, commentId);
                    comment.put(Comment.COMMENT_T_VOTE, commentVote);
                }

                comment.put(Common.REWARED_COUNT, rewardQueryService.rewardedCount(commentId, Reward.TYPE_C_COMMENT));

                // https://github.com/b3log/symphony/issues/682
                if (Comment.COMMENT_VISIBLE_C_AUTHOR == comment.optInt(Comment.COMMENT_VISIBLE)) {
                    final String commentAuthorId = comment.optString(Comment.COMMENT_AUTHOR_ID);
                    if (!isLoggedIn || (!StringUtils.equals(currentUserId, commentAuthorId) && !StringUtils.equals(currentUserId, authorId))) {
                        comment.put(Comment.COMMENT_CONTENT, langPropsService.get("onlySelfAndArticleAuthorVisibleLabel"));
                    }
                }
            }
        }

        // Load comments
        final List<JSONObject> articleComments =
                commentQueryService.getArticleComments(avatarViewMode, articleId, pageNum, pageSize, cmtViewMode);
        article.put(Article.ARTICLE_T_COMMENTS, (Object) articleComments);

        // Fill comment thank
        Stopwatchs.start("Fills comment thank");
        try {
            final String thankTemplate = langPropsService.get("thankConfirmLabel");
            for (final JSONObject comment : articleComments) {
                comment.put(Comment.COMMENT_T_NICE, comment.optDouble(Comment.COMMENT_SCORE, 0D) >= niceCmtScore);

                final String thankStr = thankTemplate.replace("{point}", String.valueOf(Symphonys.getInt("pointThankComment")))
                        .replace("{user}", comment.optJSONObject(Comment.COMMENT_T_COMMENTER).optString(User.USER_NAME));
                comment.put(Comment.COMMENT_T_THANK_LABEL, thankStr);

                final String commentId = comment.optString(Keys.OBJECT_ID);
                if (isLoggedIn) {
                    comment.put(Common.REWARDED,
                            rewardQueryService.isRewarded(currentUserId, commentId, Reward.TYPE_C_COMMENT));
                    final int commentVote = voteQueryService.isVoted(currentUserId, commentId);
                    comment.put(Comment.COMMENT_T_VOTE, commentVote);
                }

                comment.put(Common.REWARED_COUNT, rewardQueryService.rewardedCount(commentId, Reward.TYPE_C_COMMENT));

                // https://github.com/b3log/symphony/issues/682
                if (Comment.COMMENT_VISIBLE_C_AUTHOR == comment.optInt(Comment.COMMENT_VISIBLE)) {
                    final String commentAuthorId = comment.optString(Comment.COMMENT_AUTHOR_ID);
                    if (!isLoggedIn || (!StringUtils.equals(currentUserId, commentAuthorId) && !StringUtils.equals(currentUserId, authorId))) {
                        comment.put(Comment.COMMENT_CONTENT, langPropsService.get("onlySelfAndArticleAuthorVisibleLabel"));
                    }
                }
            }
        } finally {
            Stopwatchs.end();
        }

        // Referral statistic
        final String referralUserName = request.getParameter("r");
        if (!UserRegisterValidation.invalidUserName(referralUserName)) {
            final JSONObject referralUser = userQueryService.getUserByName(referralUserName);
            if (null == referralUser) {
                return;
            }

            final String viewerIP = Requests.getRemoteAddr(request);

            final JSONObject referral = new JSONObject();
            referral.put(Referral.REFERRAL_CLICK, 1);
            referral.put(Referral.REFERRAL_DATA_ID, articleId);
            referral.put(Referral.REFERRAL_IP, viewerIP);
            referral.put(Referral.REFERRAL_TYPE, Referral.REFERRAL_TYPE_C_ARTICLE);
            referral.put(Referral.REFERRAL_USER, referralUserName);

            referralMgmtService.updateReferral(referral);
        }

        if (StringUtils.isBlank(article.optString(Article.ARTICLE_AUDIO_URL))) {
            final String uid = StringUtils.isBlank(currentUserId) ? "visitor" : currentUserId;

            articleMgmtService.genArticleAudio(article, uid);
        }

        if (StringUtils.isNotBlank(Symphonys.get("ipfs.dir"))) {
            articleMgmtService.saveMarkdown(article);
        }
    }

    /**
     * Adds an article locally.
     *

     * The request json object (an article):
     *

     * {
     *   "articleTitle": "",
     *   "articleTags": "", // Tags spliting by ','
     *   "articleContent": "",
     *   "articleCommentable": boolean,
     *   "articleType": int,
     *   "articleRewardContent": "",
     *   "articleRewardPoint": int,
     *   "articleQnAOfferPoint": int,
     *   "articleAnonymous": boolean
     * }
     *

     *

     *
     * @param context the specified context
     * @param request the specified request
     */
    @RequestProcessing(value = "/article", method = HTTPRequestMethod.POST)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class, CSRFCheck.class, ArticleAddValidation.class, PermissionCheck.class})
    @After(adviceClass = StopwatchEndAdvice.class)
    public void addArticle(final HTTPRequestContext context, final HttpServletRequest request, final JSONObject requestJSONObject) {
        context.renderJSON();

        final String articleTitle = requestJSONObject.optString(Article.ARTICLE_TITLE);
        String articleTags = requestJSONObject.optString(Article.ARTICLE_TAGS);
        final String articleContent = requestJSONObject.optString(Article.ARTICLE_CONTENT);
        final boolean articleCommentable = requestJSONObject.optBoolean(Article.ARTICLE_COMMENTABLE, true);
        final int articleType = requestJSONObject.optInt(Article.ARTICLE_TYPE, Article.ARTICLE_TYPE_C_NORMAL);
        final String articleRewardContent = requestJSONObject.optString(Article.ARTICLE_REWARD_CONTENT);
        final int articleRewardPoint = requestJSONObject.optInt(Article.ARTICLE_REWARD_POINT);
        final int articleQnAOfferPoint = requestJSONObject.optInt(Article.ARTICLE_QNA_OFFER_POINT);
        final String ip = Requests.getRemoteAddr(request);
        final String ua = Headers.getHeader(request, Common.USER_AGENT, "");
        final boolean isAnonymous = requestJSONObject.optBoolean(Article.ARTICLE_ANONYMOUS, false);
        final int articleAnonymous = isAnonymous
                ? Article.ARTICLE_ANONYMOUS_C_ANONYMOUS : Article.ARTICLE_ANONYMOUS_C_PUBLIC;

        final JSONObject article = new JSONObject();
        article.put(Article.ARTICLE_TITLE, articleTitle);
        article.put(Article.ARTICLE_CONTENT, articleContent);
        article.put(Article.ARTICLE_EDITOR_TYPE, 0);
        article.put(Article.ARTICLE_COMMENTABLE, articleCommentable);
        article.put(Article.ARTICLE_TYPE, articleType);
        article.put(Article.ARTICLE_REWARD_CONTENT, articleRewardContent);
        article.put(Article.ARTICLE_REWARD_POINT, articleRewardPoint);
        article.put(Article.ARTICLE_QNA_OFFER_POINT, articleQnAOfferPoint);
        article.put(Article.ARTICLE_IP, "");
        if (StringUtils.isNotBlank(ip)) {
            article.put(Article.ARTICLE_IP, ip);
        }
        article.put(Article.ARTICLE_UA, ua);
        article.put(Article.ARTICLE_ANONYMOUS, articleAnonymous);

        try {
            final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);

            article.put(Article.ARTICLE_AUTHOR_ID, currentUser.optString(Keys.OBJECT_ID));

            if (!Role.ROLE_ID_C_ADMIN.equals(currentUser.optString(User.USER_ROLE))) {
                articleTags = articleMgmtService.filterReservedTags(articleTags);
            }

            if (Article.ARTICLE_TYPE_C_DISCUSSION == articleType && StringUtils.isBlank(articleTags)) {
                articleTags = "小黑屋";
            }

            if (Article.ARTICLE_TYPE_C_THOUGHT == articleType && StringUtils.isBlank(articleTags)) {
                articleTags = "思绪";
            }

            article.put(Article.ARTICLE_TAGS, articleTags);

            final String articleId = articleMgmtService.addArticle(article);

            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.SUCC);
            context.renderJSONValue(Article.ARTICLE_T_ID, articleId);
        } catch (final ServiceException e) {
            final String msg = e.getMessage();
            LOGGER.log(Level.ERROR, "Adds article[title=" + articleTitle + "] failed: {0}", e.getMessage());

            context.renderMsg(msg);
            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.ERR);
        }
    }

    /**
     * Shows update article.
     *
     * @param context  the specified context
     * @param request  the specified request
     * @param response the specified response
     * @throws Exception exception
     */
    @RequestProcessing(value = "/update", method = HTTPRequestMethod.GET)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class})
    @After(adviceClass = {CSRFToken.class, PermissionGrant.class, StopwatchEndAdvice.class})
    public void showUpdateArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response)
            throws Exception {
        final String articleId = request.getParameter("id");
        if (StringUtils.isBlank(articleId)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        final JSONObject article = articleQueryService.getArticle(articleId);
        if (null == article) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null == currentUser
                || !currentUser.optString(Keys.OBJECT_ID).equals(article.optString(Article.ARTICLE_AUTHOR_ID))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        final AbstractFreeMarkerRenderer renderer = new SkinRenderer(request);
        context.setRenderer(renderer);
        renderer.setTemplateName("home/post.ftl");
        final Map<String, Object> dataModel = renderer.getDataModel();

        dataModel.put(Article.ARTICLE, article);
        dataModel.put(Article.ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE));

        dataModelService.fillHeaderAndFooter(request, response, dataModel);

        // Qiniu file upload authenticate
        final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey"));
        final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket"));
        dataModel.put("qiniuUploadToken", uploadToken);
        dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain"));

        if (!Symphonys.getBoolean("qiniu.enabled")) {
            dataModel.put("qiniuUploadToken", "");
        }

        final long imgMaxSize = Symphonys.getLong("upload.img.maxSize");
        dataModel.put("imgMaxSize", imgMaxSize);
        final long fileMaxSize = Symphonys.getLong("upload.file.maxSize");
        dataModel.put("fileMaxSize", fileMaxSize);

        fillDomainsWithTags(dataModel);

        String rewardEditorPlaceholderLabel = langPropsService.get("rewardEditorPlaceholderLabel");
        rewardEditorPlaceholderLabel = rewardEditorPlaceholderLabel.replace("{point}",
                String.valueOf(Pointtransfer.TRANSFER_SUM_C_ADD_ARTICLE_REWARD));
        dataModel.put("rewardEditorPlaceholderLabel", rewardEditorPlaceholderLabel);
        dataModel.put(Common.BROADCAST_POINT, Pointtransfer.TRANSFER_SUM_C_ADD_ARTICLE_BROADCAST);

        fillPostArticleRequisite(dataModel, currentUser);
    }

    /**
     * Updates an article locally.
     *

     * The request json object (an article):
     *

     * {
     *   "articleTitle": "",
     *   "articleTags": "", // Tags spliting by ','
     *   "articleContent": "",
     *   "articleCommentable": boolean,
     *   "articleType": int,
     *   "articleRewardContent": "",
     *   "articleRewardPoint": int,
     *    "articleQnAOfferPoint": int
     * }
     *

     *

     *
     * @param context  the specified context
     * @param request  the specified request
     * @param response the specified response
     * @param id       the specified article id
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/{id}", method = HTTPRequestMethod.PUT)
    @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class, CSRFCheck.class, ArticleUpdateValidation.class,
            PermissionCheck.class})
    @After(adviceClass = StopwatchEndAdvice.class)
    public void updateArticle(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response,
                              final String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        final int avatarViewMode = (int) request.getAttribute(UserExt.USER_AVATAR_VIEW_MODE);

        final JSONObject oldArticle = articleQueryService.getArticleById(avatarViewMode, id);
        if (null == oldArticle) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        context.renderJSON();

        if (Article.ARTICLE_STATUS_C_VALID != oldArticle.optInt(Article.ARTICLE_STATUS)) {
            context.renderMsg(langPropsService.get("articleLockedLabel"));
            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.ERR);

            return;
        }

        final JSONObject requestJSONObject = (JSONObject) request.getAttribute(Keys.REQUEST);

        final String articleTitle = requestJSONObject.optString(Article.ARTICLE_TITLE);
        String articleTags = requestJSONObject.optString(Article.ARTICLE_TAGS);
        final String articleContent = requestJSONObject.optString(Article.ARTICLE_CONTENT);
        final boolean articleCommentable = requestJSONObject.optBoolean(Article.ARTICLE_COMMENTABLE, true);
        final int articleType = requestJSONObject.optInt(Article.ARTICLE_TYPE, Article.ARTICLE_TYPE_C_NORMAL);
        final String articleRewardContent = requestJSONObject.optString(Article.ARTICLE_REWARD_CONTENT);
        final int articleRewardPoint = requestJSONObject.optInt(Article.ARTICLE_REWARD_POINT);
        final int articleQnAOfferPoint = requestJSONObject.optInt(Article.ARTICLE_QNA_OFFER_POINT);
        final String ip = Requests.getRemoteAddr(request);
        final String ua = Headers.getHeader(request, Common.USER_AGENT, "");

        final JSONObject article = new JSONObject();
        article.put(Keys.OBJECT_ID, id);
        article.put(Article.ARTICLE_TITLE, articleTitle);
        article.put(Article.ARTICLE_CONTENT, articleContent);
        article.put(Article.ARTICLE_EDITOR_TYPE, 0);
        article.put(Article.ARTICLE_COMMENTABLE, articleCommentable);
        article.put(Article.ARTICLE_TYPE, articleType);
        article.put(Article.ARTICLE_REWARD_CONTENT, articleRewardContent);
        article.put(Article.ARTICLE_REWARD_POINT, articleRewardPoint);
        article.put(Article.ARTICLE_QNA_OFFER_POINT, articleQnAOfferPoint);
        article.put(Article.ARTICLE_IP, "");
        if (StringUtils.isNotBlank(ip)) {
            article.put(Article.ARTICLE_IP, ip);
        }
        article.put(Article.ARTICLE_UA, ua);

        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null == currentUser
                || !currentUser.optString(Keys.OBJECT_ID).equals(oldArticle.optString(Article.ARTICLE_AUTHOR_ID))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        article.put(Article.ARTICLE_AUTHOR_ID, currentUser.optString(Keys.OBJECT_ID));

        if (!Role.ROLE_ID_C_ADMIN.equals(currentUser.optString(User.USER_ROLE))) {
            articleTags = articleMgmtService.filterReservedTags(articleTags);
        }

        if (Article.ARTICLE_TYPE_C_DISCUSSION == articleType && StringUtils.isBlank(articleTags)) {
            articleTags = "小黑屋";
        }

        if (Article.ARTICLE_TYPE_C_THOUGHT == articleType && StringUtils.isBlank(articleTags)) {
            articleTags = "思绪";
        }

        article.put(Article.ARTICLE_TAGS, articleTags);

        try {
            articleMgmtService.updateArticle(article);

            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.SUCC);
            context.renderJSONValue(Article.ARTICLE_T_ID, id);
        } catch (final ServiceException e) {
            final String msg = e.getMessage();
            LOGGER.log(Level.ERROR, "Adds article[title=" + articleTitle + "] failed: {0}", e.getMessage());

            context.renderMsg(msg);
            context.renderJSONValue(Keys.STATUS_CODE, StatusCodes.ERR);
        }
    }

    /**
     * Markdowns.
     *

     * Renders the response with a json object, for example,
     *

     * {
     *     "html": ""
     * }
     *

     *

     *
     * @param request the specified http servlet request
     * @param context the specified http request context
     */
    @RequestProcessing(value = "/markdown", method = HTTPRequestMethod.POST)
    @Before(adviceClass = StopwatchStartAdvice.class)
    @After(adviceClass = StopwatchEndAdvice.class)
    public void markdown2HTML(final HttpServletRequest request, final HTTPRequestContext context) {
        context.renderJSON(true);
        String markdownText = request.getParameter("markdownText");
        if (StringUtils.isBlank(markdownText)) {
            context.renderJSONValue("html", "");

            return;
        }

        markdownText = shortLinkQueryService.linkArticle(markdownText);
        markdownText = shortLinkQueryService.linkTag(markdownText);
        markdownText = Emotions.toAliases(markdownText);
        markdownText = Emotions.convert(markdownText);
        markdownText = Markdowns.toHTML(markdownText);
        markdownText = Markdowns.clean(markdownText, "");
        markdownText = MP3Players.render(markdownText);
        markdownText = VideoPlayers.render(markdownText);

        context.renderJSONValue("html", markdownText);
    }

    /**
     * Gets article preview content.
     *

     * Renders the response with a json object, for example,
     *

     * {
     *     "html": ""
     * }
     *

     *

     *
     * @param request   the specified http servlet request
     * @param response  the specified http servlet response
     * @param context   the specified http request context
     * @param articleId the specified article id
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/{articleId}/preview", method = HTTPRequestMethod.GET)
    @Before(adviceClass = StopwatchStartAdvice.class)
    @After(adviceClass = StopwatchEndAdvice.class)
    public void getArticlePreviewContent(final HttpServletRequest request, final HttpServletResponse response,
                                         final HTTPRequestContext context, final String articleId) throws Exception {
        final String content = articleQueryService.getArticlePreviewContent(articleId, request);
        if (StringUtils.isBlank(content)) {
            context.renderJSON().renderFalseResult();

            return;
        }

        context.renderJSON(true).renderJSONValue("html", content);
    }

    /**
     * Article rewards.
     *
     * @param request  the specified http servlet request
     * @param response the specified http servlet response
     * @param context  the specified http request context
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/reward", method = HTTPRequestMethod.POST)
    @Before(adviceClass = StopwatchStartAdvice.class)
    @After(adviceClass = StopwatchEndAdvice.class)
    public void reward(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
            throws Exception {
        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null == currentUser) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        final String articleId = request.getParameter(Article.ARTICLE_T_ID);
        if (StringUtils.isBlank(articleId)) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return;
        }

        context.renderJSON();

        try {
            articleMgmtService.reward(articleId, currentUser.optString(Keys.OBJECT_ID));
        } catch (final ServiceException e) {
            context.renderMsg(langPropsService.get("transferFailLabel"));

            return;
        }

        final JSONObject article = articleQueryService.getArticle(articleId);
        articleQueryService.processArticleContent(article, request);

        final String rewardContent = article.optString(Article.ARTICLE_REWARD_CONTENT);
        context.renderTrueResult().renderJSONValue(Article.ARTICLE_REWARD_CONTENT, rewardContent);
    }

    /**
     * Article thanks.
     *
     * @param request  the specified http servlet request
     * @param response the specified http servlet response
     * @param context  the specified http request context
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/thank", method = HTTPRequestMethod.POST)
    @Before(adviceClass = {StopwatchStartAdvice.class, PermissionCheck.class})
    @After(adviceClass = StopwatchEndAdvice.class)
    public void thank(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
            throws Exception {
        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null == currentUser) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        final String articleId = request.getParameter(Article.ARTICLE_T_ID);
        if (StringUtils.isBlank(articleId)) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return;
        }

        context.renderJSON();

        try {
            articleMgmtService.thank(articleId, currentUser.optString(Keys.OBJECT_ID));
        } catch (final ServiceException e) {
            context.renderMsg(langPropsService.get("transferFailLabel"));

            return;
        }

        context.renderTrueResult();
    }

    /**
     * Sticks an article.
     *
     * @param request  the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     * @param context  the specified HTTP request context
     * @throws Exception exception
     */
    @RequestProcessing(value = "/article/stick", method = HTTPRequestMethod.POST)
    @Before(adviceClass = {StopwatchStartAdvice.class, PermissionCheck.class})
    @After(adviceClass = StopwatchEndAdvice.class)
    public void stickArticle(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
            throws Exception {
        final JSONObject currentUser = (JSONObject) request.getAttribute(Common.CURRENT_USER);
        if (null == currentUser) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        final String articleId = request.getParameter(Article.ARTICLE_T_ID);
        if (StringUtils.isBlank(articleId)) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);

            return;
        }

        final JSONObject article = articleQueryService.getArticle(articleId);
        if (null == article) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);

            return;
        }

        if (!currentUser.optString(Keys.OBJECT_ID).equals(article.optString(Article.ARTICLE_AUTHOR_ID))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        context.renderJSON();

        try {
            articleMgmtService.stick(articleId);
        } catch (final ServiceException e) {
            context.renderMsg(e.getMessage());

            return;
        }

        context.renderTrueResult().renderMsg(langPropsService.get("stickSuccLabel"));
    }

    /**
     * Expires a sticked article.
     *
     * @param request  the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     * @param context  the specified HTTP request context
     * @throws Exception exception
     */
    @RequestProcessing(value = "/cron/article/stick-expire", method = HTTPRequestMethod.GET)
    @Before(adviceClass = StopwatchStartAdvice.class)
    @After(adviceClass = StopwatchEndAdvice.class)
    public void expireStickArticle(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
            throws Exception {
        final String key = Symphonys.get("keyOfSymphony");
        if (!key.equals(request.getParameter("key"))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);

            return;
        }

        articleMgmtService.expireStick();

        context.renderJSON().renderTrueResult();
    }
}


text:
// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright (C)2006 Google, Inc.

/**
 * @fileoverview Character counter widget implementation.
 *
 * @see ../demos/charcounter.html
 */

goog.provide('goog.ui.CharCounter');
goog.provide('goog.ui.CharCounter.Display');

goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventTarget');
goog.require('goog.events.InputHandler');

/**
 * CharCounter widget. Counts the number of characters in a input field or a
 * text box and displays the number of additional characters that may be
 * entered before the maximum length is reached.
 *
 * @extends {goog.events.EventTarget}
 * @param {HTMLInputElement|HTMLTextAreaElement} elInput Input or text area
 *     element to count the number of characters in.
 * @param {Element} elCount HTML element to display the remaining number of
 *     characters in.
 * @param {number} maxLength The maximum length.
 * @param {goog.ui.CharCounter.Display} opt_displayMode Display mode for this
 *     char counter. Defaults to {@link goog.ui.CharCounter.Display.REMAINING}.
 * @constructor
 */
goog.ui.CharCounter = function(elInput, elCount, maxLength, opt_displayMode) {
  goog.events.EventTarget.call(this);

  /**
   * Input or text area element to count the number of characters in.
   * @type {HTMLInputElement|HTMLTextAreaElement}
   * @private
   */
  this.elInput_ = elInput;

  /**
   * HTML element to display the remaining number of characters in.
   * @type {Element}
   * @private
   */
  this.elCount_ = elCount;

  /**
   * The maximum length.
   * @type {number}
   * @private
   */
  this.maxLength_ = maxLength;

  /**
   * The display mode for this char counter.
   * @type {!goog.ui.CharCounter.Display}
   * @private
   */
  this.display_ = opt_displayMode || goog.ui.CharCounter.Display.REMAINING;

  elInput.maxLength = maxLength;

  /**
   * The input handler that provides the input event.
   * @type {goog.events.InputHandler}
   * @private
   */
  this.inputHandler_ = new goog.events.InputHandler(elInput);

  goog.events.listen(this.inputHandler_,
      goog.events.InputHandler.EventType.INPUT, this.onChange_, false, this);

  this.checkLength_();
};
goog.inherits(goog.ui.CharCounter, goog.events.EventTarget);

/**
 * Display mode for the char counter.
 * @enum {number}
 */
goog.ui.CharCounter.Display = {
  /** Widget displays the number of characters remaining (the default). */
  REMAINING: 0,
  /** Widget displays the number of characters entered. */
  INCREMENTAL: 1
};

/**
 * Sets the maximum length.
 *
 * @param {number} maxLength The maximum length.
 */
goog.ui.CharCounter.prototype.setMaxLength = function(maxLength) {
  this.maxLength_ = maxLength;
  this.elInput_.maxLength = maxLength;
  this.checkLength_();
};

/**
 * Returns the maximum length.
 *
 * @return {number} The maximum length.
 */
goog.ui.CharCounter.prototype.getMaxLength = function() {
  return this.maxLength_;
};

/**
 * Sets the display mode.
 *
 * @param {!goog.ui.CharCounter.Display} displayMode The display mode.
 */
goog.ui.CharCounter.prototype.setDisplayMode = function(displayMode) {
  this.display_ = displayMode;
  this.checkLength_();
};

/**
 * Returns the display mode.
 *
 * @return {!goog.ui.CharCounter.Display} The display mode.
 */
goog.ui.CharCounter.prototype.getDisplayMode = function() {
  return this.display_;
};

/**
 * Change event handler for input field.
 *
 * @param {goog.events.BrowserEvent} event Change event.
 * @private
 */
goog.ui.CharCounter.prototype.onChange_ = function(event) {
  this.checkLength_();
};

/**
 * Checks length of text in input field and updates the counter. Truncates text
 * if the maximum lengths is exceeded.
 *
 * @private
 */
goog.ui.CharCounter.prototype.checkLength_ = function() {
  var count = this.elInput_.value.length;

  // There's no maxlength property for textareas so instead we truncate the
  // text if it gets too long. It's also used to truncate the text in a input
  // field if the maximum length is changed.
  if (count > this.maxLength_) {

    var scrollTop = this.elInput_.scrollTop
    var scrollLeft = this.elInput_.scrollLeft;

    this.elInput_.value = this.elInput_.value.substring(0, this.maxLength_);
    count = this.maxLength_;

    this.elInput_.scrollTop = scrollTop;
    this.elInput_.scrollLeft = scrollLeft;
  }

  var incremental = this.display_ == goog.ui.CharCounter.Display.INCREMENTAL;
  goog.dom.setTextContent(
      this.elCount_,
      /** @type {string} */(incremental ? count : this.maxLength_ - count));
};

/** @inheritDoc */
goog.ui.CharCounter.prototype.disposeInternal = function() {
  goog.ui.CharCounter.superClass_.disposeInternal.call(this);
  delete this.elInput_;
  this.inputHandler_.dispose();
  this.inputHandler_ = null;
};

redpajama_set_name: RedPajamaGithub


text:
class Calculator::SalesTax < Calculator

  def self.description
    I18n.t("sales_tax")
  end

  def self.register
    super
    TaxRate.register_calculator(self)
  end

  def self.calculate_tax(order, rates)
    ActiveSupport::Deprecation.warn("please use Calculator::SalesTax#compute instead", caller)

    return 0 if rates.empty?
    # note: there is a bug with associations in rails 2.1 model caching so we're using this hack
    # (see http://rails.lighthouseapp.com/projects/8994/tickets/785-caching-models-fails-in-development)
    cache_hack = rates.first.respond_to?(:tax_category_id)

    taxable_totals = {}
    order.line_items.each do |line_item|
      next unless tax_category = line_item.variant.product.tax_category
      next unless rate = rates.find { | sales_rate | sales_rate.tax_category_id == tax_category.id } if cache_hack
      next unless rate = rates.find { | sales_rate | sales_rate.tax_category == tax_category } unless cache_hack

      taxable_totals[tax_category] ||= 0
      taxable_totals[tax_category] += line_item.total
    end

    return 0 if taxable_totals.empty?
    tax = 0
    rates.each do |rate|
      tax_category = rate.tax_category unless cache_hack
      tax_category = TaxCategory.find(rate.tax_category_id) if cache_hack
      next unless taxable_total = taxable_totals[tax_category]
      tax += taxable_total * rate.amount
    end
    tax
  end

  def compute(order)
    rate = self.calculable
    line_items = order.line_items.select { |i| i.product.tax_category == rate.tax_category }
    line_items.inject(0) {|sum, line_item|
      sum += line_item.total * rate.amount
    }
  end
end


text:
package org.apache.gora.aerospike.store;

import org.apache.gora.aerospike.GoraAerospikeTestDriver;
import org.apache.gora.examples.WebPageDataCreator;
import org.apache.gora.examples.generated.WebPage;
import org.apache.gora.query.Query;
import org.apache.gora.store.DataStoreTestBase;
import org.apache.gora.store.DataStoreTestUtil;
import org.apache.gora.util.AvroUtils;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.testcontainers.containers.GenericContainer;

import java.time.Duration;

import static org.apache.gora.examples.WebPageDataCreator.URLS;

/**
 * Test case for AerospikeStore.
 */
public class TestAerospikeStore extends DataStoreTestBase {

  private static final String DOCKER_CONTAINER_NAME = "aerospike/aerospike-server:5.5.0.7";

  @ClassRule
  public static GenericContainer aerospikeContainer = new GenericContainer(DOCKER_CONTAINER_NAME)
          .withExposedPorts(3000).waitingFor(new AerospikeStartupLogWaitStrategy())
          .withStartupTimeout(Duration.ofSeconds(240));

  static {
    setTestDriver(new GoraAerospikeTestDriver(aerospikeContainer));
  }

  @Override
  public void setUp() throws Exception {
    super.setUp();
  }

  @Override
  public void tearDown() throws Exception {
    super.tearDown();
  }

  @Test
  @Override
  public void testQuery() throws Exception {
    // Clearing the test data in the database
    Query<String, WebPage> query;
    WebPageDataCreator.createWebPageData(webPageStore);
    query = webPageStore.newQuery();
    webPageStore.deleteByQuery(query);

    super.testQuery();
  }

  @Test
  @Override
  public void testDelete() throws Exception {
    // Clearing the test data in the database
    Query<String, WebPage> query;
    WebPageDataCreator.createWebPageData(webPageStore);
    query = webPageStore.newQuery();
    webPageStore.deleteByQuery(query);

    super.testDelete();
  }

  @Test
  @Override
  public void testDeleteByQuery() throws Exception {

    // Can not use the super method as they query key ranges are not supported
    Query<String, WebPage> query;
    //test 1 - delete all
    WebPageDataCreator.createWebPageData(webPageStore);

    query = webPageStore.newQuery();

    DataStoreTestUtil.assertNumResults(webPageStore.newQuery(), URLS.length);
    webPageStore.deleteByQuery(query);
    webPageStore.flush();
    DataStoreTestUtil.assertEmptyResults(webPageStore.newQuery());

    //test 2 - delete all
    WebPageDataCreator.createWebPageData(webPageStore);

    query = webPageStore.newQuery();
    query.setFields(AvroUtils.getSchemaFieldNames(WebPage.SCHEMA$));

    DataStoreTestUtil.assertNumResults(webPageStore.newQuery(), URLS.length);
    webPageStore.deleteByQuery(query);
    webPageStore.flush();
    DataStoreTestUtil.assertEmptyResults(webPageStore.newQuery());

    webPageStore.truncateSchema();
  }

  // Unsupported functionality due to the limitations in Aerospike java client

  @Test
  @Ignore("Explicit schema creation related functionality is not supported in Aerospike")
  @Override
  public void testTruncateSchema() throws Exception {
    super.testTruncateSchema();
  }

  @Test
  @Ignore("Explicit schema creation related functionality is not supported in Aerospike")
  @Override
  public void testDeleteSchema() throws Exception {
    super.testDeleteSchema();
  }

  @Test
  @Ignore("Explicit schema creation related functionality is not supported in Aerospike")
  @Override
  public void testSchemaExists() throws Exception {
    super.testSchemaExists();
  }

  @Test
  @Ignore("Query key ranges based on primary key is not supported via the java client")
  @Override
  public void testQueryStartKey() throws Exception {
    super.testQueryStartKey();
  }

  @Test
  @Ignore("Query key ranges based on primary key is not supported via the java client")
  @Override
  public void testQueryEndKey() throws Exception {
    super.testQueryEndKey();
  }

  @Test
  @Ignore("Query key ranges based on primary key is not supported via the java client")
  @Override
  public void testQueryKeyRange() throws Exception {
    super.testQueryKeyRange();
  }

  @Test
  @Ignore("Not supported as query key ranges are not supported")
  @Override
  public void testDeleteByQueryFields() throws Exception {
    super.testDeleteByQueryFields();
  }
}


text:
package openperipheral.adapter.property;

import com.google.common.base.Preconditions;
import java.lang.reflect.Field;
import openperipheral.api.adapter.IPropertyCallback;
import openperipheral.api.property.ISingleCustomProperty;

public class SingleManipulatorProvider {

	public static final IFieldManipulator FIELD_MANIPULATOR = new IFieldManipulator() {
		@Override
		public void setField(Object owner, Object target, Field field, Object value) {
			PropertyUtils.setContents(owner, field, value);
		}

		@Override
		public Object getField(Object owner, Object target, Field field) {
			return target;
		}
	};

	public static final IFieldManipulator OWNER_DELEGATING_MANIPULATOR = new IFieldManipulator() {
		@Override
		public void setField(Object owner, Object target, Field field, Object value) {
			((IPropertyCallback)owner).setField(field, value);
		}

		@Override
		public Object getField(Object owner, Object target, Field field) {
			return ((IPropertyCallback)owner).getField(field);
		}
	};

	public static final IFieldManipulator TARGET_DELEGATING_MANIPULATOR = new IFieldManipulator() {

		@SuppressWarnings("unchecked")
		@Override
		public void setField(Object owner, Object target, Field field, Object value) {
			Preconditions.checkNotNull(target, "No value in field");
			((ISingleCustomProperty<Object>)target).set(owner, field, value);
		}

		@SuppressWarnings("unchecked")
		@Override
		public Object getField(Object owner, Object target, Field field) {
			Preconditions.checkNotNull(target, "No value in field");
			return ((ISingleCustomProperty<Object>)target).get(owner, field);
		}
	};

	public static IFieldManipulator getProvider(Class<?> fieldType, boolean isDelegating) {
		if (isDelegating) return OWNER_DELEGATING_MANIPULATOR;
		if (ISingleCustomProperty.class.isAssignableFrom(fieldType)) return TARGET_DELEGATING_MANIPULATOR;
		return FIELD_MANIPULATOR;
	}

}


text:
namespace sharp.Serene.BasicSamples {
    export class PopulateLinkedDataForm extends Serenity.PrefixedContext {
        static formKey = 'BasicSamples.PopulateLinkedData';

    }

    export interface PopulateLinkedDataForm {
        CustomerID: Northwind.CustomerEditor;
        CustomerContactName: Serenity.StringEditor;
        CustomerContactTitle: Serenity.StringEditor;
        CustomerCity: Serenity.StringEditor;
        CustomerRegion: Serenity.StringEditor;
        CustomerCountry: Serenity.StringEditor;
        CustomerPhone: Serenity.StringEditor;
        CustomerFax: Serenity.StringEditor;
        OrderDate: Serenity.DateEditor;
        RequiredDate: Serenity.DateEditor;
        EmployeeID: Serenity.LookupEditor;
        DetailList: Northwind.OrderDetailsEditor;
    }

    [['CustomerID', () => Northwind.CustomerEditor], ['CustomerContactName', () => Serenity.StringEditor], ['CustomerContactTitle', () => Serenity.StringEditor], ['CustomerCity', () => Serenity.StringEditor], ['CustomerRegion', () => Serenity.StringEditor], ['CustomerCountry', () => Serenity.StringEditor], ['CustomerPhone', () => Serenity.StringEditor], ['CustomerFax', () => Serenity.StringEditor], ['OrderDate', () => Serenity.DateEditor], ['RequiredDate', () => Serenity.DateEditor], ['EmployeeID', () => Serenity.LookupEditor], ['DetailList', () => Northwind.OrderDetailsEditor]].forEach(x => Object.defineProperty(PopulateLinkedDataForm.prototype, <string>x[0], { get: function () { return this.w(x[0], (x[1] as any)()); }, enumerable: true, configurable: true }));
}


text:
This release adds search functionality to our case library, and lays the groundwork for the days that we host cases from libraries around the world. The full text of all the cases can be searched for any keyword; we're using Postgres `ts_vectors` in a materialized view to keep that fast. The search results view is also able to handle "subindexes" of all the cases from a given library, or later all the cases from a given stack or category. (#161)

![screen shot 2017-12-13 at 16 00 50](https://user-images.githubusercontent.com/4642599/33962226-d1c07862-e01e-11e7-8ffc-61820f29b82d.png)

### Other features

* Sends a weekly usage report to the team, keeping us apprised of how many students and instructors are using our platform, and which cases they're using (#167)
* Updates the platform's French, Japanese, and Chinese translations (#169, #170)
* Allows for the download of a CSV formatted report of all quiz submissions by students in a given deployment (#171)

## Bug fixes and improvements
* Caches assets, greatly speeding up subsequent pages after the first (#165)
* Splits up the JS bundle to lazy load pages the user might never access (#164)
* Preserves the order of quiz questions (#175)
* Handle errors intelligently (#178)
* Updates flow to 0.60.1 (#179)
* Tweaks some visual things (#168, #172)


text:
.. include:: ../README.rst

.. toctree::
   :hidden:

   supermann
   supermann.metrics


text:
/**
 * @fileoverview Rule to flag trailing commas in object literals.
 * @author Ian Christian Myers
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

    "use strict";

     //-------------------------------------------------------------------------
     // Helpers
     //-------------------------------------------------------------------------

    function checkForTrailingComma(node) {
        var tokens = context.getTokens(node),
            secondToLastToken = tokens[tokens.length - 2];

        var items = node.properties || node.elements,
            lastItem = items[items.length - 1];
        // The last token in an object/array literal will always be a closing
        // curly, so we check the second to last token for a comma.
        if(secondToLastToken.value === "," && items.length && lastItem) {
            context.report(lastItem, "Trailing comma.");
        }
    }

    //--------------------------------------------------------------------------
    // Public API
    //--------------------------------------------------------------------------

    return {
        "ObjectExpression": checkForTrailingComma,
        "ArrayExpression": checkForTrailingComma
    };

};


text:
package org.apache.hadoop.hdfs.server.namenode.ha;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.NameNodeProxiesClient;
import org.apache.hadoop.security.UserGroupInformation;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicBoolean;

public class ClientHAProxyFactory<T> implements HAProxyFactory<T> {
  @Override
  @SuppressWarnings("unchecked")
  public T createProxy(Configuration conf, InetSocketAddress nnAddr,
      Class<T> xface, UserGroupInformation ugi, boolean withRetries,
      AtomicBoolean fallbackToSimpleAuth) throws IOException {
    return (T) NameNodeProxiesClient.createNonHAProxyWithClientProtocol(
      nnAddr, conf, ugi, false, fallbackToSimpleAuth);
  }

  @Override
  public T createProxy(Configuration conf, InetSocketAddress nnAddr,
      Class<T> xface, UserGroupInformation ugi, boolean withRetries)
      throws IOException {
    return createProxy(conf, nnAddr, xface, ugi, withRetries, null);
  }
}


text:
<?xml version="1.0" encoding="utf-8"?>

<!--
  ~ Copyright 2012 Red Hat, Inc. and/or its affiliates.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~       http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.4.0//EN"
    "http://google-web-toolkit.googlecode.com/svn/tags/2.5.0/distro-source/core/src/gwt-module.dtd">
<module>

  <!-- Inherit the core Web Toolkit stuff. -->
  <inherits name="com.google.gwt.i18n.I18N"/>
  <inherits name="com.google.gwt.http.HTTP"/>
  <inherits name="com.google.gwt.user.User"/>

  <inherits name='org.uberfire.ext.editor.commons.UberfireCommonsEditorClient'/>
  <inherits name="org.uberfire.ext.properties.editor.PropertiesEditorClient"/>
  <inherits name="org.uberfire.ext.properties.editor.PropertiesEditorAPI"/>

  <inherits name='org.guvnor.common.services.project.GuvnorProjectAPI'/>
  <inherits name="org.kie.workbench.common.widgets.KieWorkbenchWidgetsCommon"/>
  <inherits name="org.kie.workbench.common.widgets.metadata.KieWorkbenchMetadataWidget"/>
  <inherits name="org.kie.workbench.common.services.KieWorkbenchCommonServicesAPI"/>
  <inherits name="org.kie.workbench.common.screens.datamodeller.KieWorkbenchDatamodellerAPI"/>
  <inherits name="org.kie.workbench.common.screens.javaeditor.KieWorkbenchCommonJavaEditorClient"/>

  <source path="client"/>

</module>


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
null

#### Original name
Agaricus micropholis Berk. & Broome, 1871

### Remarks
null


text:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information
namespace DotNetNuke.Web.UI.WebControls
{
    using System;
    using System.Web.UI;

    public class DnnRibbonBarGroupCollection : ControlCollection
    {
        public DnnRibbonBarGroupCollection(Control owner)
            : base(owner)
        {
        }

        public new DnnRibbonBarGroup this[int index]
        {
            get
            {
                return (DnnRibbonBarGroup)base[index];
            }
        }

        public override void Add(Control child)
        {
            if (child is DnnRibbonBarGroup)
            {
                base.Add(child);
            }
            else
            {
                throw new ArgumentException("DnnRibbonBarGroupCollection must contain controls of type DnnRibbonBarGroup");
            }
        }

        public override void AddAt(int index, Control child)
        {
            if (child is DnnRibbonBarGroup)
            {
                base.AddAt(index, child);
            }
            else
            {
                throw new ArgumentException("DnnRibbonBarGroupCollection must contain controls of type DnnRibbonBarGroup");
            }
        }
    }
}


text:
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
exports.PackageManager = void 0;
/**
 * The preferred package manager configuration files to use for registry settings.
 */
var PackageManager;
(function (PackageManager) {
    PackageManager["Cnpm"] = "cnpm";
    PackageManager["Npm"] = "npm";
    PackageManager["Pnpm"] = "pnpm";
    PackageManager["Yarn"] = "yarn";
})(PackageManager = exports.PackageManager || (exports.PackageManager = {}));


text:
namespace jag {
namespace pdf {

// fwd
class DocWriterImpl;
class IndirectObjectRef;
class FontDictionary;

// ensures stable sort for FontDictionary objects, otherwise different runs of
// the same program could produce different pdfs
//
struct stable_font_dict_less
{
    bool operator()(FontDictionary const* lhs, FontDictionary const* rhs) const
    {
        return lhs->id() < rhs->id();
    }
};

//
//
//
class FontManagement
    : public noncopyable
{
public:
    FontManagement(DocWriterImpl& doc);

    PDFFont const& font_load(Char const* fspec);
    PDFFont const& font_load(IFontEx const& fnt);

    IndirectObjectRef font_ref(FontDictionary const& font_dict);
    void output_fonts();
    IndirectObjectRef enc_diff_dict(EnumCharacterEncoding enc);

private:
    PDFFont const& lookup_font(std::auto_ptr<PDFFont>& pdffont);

public: //diagnostics
    size_t dbg_num_fonts() const;
    size_t dbg_num_dicts() const;

private:
    // font dictionary types
    typedef boost::ptr_map<PDFFontDictData, FontDictionary> FontDictMap;

    // pdf font types
    typedef boost::ptr_set<PDFFont> FontMap;
    typedef std::set<FontDictionary*,stable_font_dict_less> FontsToOutput;

private:
    DocWriterImpl&  m_doc;
    FontDictMap m_fontdicts;            ///< Keeps font dictionaries.
    FontMap m_fonts;                    ///< Keeps pdf fonts.
    FontsToOutput m_fonts_to_output;    ///< Fonts being referenced and thus gonna be output
    boost::scoped_array<IndirectObjectRef> m_enc_diffs;
    int m_fdict_id;
};

}} //namespace jag::pdf

#endif //__FONTMANAGEMENT_H_JG_1140__


text:
body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; }
a { color: #00B7FF; }
.action-row { padding: 9px 14px; background-color: #f7f7f9; border-radius: 5px; border: Solid 1px #e1e1e8; margin-bottom: 3px }
.menu-row { padding: 9px 14px; margin-bottom: 3px }
.action-row   { cursor: move; }
.action-delete { cursor: pointer; margin-left: 10px; color: red }
.set { cursor: pointer; }
#set-editor { display: none; }

/* Footer style */
html { position: relative; min-height: 100%; }
body { margin-bottom: 40px; }
.footer { position: absolute; bottom: 0; height: 40px }
.footer-icons a { padding-left: 15px }

.colorSquare { display:inline-block; border-radius:7.5px; width: 15px; height: 15px; margin-right: 4px; border: Solid 1px rgba(33,33,33,0.33); }

.runCounter, .run-sets, .run-actions { text-align: center; }
.run-actions div { font-size: 18pt; }
.curr-set, .curr-action { font-weight: 700; }
#runModal .modal-footer { text-align:center }
.runCountdown, .runCountdownOK { font-size: 80pt; }
.runRound { font-size: 30pt; }
.runSetTimeLeft { font-size: 18pt; }
.runCounter { padding-top: 60px; padding-bottom: 60px; }
.progress-bar { text-align: left; padding-left: 10px; font-weight: 600; }


text:
Liberty 1.0.0 Deployment Warning
================================

Warning Overview
----------------
The Kolla community discovered in the of middle Mitaka development that it
was possible for data loss to occur if the data container is rebuilt.  In
this scenario, Docker pulls a new container, and the new container doesn't
contain the data from the old container.  Kolla stable/liberty and Kolla
1.0.0 are not to be used at this time, as they result in *critical data loss
problems*.

Resolution
----------
To rectify this problem, we plan to have a release of 1.1.0-rc1 on
April 1st, 2016.  We plan our final releae of 1.1.0 on April 15th, 2016.  The
work going into this version will be:

* Move forward to Docker 1.10.z as a minimum dependency.
* Move to named volumes to remove data loss scenario.
* Backport upgrade playbooks from Mitaka so Operators may effectively manage
  OSSA and CVE advisories in their OpenStack cloud without being forced to
  migrate to Mitaka.
* Backport thin-containers for Neutron agents.
* Backport Kolla's docker integration module to remove the hard pin on
  Docker 1.8.2.
* The Kolla community expects the docker containers themselves to be
  minimally modified.


text:
<?php

namespace Google\Service\BeyondCorp;

class CloudSecurityZerotrustApplinkAppConnectorProtoConnectorDetails extends \Google\Model
{
}

// Adding a class alias for backwards compatibility with the previous class name.
class_alias(CloudSecurityZerotrustApplinkAppConnectorProtoConnectorDetails::class, 'Google_Service_BeyondCorp_CloudSecurityZerotrustApplinkAppConnectorProtoConnectorDetails');


text:
namespace Algorithms
{
    using System;
    using System.Collections.Generic;

    public class MergeSorter<T> : ISorter<T> where T : IComparable<T>
    {
        private T[] temp;

        public void Sort(IList<T> collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("Collection is null.");
            }

            this.temp = new T[collection.Count];
            this.MergeSort(collection, 0, collection.Count - 1);
        }

        private void MergeSort(IList<T> collection, int leftIndex, int rightIndex)
        {
            if (leftIndex >= rightIndex)
            {
                return;
            }

            int middleIndex = (leftIndex + rightIndex) / 2;

            this.MergeSort(collection, leftIndex, middleIndex);
            this.MergeSort(collection, middleIndex + 1, rightIndex);

            this.Merge(collection, leftIndex, middleIndex, rightIndex);
        }

        private void Merge(IList<T> collection, int leftIndex, int middleIndex, int rightIndex)
        {
            int tempPointer = leftIndex;
            int leftPointer = leftIndex;
            int rightPointer = middleIndex + 1;

            while (leftPointer <= middleIndex && rightPointer <= rightIndex)
            {
                if (collection[leftPointer].CompareTo(collection[rightPointer]) < 0)
                {
                    this.temp[tempPointer++] = collection[leftPointer++];
                }
                else
                {
                    this.temp[tempPointer++] = collection[rightPointer++];
                }
            }

            while (leftPointer <= middleIndex)
            {
                this.temp[tempPointer++] = collection[leftPointer++];
            }

            while (rightPointer <= rightIndex)
            {
                this.temp[tempPointer++] = collection[rightPointer++];
            }

            for (int index = leftIndex; index <= rightIndex; index++)
            {
                collection[index] = this.temp[index];
            }
        }
    }
}


text:
#pragma once

#include "il2cpp-config.h"

#ifndef _MSC_VER
# include <alloca.h>
#else
# include <malloc.h>
#endif

#include <stdint.h>
#include <assert.h>
#include <exception>

// System.Text.RegularExpressions.BaseMachine/MatchAppendEvaluator
struct MatchAppendEvaluator_t2378778064;
// System.Object
struct Il2CppObject;
// System.Text.RegularExpressions.Match
struct Match_t3797657504;
// System.Text.StringBuilder
struct StringBuilder_t3822575854;
// System.IAsyncResult
struct IAsyncResult_t537683269;
// System.AsyncCallback
struct AsyncCallback_t1363551830;

#include "codegen/il2cpp-codegen.h"
#include "mscorlib_System_Object837106420.h"
#include "mscorlib_System_IntPtr676692020.h"
#include "System_System_Text_RegularExpressions_Match3797657504.h"
#include "mscorlib_System_Text_StringBuilder3822575854.h"
#include "mscorlib_System_AsyncCallback1363551830.h"

// System.Void System.Text.RegularExpressions.BaseMachine/MatchAppendEvaluator::.ctor(System.Object,System.IntPtr)
extern "C"  void MatchAppendEvaluator__ctor_m44201646 (MatchAppendEvaluator_t2378778064 * __this, Il2CppObject * ___object, IntPtr_t ___method, const MethodInfo* method) IL2CPP_METHOD_ATTR;
// System.Void System.Text.RegularExpressions.BaseMachine/MatchAppendEvaluator::Invoke(System.Text.RegularExpressions.Match,System.Text.StringBuilder)
extern "C"  void MatchAppendEvaluator_Invoke_m2910809428 (MatchAppendEvaluator_t2378778064 * __this, Match_t3797657504 * ___match, StringBuilder_t3822575854 * ___sb, const MethodInfo* method) IL2CPP_METHOD_ATTR;
extern "C" void pinvoke_delegate_wrapper_MatchAppendEvaluator_t2378778064(Il2CppObject* delegate, Match_t3797657504 * ___match, StringBuilder_t3822575854 * ___sb);
// System.IAsyncResult System.Text.RegularExpressions.BaseMachine/MatchAppendEvaluator::BeginInvoke(System.Text.RegularExpressions.Match,System.Text.StringBuilder,System.AsyncCallback,System.Object)
extern "C"  Il2CppObject * MatchAppendEvaluator_BeginInvoke_m1979969071 (MatchAppendEvaluator_t2378778064 * __this, Match_t3797657504 * ___match, StringBuilder_t3822575854 * ___sb, AsyncCallback_t1363551830 * ___callback, Il2CppObject * ___object, const MethodInfo* method) IL2CPP_METHOD_ATTR;
// System.Void System.Text.RegularExpressions.BaseMachine/MatchAppendEvaluator::EndInvoke(System.IAsyncResult)
extern "C"  void MatchAppendEvaluator_EndInvoke_m4264062910 (MatchAppendEvaluator_t2378778064 * __this, Il2CppObject * ___result, const MethodInfo* method) IL2CPP_METHOD_ATTR;


text:
void init_sensors();

void loop_sensors();

double measureDepth();

void retrieve_water();

void resetServo();

void pump_stop();

void pump_in();

void pump_out();

int getDist();

long microsecondsToCentimeters(long microseconds);


text:
layout: model
title: English asr_wav2vec2_base_timit_demo_colab3_by_sherry7144 TFWav2Vec2ForCTC from sherry7144
author: John Snow Labs
name: asr_wav2vec2_base_timit_demo_colab3_by_sherry7144
date: 2022-09-24
tags: [wav2vec2, en, audio, open_source, asr]
task: Automatic Speech Recognition
language: en
edition: Spark NLP 4.2.0
spark_version: 3.0
supported: true
annotator: Wav2Vec2ForCTC
article_header:
  type: cover
use_language_switcher: "Python-Scala-Java"
---

## Description

Pretrained Wav2vec2  model, adapted from Hugging Face and curated to provide scalability and production-readiness using Spark NLP.`asr_wav2vec2_base_timit_demo_colab3_by_sherry7144` is a English model originally trained by sherry7144.

NOTE: This model only works on a CPU, if you need to use this model on a GPU device please use asr_wav2vec2_base_timit_demo_colab3_by_sherry7144_gpu

{:.btn-box}
<button class="button button-orange" disabled>Live Demo</button>
<button class="button button-orange" disabled>Open in Colab</button>
[Download](https://s3.amazonaws.com/auxdata.johnsnowlabs.com/public/models/asr_wav2vec2_base_timit_demo_colab3_by_sherry7144_en_4.2.0_3.0_1664041663422.zip){:.button.button-orange.button-orange-trans.arr.button-icon}

## How to use

<div class="tabs-box" markdown="1">
{% include programmingLanguageSelectScalaPythonNLU.html %}
```python

audio_assembler = AudioAssembler() \
    .setInputCol("audio_content") \
    .setOutputCol("audio_assembler")

speech_to_text = Wav2Vec2ForCTC \
    .pretrained("asr_wav2vec2_base_timit_demo_colab3_by_sherry7144", "en")\
    .setInputCols("audio_assembler") \
    .setOutputCol("text")

pipeline = Pipeline(stages=[
  audio_assembler,
  speech_to_text,
])

pipelineModel = pipeline.fit(audioDf)

pipelineDF = pipelineModel.transform(audioDf)
```
```scala

val audioAssembler = new AudioAssembler()
    .setInputCol("audio_content")
    .setOutputCol("audio_assembler")

val speechToText = Wav2Vec2ForCTC
    .pretrained("asr_wav2vec2_base_timit_demo_colab3_by_sherry7144", "en")
    .setInputCols("audio_assembler")
    .setOutputCol("text")

val pipeline = new Pipeline().setStages(Array(audioAssembler, speechToText))

val pipelineModel = pipeline.fit(audioDf)

val pipelineDF = pipelineModel.transform(audioDf)

```
</div>

{:.model-param}
## Model Information

{:.table-model}
|---|---|
|Model Name:|asr_wav2vec2_base_timit_demo_colab3_by_sherry7144|
|Compatibility:|Spark NLP 4.2.0+|
|License:|Open Source|
|Edition:|Official|
|Input Labels:|[audio_assembler]|
|Output Labels:|[text]|
|Language:|en|
|Size:|355.0 MB|


text:
@interface LPMainViewController : UIViewController <LPSceneDelegate, SKPhysicsContactDelegate, AVAudioPlayerDelegate>

@property (nonatomic, strong) LPScene *scene;
@property (nonatomic, strong) UIView *flash;

@property (nonatomic, strong) IBOutlet SKView *gameView;
@property (weak,nonatomic) IBOutlet UIView *getReadyView;

@property (weak,nonatomic) IBOutlet UIView *gameOverView;
@property (weak,nonatomic) IBOutlet UIImageView *medalImageView;
@property (weak,nonatomic) IBOutlet UILabel *currentScore;
@property (weak,nonatomic) IBOutlet UILabel *bestScoreLabel;

@property (nonatomic, strong) IBOutlet UILabel *currentScoreBottom;

@end


text:
Clementine in a Docker container

## Requirements

* Docker 1.2+ (should work fine on 1.0+ but I haven't tried)
* An X11 socket

## Usage

docker run -it \
		-v $HOME/.config/clementine/:/root/.config/clementine \
		-v $HOME/Musicas:/root/Music \
		-v /tmp/.X11-unix:/tmp/.X11-unix \
		-e DISPLAY=$DISPLAY clementine


text:
BEGIN_LEFDEF_PARSER_NAMESPACE

class lefiViaRuleLayer
{
 public:
  lefiViaRuleLayer();
  void Init();

  void Destroy();
  ~lefiViaRuleLayer();
  void clearLayerOverhang();

  void setName(const char* name);
  void setHorizontal();
  void setVertical();
  void setEnclosure(double overhang1, double overhang2);  // 5.5
  void setWidth(double minW, double maxW);
  void setOverhang(double d);
  void setOverhangToEnclosure(double d);  // 5.6
  void setMetalOverhang(double d);
  void setResistance(double d);
  void setSpacing(double x, double y);
  void setRect(double xl, double yl, double xh, double yh);

  int hasDirection() const;
  int hasEnclosure() const;  // 5.5
  int hasWidth() const;
  int hasResistance() const;
  int hasOverhang() const;
  int hasMetalOverhang() const;
  int hasSpacing() const;
  int hasRect() const;

  char* name() const;
  int isHorizontal() const;
  int isVertical() const;
  double enclosureOverhang1() const;  // 5.5
  double enclosureOverhang2() const;  // 5.5
  double widthMin() const;
  double widthMax() const;
  double overhang() const;
  double metalOverhang() const;
  double resistance() const;
  double spacingStepX() const;
  double spacingStepY() const;
  double xl() const;
  double yl() const;
  double xh() const;
  double yh() const;

  // Debug print
  void print(FILE* f) const;

 protected:
  char* name_;
  char direction_;
  double overhang1_;  // 5.5
  double overhang2_;  // 5.5
  int hasWidth_;
  int hasResistance_;
  int hasOverhang_;
  int hasMetalOverhang_;
  int hasSpacing_;
  int hasRect_;
  double widthMin_;
  double widthMax_;
  double overhang_;
  double metalOverhang_;
  double resistance_;
  double spacingStepX_;
  double spacingStepY_;
  double xl_, yl_, xh_, yh_;
};

class lefiViaRule
{
 public:
  lefiViaRule();
  void Init();

  void clear();
  void clearLayerOverhang();

  void Destroy();
  ~lefiViaRule();

  void setGenerate();
  void setDefault();

  // This should clear out all the old stuff.
  void setName(const char* name);

  // Add one of possibly many via names
  void addViaName(const char* name);

  // These routines set a part of the active layer.
  void setRect(double xl, double yl, double xh, double yh);
  void setSpacing(double x, double y);
  void setWidth(double x, double y);
  void setResistance(double d);
  void setOverhang(double d);
  void setOverhangToEnclosure(double d);  // 5.6
  void setMetalOverhang(double d);
  void setVertical();
  void setHorizontal();
  void setEnclosure(double overhang1, double overhang2);
  void addProp(const char* name, const char* value, const char type);
  void addNumProp(const char* name,
                  const double d,
                  const char* value,
                  const char type);

  // This routine sets and creates the active layer.
  void setLayer(const char* name);

  int hasGenerate() const;
  int hasDefault() const;
  char* name() const;

  // There are 2 or 3 layers in a rule.
  // numLayers() tells how many.
  // If a third layer exists then it is the cut layer.
  int numLayers() const;
  lefiViaRuleLayer* layer(int index) const;

  int numVias() const;
  char* viaName(int index) const;

  int numProps() const;
  const char* propName(int index) const;
  const char* propValue(int index) const;
  double propNumber(int index) const;
  char propType(int index) const;
  int propIsNumber(int index) const;
  int propIsString(int index) const;

  // Debug print
  void print(FILE* f) const;

 protected:
  char* name_;
  int nameSize_;

  int hasGenerate_;
  int hasDefault_;

  int numLayers_;
  lefiViaRuleLayer layers_[3];

  int numVias_;
  int viasAllocated_;
  char** vias_;

  int numProps_;
  int propsAllocated_;
  char** names_;
  char** values_;
  double* dvalues_;
  char* types_;
};

END_LEFDEF_PARSER_NAMESPACE

USE_LEFDEF_PARSER_NAMESPACE

#endif


text:
package core.misc

import com.fasterxml.jackson.databind.{ JsonNode, ObjectMapper }
import play.api.http.Status._
import play.api.mvc.{ Result, Results }

import scala.language.postfixOps

/**
 * Created by topy on 10/23/15.
 */
object HanseResult {

  object RetCode extends Enumeration {
    val OK = Value(0)
    val INVALID_ARGUMENTS = Value(100, "Invalid arguments")
    val FORBIDDEN = Value(403, "Forbidden")
    val NOT_FOUND = Value(404, "Resource not found")
    val ALIPAY_REFUND = Value(901, "Ali pay refund need manual operation")
    val UNKNOWN = Value(999, "Unknown error")
  }

  /**
   * 返回标准的HTTP响应
   * @return
   */
  def apply(status: Int = OK, retCode: RetCode.Value = RetCode.OK, data: Option[JsonNode] = None, errorMsg: Option[String] = None): Result = {
    // error信息的生成:如果retCode不为OK,且errorMsg为None,则生成默认的信息
    val errorWithDefault = errorMsg orElse {
      if (retCode != RetCode.OK)
        Some(retCode.toString)
      else
        None
    }
    val mapper = new ObjectMapper()
    val node = mapper.createObjectNode()
    node put ("timestamp", System.currentTimeMillis()) put ("code", retCode.id)

    if (errorWithDefault nonEmpty)
      node put ("error", errorWithDefault.get)
    if (data nonEmpty)
      node set ("result", data.get)

    val contents = mapper.writeValueAsString(node)
    Results.Status(status)(contents).withHeaders("Content-Type" -> "application/json;charset=utf-8")
  }

  // 正常
  def ok(retCode: RetCode.Value = RetCode.OK, data: Option[JsonNode] = None, errorMsg: Option[String] = None): Result =
    HanseResult(OK, retCode, data, errorMsg)

  def notFound(message: Option[String] = None): Result = HanseResult(NOT_FOUND, RetCode.NOT_FOUND, errorMsg = message)

  // 请求中的参数有问题
  def unprocessable(retCode: RetCode.Value = RetCode.INVALID_ARGUMENTS, data: Option[JsonNode] = None,
    errorMsg: Option[String] = None): Result =
    HanseResult(UNPROCESSABLE_ENTITY, retCode, data, errorMsg)

  // 权限错误
  def forbidden(data: Option[JsonNode] = None, errorMsg: Option[String] = None): Result =
    HanseResult(FORBIDDEN, RetCode.FORBIDDEN, data, errorMsg)

  def unprocessableWithMsg(errorMsg: Option[String]): Result =
    HanseResult(UNPROCESSABLE_ENTITY, RetCode.INVALID_ARGUMENTS, None, errorMsg)

  def conflict(errorMsg: Option[String] = None): Result = HanseResult(CONFLICT, RetCode.UNKNOWN, None, errorMsg)
}