text:
package net.ymate.platform.module.wechat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.ymate.platform.commons.util.DateTimeUtils;
import net.ymate.platform.commons.util.UUIDUtils;
import net.ymate.platform.module.wechat.base.*;
import net.ymate.platform.module.wechat.message.OutMessage;
import net.ymate.platform.module.wechat.message.TemplateOutMessage;
import net.ymate.platform.module.wechat.support.DefaultMessageProcessor;
import net.ymate.platform.module.wechat.support.HttpClientHelper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *

 * WeChat
 *

 *

 * 微信公众平台服务接入框架管理器;
 *

 *
 * @author 刘镇(suninformation@163.com)
 * @version 0.0.0
 *

 *

 *          版本号	动作	修改人	修改时间
 *

 *
 *

 *          0.0.0
 *          创建类
 *          刘镇
 *          2014年3月13日上午1:14:17
 *

 *

 */
public class WeChat {

//	private static final Log _LOG = LogFactory.getLog(WeChat.class);

    /**
     * 当前微信公众平台服务接入框架初始化配置对象
     */
    private static IWeChatConfig __CFG_CONFIG;

    private static boolean __IS_INITED;

    private static IAccountDataProvider __dataProvider;

    private static IMessageProcessor __messageProcessor;

    /**
     * 初始化微信公众平台服务接入框架管理器
     *
     * @param config
     * @throws Exception
     */
    public static void initialize(IWeChatConfig config) throws Exception {
        if (!__IS_INITED) {
            if (config == null) {
                throw new NullArgumentException("config");
            }
            if ((__dataProvider = config.getAccountDataProviderImpl()) == null) {
                throw new NullArgumentException("AccountDataProviderImpl");
            }
            __dataProvider.initialize();
            //
            if ((__messageProcessor = config.getMessageProcessorImpl()) == null) {
//				_LOG.debug("Default Message Processor Used");
                if (config.getMessageHandlerImpl() == null) {
                    throw new NullArgumentException("MessageHandlerImpl");
                }
                __messageProcessor = new DefaultMessageProcessor(config.getMessageHandlerImpl());
            }
            __CFG_CONFIG = config;
            __IS_INITED = true;
        }
    }

    /**
     * @return 获取微信开放平台服务接入框架初始化配置对象
     */
    public static IWeChatConfig getConfig() throws Exception {
        __doCheckModuleInited();
        return __CFG_CONFIG;
    }

    /**
     * 销毁模块
     */
    public static void destroy() throws Exception {
        if (__IS_INITED) {
            __IS_INITED = false;
            __dataProvider.destroy();
        }
    }

    /**
     * @return 返回微信多帐号数据提供者
     * @throws Exception
     */
    public static IAccountDataProvider getAccountDataProvider() throws Exception {
        __doCheckModuleInited();
        return __dataProvider;
    }

    /**
     * @return 返回消息处理器
     * @throws Exception
     */
    public static IMessageProcessor getMessageProcessor() throws Exception {
        __doCheckModuleInited();
        return __messageProcessor;
    }

    private static void __doCheckModuleInited() throws Exception {
        if (!__IS_INITED) {
            throw new Exception("YMP Module WeChat was not Inited");
        }
    }

    public static JSONObject __doCheckJsonResult(String jsonStr) throws Exception {
        if (StringUtils.isBlank(jsonStr)) {
            return null;
        }
        JSONObject _result = JSON.parseObject(jsonStr);
        if (_result.containsKey("errcode") && _result.getIntValue("errcode") != 0) {
            throw new Exception("[" + _result.getIntValue("errcode") + "]" + _result.getString("errmsg"));
        }
        return _result;
    }

    private static String __doParamSignatureSort(Map<String, Object> params, boolean encode) {
        StringBuilder _paramSB = new StringBuilder();
        String[] _keys = params.keySet().toArray(new String[0]);
        Arrays.sort(_keys);
        boolean _flag = true;
        for (String _key : _keys) {
            String _value = (String) params.get(_key);
            if (StringUtils.isNotEmpty(_value)) {
                if (_flag) {
                    _flag = false;
                } else {
                    _paramSB.append("&");
                }
                _paramSB.append(_key).append("=");
                if (encode) {
                    try {
                        _paramSB.append(URLEncoder.encode(_value, HttpClientHelper.DEFAULT_CHARSET));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                } else {
                    _paramSB.append(_value);
                }
            }
        }
        return _paramSB.toString();
    }

    /**
     * @param token
     * @param signature
     * @param timestamp
     * @param nonce
     * @return 返回签名检查结果
     */
    public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
        List<String> _params = new ArrayList<String>();
        _params.add(token);
        _params.add(timestamp);
        _params.add(nonce);
        Collections.sort(_params, new Comparator<String>() {
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        return DigestUtils.shaHex(_params.get(0) + _params.get(1) + _params.get(2)).equals(signature);
    }

    /**
     * 生成JSAPI配置对象
     *
     * @param accountId 微信公众帐号ID
     * @param url       使用JSAPI的页面URL地址
     * @return 返回wx.config对象
     * @throws Exception
     */
    public static JSONObject wxCreateJsApiConfig(String accountId, String url) throws Exception {
        String _jsapiTicket = __dataProvider.getJsApiTicket(accountId);
        String _timestamp = DateTimeUtils.currentTimeMillisUTC() + "";
        String _noncestr = UUIDUtils.uuid();
        //
        StringBuilder _signSB = new StringBuilder()
                .append("jsapi_ticket=").append(_jsapiTicket).append("&")
                .append("noncestr=").append(_noncestr).append("&")
                .append("timestamp=").append(_timestamp).append("&")
                .append("url=").append(StringUtils.substringBefore(url, "#"));
        //
        JSONObject _json = new JSONObject();
        _json.put("jsapi_ticket", _jsapiTicket);
        _json.put("timestamp", _timestamp);
        _json.put("nonceStr", _noncestr);
        _json.put("url", url);
        _json.put("signature", DigestUtils.shaHex(_signSB.toString()));
        _json.put("appId", __dataProvider.getAppId(accountId));
        return _json;
    }

    /**
     * @param accountId 微信公众帐号ID
     * @return 获取AccessToken,在有效期内将被缓存,过期后会重新获取新的Token
     * @throws Exception
     */
    public static String wxGetAccessToken(String accountId) throws Exception {
        __doCheckModuleInited();
        if (StringUtils.isBlank(accountId)) {
            throw new NullArgumentException("accountId");
        }
        return __dataProvider.getAccessToken(accountId);
    }

    /**
     * @param accountId 微信公众帐号ID
     * @return 基于安全等考虑,需要获知微信服务器的IP地址列表,以便进行相关限制,可以通过该接口获得微信服务器IP地址列表
     * @throws Exception
     */
    public static String[] wxGetCallbackIP(String accountId) throws Exception {
        __doCheckModuleInited();
        if (StringUtils.isBlank(accountId)) {
            throw new NullArgumentException("accountId");
        }
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.WX_GET_CALLBACK_IP.concat(wxGetAccessToken(accountId))));
        return _json.getJSONArray("ip_list").toArray(new String[0]);
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param mediaId
     * @return 获取媒体资源
     * @throws Exception
     */
    public static IMediaFileWrapper wxMediaGetFile(String accountId, String mediaId) throws Exception {
        __doCheckModuleInited();
        IMediaFileWrapper _wrapper = HttpClientHelper.create().doDownload(WX_API.MEDIA_GET + wxGetAccessToken(accountId) + "&media_id=" + mediaId);
        if (_wrapper.getErrorMsg() != null && StringUtils.isNotEmpty(_wrapper.getErrorMsg())) {
            __doCheckJsonResult(_wrapper.getErrorMsg());
        }
        return _wrapper;
    }

    /**
     * 上传的多媒体文件有格式和大小限制,如下:
     * 图片(image): 128K,支持JPG格式
     * 语音(voice):256K,播放长度不超过60s,支持AMR\MP3格式
     * 视频(video):1MB,支持MP4格式
     * 缩略图(thumb):64KB,支持JPG格式
     * 媒体文件在后台保存时间为3天,即3天后media_id失效
     *
     * @param accountId 微信公众帐号ID
     * @param type
     * @param file
     * @return 上传媒体文件
     * @throws Exception
     */
    public static WxMediaUploadResult wxMediaUploadFile(String accountId, WxMediaType type, File file) throws Exception {
        __doCheckModuleInited();
        if (WxMediaType.NEWS.equals(type)) {
            throw new UnsupportedOperationException("News media type need use wxMediaUploadNews method.");
        }
        // {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}
        // {"type":"TYPE","thubm_media_id":"MEDIA_ID","created_at":123456789}
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doUpload(WX_API.MEDIA_UPLOAD + wxGetAccessToken(accountId) + "&type=" + type.toString().toLowerCase(), file));
        return new WxMediaUploadResult(type, _json.getString("media_id"), _json.getString("thumb_media_id"), _json.getLong("created_at"));
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param articles  图文消息对象集合
     * @return 上传图文消息素材
     * @throws Exception
     */
    public static WxMediaUploadResult wxMediaUploadNews(String accountId, List<WxMassArticle> articles) throws Exception {
        __doCheckModuleInited();
        if (articles == null || articles.isEmpty()) {
            throw new NullArgumentException("articles");
        }
        StringBuilder _paramSB = new StringBuilder("{ \"articles\": [");
        boolean _flag = false;
        for (WxMassArticle article : articles) {
            if (_flag) {
                _paramSB.append(",");
            }
            _paramSB.append(article.toJSON());
            _flag = true;
        }
        _paramSB.append("]}");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MEDIA_UPLOAD_NEWS + wxGetAccessToken(accountId), _paramSB.toString()));
        return new WxMediaUploadResult(WxMediaType.NEWS, _json.getString("media_id"), _json.getString("thumb_media_id"), _json.getLong("created_at"));
    }

    /**
     * @param accountId
     * @param video
     * @return 上传群发用的视频
     * @throws Exception
     */
    public static WxMediaUploadResult wxMediaUploadVideo(String accountId, WxMassVideo video) throws Exception {
        __doCheckModuleInited();
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MEDIA_UPLOAD_VIDEO + wxGetAccessToken(accountId), video.toJSON()));
        return new WxMediaUploadResult(WxMediaType.VIDEO, _json.getString("media_id"), _json.getString("thumb_media_id"), _json.getLong("created_at"));
    }

    /**
     * @param accountId
     * @param groupId
     * @param msgType
     * @param mediaIdOrContent
     * @return 根据分组进行群发并返回消息ID
     * @throws Exception
     */
    public static Long wxMassSendByGroupId(String accountId, String groupId, String msgType, String mediaIdOrContent) throws Exception {
        __doCheckModuleInited();
        StringBuilder _paramSB = new StringBuilder("{");
        _paramSB.append("\"filter\": {").append("\"group_id\":").append("\"").append(groupId).append("\"},");
        //
        String _msgType = WX_MESSAGE.TYPE_MP_NEWS;
        String _bodyAttr = "media_id";
        if (WX_MESSAGE.TYPE_MP_NEWS.equals(msgType)) {
            // default..
        } else if (WX_MESSAGE.TYPE_TEXT.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_TEXT;
            _bodyAttr = "content";
        } else if (WX_MESSAGE.TYPE_VOICE.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_VOICE;
        } else if (WX_MESSAGE.TYPE_IMAGE.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_IMAGE;
        } else if (WX_MESSAGE.TYPE_MP_VIDEO.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_MP_VIDEO;
        } else {
            throw new UnsupportedOperationException("Unsupport Message Type \"" + msgType + "\".");
        }
        _paramSB.append("\"").append(_msgType).append("\": {").append("\"").append(_bodyAttr).append("\":\"").append(mediaIdOrContent).append("\"},");
        _paramSB.append("\"msgtype\": \"").append(_msgType).append("\"}");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MASS_SEND_BY_GROUP + wxGetAccessToken(accountId), _paramSB.toString()));
        return _json.getLong("msg_id");
    }

    /**
     * @param accountId
     * @param openIds
     * @param mediaIdOrContent
     * @return 根据OpenID列表群发并返回消息ID
     * @throws Exception
     */
    public static Long wxMassSendByOpenId(String accountId, List<String> openIds, String msgType, String mediaIdOrContent) throws Exception {
        __doCheckModuleInited();
        if (openIds == null || openIds.isEmpty()) {
            throw new NullArgumentException("openIds");
        }
        StringBuilder _paramSB = new StringBuilder("{");
        _paramSB.append("\"touser\": ").append(JSON.toJSONString(openIds)).append(",");
        //
        String _msgType = WX_MESSAGE.TYPE_MP_NEWS;
        String _bodyAttr = "media_id";
        if (WX_MESSAGE.TYPE_MP_NEWS.equals(msgType)) {
            // default..
        } else if (WX_MESSAGE.TYPE_TEXT.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_TEXT;
            _bodyAttr = "content";
        } else if (WX_MESSAGE.TYPE_VOICE.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_VOICE;
        } else if (WX_MESSAGE.TYPE_IMAGE.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_IMAGE;
        } else if (WX_MESSAGE.TYPE_MP_VIDEO.equals(msgType)) {
            _msgType = WX_MESSAGE.TYPE_MP_VIDEO;
        } else {
            throw new UnsupportedOperationException("Unsupport Message Type \"" + msgType + "\".");
        }
        _paramSB.append("\"").append(_msgType).append("\": {").append("\"").append(_bodyAttr).append("\":\"").append(mediaIdOrContent).append("\"},");
        _paramSB.append("\"msgtype\": \"").append(_msgType).append("\"}");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MASS_SEND_BY_OPENID + wxGetAccessToken(accountId), _paramSB.toString()));
        return _json.getLong("msg_id");
    }

    /**
     * @param accountId
     * @param msgId
     * @return 删除群发(只是将消息的图文详情页失效)
     * @throws Exception
     */
    public static boolean wxMassDelete(String accountId, Long msgId) throws Exception {
        __doCheckModuleInited();
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MASS_DELETE.concat(wxGetAccessToken(accountId)), "{\"msgid\":" + msgId + "}"));
        return 0 == _result.getIntValue("errcode");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param message
     * @return 发送客服消息
     * @throws Exception
     */
    public static String wxMessageSendCustom(String accountId, OutMessage message) throws Exception {
        __doCheckModuleInited();
        return HttpClientHelper.create().doPost(WX_API.MESSAGE_SEND.concat(wxGetAccessToken(accountId)), message.toJSON());
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param message   模板消息对象
     * @return 发送模板消息,若成功则返回msgid
     * @throws Exception
     */
    public static String wxMessageSendTemplate(String accountId, TemplateOutMessage message) throws Exception {
        __doCheckModuleInited();
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MESSAGE_TEMPLATE_SEND.concat(wxGetAccessToken(accountId)), message.toJSON()));
        return _result.getString("msgid");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param openid
     * @param lang      语言(可选)
     * @return 获取用户基本信息
     * @throws Exception
     */
    public static WxUser wxUserGetInfo(String accountId, String openid, WxLangType lang) throws Exception {
        __doCheckModuleInited();
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("access_token", wxGetAccessToken(accountId));
        _params.put("openid", openid);
        if (lang != null) {
            _params.put("lang", lang.toString());
        }
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.USER_INFO, _params));
        return new WxUser(_json.getString("openid"),
                _json.getString("nickname"), _json.getInteger("sex"),
                _json.getString("city"), _json.getString("province"),
                _json.getString("country"), _json.getString("headimgurl"),
                _json.getInteger("subscribe"), _json.getLong("subscribe_time"));
    }

    /**
     * @param accountId   微信公众帐号ID
     * @param next_openid
     * @return 获取关注者列表
     * @throws Exception
     */
    public static WxFollwersResult wxUserGetList(String accountId, String next_openid) throws Exception {
        __doCheckModuleInited();
        Map<String, String> params = new HashMap<String, String>();
        params.put("access_token", wxGetAccessToken(accountId));
        params.put("next_openid", next_openid);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.USER_GET, params));
        List<String> _datas = null;
        if (_json.containsKey("data") && _json.getJSONObject("data").containsKey("openid")) {
            _datas = JSON.parseArray(_json.getJSONObject("data").getJSONArray("openid").toJSONString(), String.class);
        }
        if (_datas == null) {
            _datas = Collections.emptyList();
        }
        return new WxFollwersResult(_json.getLongValue("total"), _json.getIntValue("count"), _datas, _json.getString("next_openid"));
    }

    /**
     * @param accountId
     * @param openid    用户标识
     * @param remark    新的备注名,长度必须小于30字符
     * @return 对指定用户设置备注名
     * @throws Exception
     */
    public static boolean wxUserUpdateRemark(String accountId, String openid, String remark) throws Exception {
        __doCheckModuleInited();
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("access_token", wxGetAccessToken(accountId));
        _params.put("openid", openid);
        _params.put("remark", remark);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.USER_UPDATE_REMARK, _params));
        return 0 == _json.getIntValue("errcode");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param name
     * @return 创建分组
     * @throws Exception
     */
    public static WxGroup wxGroupCreate(String accountId, String name) throws Exception {
        __doCheckModuleInited();
        JSONObject _groupJSON = new JSONObject();
        JSONObject _nameJSON = new JSONObject();
        _nameJSON.put("name", name);
        _groupJSON.put("group", _nameJSON);
        return JSON.toJavaObject(__doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.GROUP_CREATE.concat(wxGetAccessToken(accountId)), _groupJSON.toString())), WxGroup.class);
    }

    /**
     * @param accountId 微信公众帐号ID
     * @return 查询所有分组
     * @throws Exception
     */
    public static List<WxGroup> wxGroupGetList(String accountId) throws Exception {
        __doCheckModuleInited();
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.GROUP_GET.concat(wxGetAccessToken(accountId))));
        if (_json.containsKey("groups")) {
            return JSON.parseArray(_json.getJSONArray("groups").toJSONString(), WxGroup.class);
        }
        return Collections.emptyList();
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param openid
     * @return 查询用户所在分组ID
     * @throws Exception
     */
    public static int wxGroupGetId(String accountId, String openid) throws Exception {
        __doCheckModuleInited();
        JSONObject _openidJSON = new JSONObject();
        _openidJSON.put("openid", openid);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.GROUP_GET_ID.concat(wxGetAccessToken(accountId)), _openidJSON.toString()));
        return _json.getIntValue("groupid");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param id
     * @param name
     * @return 修改分组名
     * @throws Exception
     */
    public static boolean wxGroupUpdate(String accountId, String id, String name) throws Exception {
        __doCheckModuleInited();
        JSONObject _groupJSON = new JSONObject();
        _groupJSON.put("id", id);
        _groupJSON.put("name", name);
        JSONObject _paramJSON = new JSONObject();
        _paramJSON.put("group", _groupJSON);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.GROUP_UPDATE.concat(wxGetAccessToken(accountId)), _paramJSON.toString()));
        return 0 == _json.getIntValue("errcode");
    }

    /**
     * @param accountId  微信公众帐号ID
     * @param openid
     * @param to_groupid
     * @return 移动用户分组
     * @throws Exception
     */
    public static boolean wxGroupMembersMove(String accountId, String openid, String to_groupid) throws Exception {
        __doCheckModuleInited();
        JSONObject _paramJSON = new JSONObject();
        _paramJSON.put("openid", openid);
        _paramJSON.put("to_groupid", to_groupid);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.GROUP_MEMBERS_UPDATE.concat(wxGetAccessToken(accountId)), _paramJSON.toString()));
        return 0 == _json.getIntValue("errcode");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @param menu
     * @return 创建菜单
     * @throws Exception
     */
    public static boolean wxMenuCreate(String accountId, WxMenu menu) throws Exception {
        __doCheckModuleInited();
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MENU_CREATE.concat(wxGetAccessToken(accountId)), JSON.toJSONString(menu)));
        return 0 == _result.getIntValue("errcode");
    }

    /**
     * @param accountId 微信公众帐号ID
     * @return 查询菜单
     * @throws Exception
     */
    public static WxMenu wxMenuGet(String accountId) throws Exception {
        __doCheckModuleInited();
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.MENU_GET.concat(wxGetAccessToken(accountId))));
        return JSON.toJavaObject(_json.getJSONObject("menu"), WxMenu.class);
    }

    /**
     * @param accountId 微信公众帐号ID
     * @return 删除自定义菜单
     * @throws Exception
     */
    public static boolean wxMenuDelete(String accountId) throws Exception {
        __doCheckModuleInited();
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.MENU_DELETE.concat(wxGetAccessToken(accountId))));
        return 0 == _result.getIntValue("errcode");
    }

    /**
     * @param accountId      微信公众帐号ID
     * @param scene_id       场景ID,场景ID若大于100000时自动转换成为临时二维码
     * @param expire_seconds 二维码有效时间,0表示永久保存,最大1800,单位:秒
     * @return 创建二维码Ticket
     * @throws Exception
     */
    public static WxQRCode wxQRCodeCreate(String accountId, int scene_id, int expire_seconds) throws Exception {
        __doCheckModuleInited();
        JSONObject _paramJSON = new JSONObject();
        if (expire_seconds > 0 || scene_id > 100000) {
            _paramJSON.put("action_name", "QR_SCENE");
            _paramJSON.put("expire_seconds", expire_seconds <= 0 ? 1800 : expire_seconds);
        }
        JSONObject _sceneJSON = new JSONObject();
        _sceneJSON.put("scene_id", scene_id);
        JSONObject _infoJSON = new JSONObject();
        _infoJSON.put("scene", _sceneJSON);
        _paramJSON.put("action_info", _infoJSON);
        // {"ticket":"gQG28DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0FuWC1DNmZuVEhvMVp4NDNMRnNRAAIEesLvUQMECAcAAA==","expire_seconds":1800}
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.QRCODE_CREATE.concat(wxGetAccessToken(accountId)), _paramJSON.toString()));
        return new WxQRCode(scene_id, _json.getString("ticket"), _json.getIntValue("expire_seconds"));
    }

    /**
     * @param ticket
     * @return 返回二维码访问URL地址
     */
    public static String wxQRCodeShowURL(String ticket) {
        try {
            return WX_API.QRCODE_SHOW.concat(URLEncoder.encode(ticket, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param accountId    微信公众帐号ID
     * @param needUserInfo 是否弹出授权页面
     * @param state        自定义参数(a-zA-Z0-9)
     * @return 返回微信用户授权URL地址
     * @throws Exception
     */
    public static String wxOAuthGetCodeURL(String accountId, boolean needUserInfo, String state) throws Exception {
        String _appId = __dataProvider.getAppId(accountId);
        if (StringUtils.isBlank(_appId)) {
            throw new NullArgumentException("appId");
        }
        return wxOAuthGetCodeURL(accountId, needUserInfo, state, __dataProvider.getRedirectURI(accountId));
    }

    /**
     * @param accountId    微信公众帐号ID
     * @param needUserInfo 是否弹出授权页面
     * @param state        自定义参数(a-zA-Z0-9)
     * @param redirectURI  自定义重定向地址
     * @return 返回微信用户授权URL地址
     * @throws Exception
     */
    public static String wxOAuthGetCodeURL(String accountId, boolean needUserInfo, String state, String redirectURI) throws Exception {
        __doCheckModuleInited();
        String _appId = __dataProvider.getAppId(accountId);
        if (StringUtils.isBlank(_appId)) {
            throw new NullArgumentException("appId");
        }
        if (StringUtils.isBlank(redirectURI)) {
            throw new NullArgumentException("redirectURI");
        }
        Map<String, Object> _params = new HashMap<String, Object>();
        _params.put("appid", _appId);
        _params.put("response_type", "code");
        _params.put("redirect_uri", URLEncoder.encode(redirectURI, HttpClientHelper.DEFAULT_CHARSET));
        _params.put("scope", needUserInfo ? "snsapi_userinfo" : "snsapi_base");
        _params.put("state", StringUtils.defaultIfEmpty(state, "") + "#wechat_redirect");
        return WX_API.OAUTH_GET_CODE.concat(__doParamSignatureSort(_params, false));
    }

    /**
     * { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
     *
     * @param accountId 微信公众帐号ID
     * @param code
     * @return 通过Code换取网页授权的AccessToken
     * @throws Exception
     */
    public static WxOAuthToken wxOAuthGetToken(String accountId, String code) throws Exception {
        __doCheckModuleInited();
        String _appId = __dataProvider.getAppId(accountId);
        if (StringUtils.isBlank(_appId)) {
            throw new NullArgumentException("appId");
        }
        String _appSecret = __dataProvider.getAppSecret(accountId);
        if (StringUtils.isBlank(_appSecret)) {
            throw new NullArgumentException("appSecret");
        }
        if (StringUtils.isBlank(code)) {
            throw new NullArgumentException("code");
        }
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("appid", _appId);
        _params.put("secret", _appSecret);
        _params.put("code", code);
        _params.put("grant_type", "authorization_code");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.OAUTH_ACCESS_TOKEN, _params));
        return new WxOAuthToken(_json.getString("access_token"), _json.getIntValue("expires_in"), _json.getString("refresh_token"), _json.getString("openid"), _json.getString("scope"));
    }

    /**
     * @param accountId    微信公众帐号ID
     * @param refreshToken 哪个想刷就刷哪个~
     * @return 刷新AccessToken
     * @throws Exception
     */
    public static WxOAuthToken wxOAuthRefreshToken(String accountId, String refreshToken) throws Exception {
        __doCheckModuleInited();
        String _appId = __dataProvider.getAppId(accountId);
        if (StringUtils.isBlank(_appId)) {
            throw new NullArgumentException("appId");
        }
        if (StringUtils.isBlank(refreshToken)) {
            throw new NullArgumentException("refreshToken");
        }
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("appid", _appId);
        _params.put("grant_type", "refresh_token");
        _params.put("refresh_token", refreshToken);
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.OAUTH_REFRESH_TOKEN, _params));
        return new WxOAuthToken(_json.getString("access_token"), _json.getIntValue("expires_in"), _json.getString("refresh_token"), _json.getString("openid"), _json.getString("scope"));
    }

    /**
     * @param openid
     * @param lang   语言(可选)
     * @return 拉取用户信息
     * @throws Exception
     */
    public static WxOAuthUser wxOAuthUserGetInfo(String oauthAccessToken, String openid, WxLangType lang) throws Exception {
        __doCheckModuleInited();
        if (StringUtils.isBlank(oauthAccessToken)) {
            throw new NullArgumentException("oauthAccessToken");
        }
        if (StringUtils.isBlank(openid)) {
            throw new NullArgumentException("openid");
        }
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("openid", openid);
        if (lang != null) {
            _params.put("lang", lang.toString());
        }
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.OAUTH_USER_INFO.concat(oauthAccessToken), _params));
        return new WxOAuthUser(_json.getString("openid"),
                _json.getString("unionid"),
                _json.getString("nickname"), _json.getInteger("sex"),
                _json.getString("city"), _json.getString("province"),
                _json.getString("country"), _json.getString("headimgurl"),
                JSON.parseArray(_json.getJSONArray("privilege").toJSONString(), String.class));
    }

    /**
     * 检验授权凭证(access_token)是否有效
     *
     * @param oauthAccessToken 网页授权接口调用凭证
     * @param openid           用户的唯一标识
     * @return true / false
     * @throws Exception
     */
    public static boolean wxOAuthAuthAccessToken(String oauthAccessToken, String openid) throws Exception {
        __doCheckModuleInited();
        if (StringUtils.isBlank(oauthAccessToken)) {
            throw new NullArgumentException("oauthAccessToken");
        }
        if (StringUtils.isBlank(openid)) {
            throw new NullArgumentException("openid");
        }
        Map<String, String> _params = new HashMap<String, String>();
        _params.put("openid", openid);
        try {
            __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.OAUTH_AUTH_ACCESS_TOKEN.concat(oauthAccessToken), _params));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * @param accountId
     * @param longUrl   需要转换的长链接
     * @return 长链接转成短链接
     * @throws Exception
     */
    public static String wxShortUrl(String accountId, String longUrl) throws Exception {
        __doCheckModuleInited();
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doGet(WX_API.SHORT_URL.concat(wxGetAccessToken(accountId))));
        return _json.getString("short_url");
    }

    /**
     * 上传永久图文素材
     *
     * @param accountId
     * @param articles
     * @return
     * @throws Exception
     */
    public static String wxMaterialAddNews(String accountId, List<WxMassArticle> articles) throws Exception {
        __doCheckModuleInited();
        if (articles == null || articles.isEmpty()) {
            throw new NullArgumentException("articles");
        }
        StringBuilder _paramSB = new StringBuilder("{ \"articles\": [");
        boolean _flag = false;
        for (WxMassArticle article : articles) {
            if (_flag) {
                _paramSB.append(",");
            }
            _paramSB.append(article.toJSON());
            _flag = true;
        }
        _paramSB.append("]}");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_ADD_NEWS + wxGetAccessToken(accountId), _paramSB.toString()));
        return _json.getString("media_id");
    }

    /**
     * 上传永久媒体素材(不包括视频)
     *
     * @param accountId
     * @param type
     * @param file
     * @return
     * @throws Exception
     */
    public static String wxMaterialAddNews(String accountId, WxMediaType type, File file) throws Exception {
        __doCheckModuleInited();
        if (WxMediaType.NEWS.equals(type)) {
            throw new UnsupportedOperationException("News media type need use wxMediaUploadNews method.");
        } else if (WxMediaType.VIDEO.equals(type) || WxMediaType.SHORT_VIDEO.equals(type)) {
            throw new UnsupportedOperationException("Unsupport Video and Short Video");
        }
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doUpload(WX_API.MATERIAL_ADD_MATERIAL + wxGetAccessToken(accountId) + "&type=" + type.toString().toLowerCase(), file));
        return _json.getString("media_id");
    }

    /**
     * 上传永久视频素材
     *
     * @param accountId
     * @param title
     * @param introduction
     * @param file
     * @return
     * @throws Exception
     */
    public static String wxMaterialAddNews(String accountId, String title, String introduction, File file) throws Exception {
        __doCheckModuleInited();
        String _description = URLEncoder.encode("{\"title\":\"" + title + "\", \"introduction\":\"" + introduction + "\"}", "UTF-8");
        JSONObject _json = __doCheckJsonResult(HttpClientHelper.create().doUpload(WX_API.MATERIAL_ADD_MATERIAL + wxGetAccessToken(accountId) + "&description=" + _description + "&type=" + WxMediaType.VIDEO.toString().toLowerCase(), file));
        return _json.getString("media_id");
    }

    /**
     * 删除永久素材
     *
     * @param accountId
     * @param mediaId
     * @return
     * @throws Exception
     */
    public static boolean wxMaterialDelete(String accountId, String mediaId) throws Exception {
        __doCheckModuleInited();
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_DEL_MATERIAL.concat(wxGetAccessToken(accountId)), "{\"media_id\":\"" + mediaId + "\"}"));
        return 0 == _result.getIntValue("errcode");
    }

    /**
     * 获取素材列表
     *
     * @param accountId
     * @param type
     * @param offset
     * @param count
     * @return
     * @throws Exception
     */
    public static WxMaterialResult wxMaterialGetNews(String accountId, WxMediaType type, int offset, int count) throws Exception {
        __doCheckModuleInited();
        String _params = "{\"type\":\"" + type.toString().toLowerCase() + "\", \"offset\":" + offset + ", \"count\":" + count + "}";
        JSONObject _resultJSON = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_BATCH_GET.concat(wxGetAccessToken(accountId)), _params));
        if (_resultJSON != null) {
            WxMaterialResult _result = JSON.toJavaObject(_resultJSON, WxMaterialResult.class);
            return _result;
        }
        return null;
    }

    /**
     * 获取永久素材(图文和视频)
     *
     * @param accountId
     * @param mediaId
     * @return
     * @throws Exception
     */
    public static WxNewsItem wxMaterialNewOrVideoGet(String accountId, String mediaId) throws Exception {
        __doCheckModuleInited();
        JSONObject _resultJSON = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_GET_MATERIAL.concat(wxGetAccessToken(accountId)), "{\"media_id\":\"" + mediaId + "\"}"));
        if (_resultJSON != null) {
            WxNewsItem _result = JSON.toJavaObject(_resultJSON, WxNewsItem.class);
            return _result;
        }
        return null;
    }

    /**
     * 获取永久素材(非图文和非视频)
     *
     * @param accountId
     * @param mediaId
     * @return
     * @throws Exception
     */
    public static IMediaFileWrapper wxMaterialFileGet(String accountId, String mediaId) throws Exception {
        __doCheckModuleInited();
        return HttpClientHelper.create().doDownload(WX_API.MATERIAL_GET_MATERIAL.concat(wxGetAccessToken(accountId)), "{\"media_id\":\"" + mediaId + "\"}");
    }

    /**
     * 修改永久图文素材
     *
     * @param accountId
     * @param mediaId
     * @param index
     * @param article
     * @return
     * @throws Exception
     */
    public static boolean wxMaterialUpdate(String accountId, String mediaId, int index, WxMassArticle article) throws Exception {
        __doCheckModuleInited();
        JSONObject _params = new JSONObject();
        _params.put("media_id", mediaId);
        _params.put("index", index);
        _params.put("articles", JSON.toJSON(article));
        JSONObject _result = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_UPDATE_NEWS.concat(wxGetAccessToken(accountId)), _params.toJSONString()));
        return 0 == _result.getIntValue("errcode");
    }

    /**
     * 获取素材总数
     *
     * @param accountId
     * @return
     * @throws Exception
     */
    public static WxMaterialCount wxMaterialCount(String accountId) throws Exception {
        __doCheckModuleInited();
        JSONObject _resultJSON = __doCheckJsonResult(HttpClientHelper.create().doPost(WX_API.MATERIAL_GET_COUNT.concat(wxGetAccessToken(accountId)), ""));
        if (_resultJSON != null) {
            WxMaterialCount _result = JSON.toJavaObject(_resultJSON, WxMaterialCount.class);
            return _result;
        }
        return null;
    }

    /**
     * @param request  Http请求对象
     * @param needVer5 是否需要判断版本大于5.0
     * @return 判断当前是否在微信环境
     */
    public static boolean isInWeChat(HttpServletRequest request, boolean needVer5) {
        String userAgent = request.getHeader("User-Agent");
        if (StringUtils.isNotBlank(userAgent)) {
            Pattern p = Pattern.compile("MicroMessenger/(\\d+).+");
            Matcher m = p.matcher(userAgent);
            String version = null;
            if (m.find()) {
                version = m.group(1);
            }
            if (null != version) {
                if (needVer5) {
                    return NumberUtils.toInt(version) >= 5;
                }
                return true;
            }
        }
        return false;
    }

    /**
     *

     * WX_MESSAGE
     *

     *

     * 微信消息类型
     *

     */
    public static class WX_MESSAGE {
        public final static String TYPE_TEXT = "text";
        public final static String TYPE_LOCATION = "location";
        public final static String TYPE_IMAGE = "image";
        public final static String TYPE_LINK = "link";
        public final static String TYPE_VOICE = "voice";
        public final static String TYPE_EVENT = "event";
        public final static String TYPE_VIDEO = "video";
        public final static String TYPE_SHORT_VIDEO = "shortvideo";

        public final static String TYPE_NEWS = "news";
        public final static String TYPE_MP_NEWS = "mpnews"; // 此类型仅用于群发图文
        public final static String TYPE_MP_VIDEO = "mpvideo"; // 此类型仅用于群发视频
        public final static String TYPE_MUSIC = "music";

        public final static String EVENT_LOCATION = "LOCATION";
        public final static String EVENT_SCAN = "SCAN";
        public final static String EVENT_SUBSCRIBE = "subscribe";
        public final static String EVENT_UNSUBSCRIBE = "unsubscribe";

        public final static String EVENT_CLICK = "click";
        public final static String EVENT_VIEW = "view";

        public final static String EVENT_MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH";
        public final static String EVENT_TEMPLATE_SEND_JOB_FINISH = "TEMPLATESENDJOBFINISH";
    }

    /**
     *

     * WxMediaType
     *

     *

     * 微信媒体资源类型
     *

     */
    public static enum WxMediaType {
        IMAGE, VOICE, VIDEO, SHORT_VIDEO, THUMB, NEWS
    }

    /**
     *

     * WxLangType
     *

     *

     * 微信支持的语言
     *

     */
    public static enum WxLangType {
        zh_CN, zh_TW, en
    }

    /**
     *

     * WX_API
     *

     *

     * 微信API地址
     *

     */
    public static class WX_API {
        public static final String WX_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
        public static final String WX_GET_CALLBACK_IP = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=";

        public static final String MEDIA_GET = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=";
        public static final String MEDIA_UPLOAD = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=";

        public static final String MEDIA_UPLOAD_NEWS = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=";
        public static final String MEDIA_UPLOAD_VIDEO = "http://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=";

        public static final String GROUP_CREATE = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token=";
        public static final String GROUP_GET = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token=";
        public static final String GROUP_GET_ID = "https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=";
        public static final String GROUP_UPDATE = "https://api.weixin.qq.com/cgi-bin/groups/update?access_token=";
        public static final String GROUP_MEMBERS_UPDATE = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=";

        public static final String USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info";
        public static final String USER_GET = "https://api.weixin.qq.com/cgi-bin/user/get";
        public static final String USER_UPDATE_REMARK = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=";

        public static final String MENU_CREATE = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
        public static final String MENU_GET = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=";
        public static final String MENU_DELETE = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";

        public static final String QRCODE_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
        public static final String QRCODE_SHOW = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";

        public static final String MESSAGE_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";

        public static final String MESSAGE_TEMPLATE_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";

        public static final String MASS_SEND_BY_GROUP = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=";
        public static final String MASS_SEND_BY_OPENID = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=";
        public static final String MASS_DELETE = "https://api.weixin.qq.com//cgi-bin/message/mass/delete?access_token=";

        public static final String OAUTH_GET_CODE = "https://open.weixin.qq.com/connect/oauth2/authorize?";
        public static final String OAUTH_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";
        public static final String OAUTH_REFRESH_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
        public static final String OAUTH_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=";
        public static final String OAUTH_AUTH_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/auth?access_token=";

        public static final String OAUTH_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=";

        public static final String SHORT_URL = "https://api.weixin.qq.com/cgi-bin/shorturl?action=long2short&access_token=";

        // 新增永久图文素材
        public static final String MATERIAL_ADD_NEWS = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=";
        // 新增其他类型永久素材
        public static final String MATERIAL_ADD_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=";
        // 获取永久素材
        public static final String MATERIAL_GET_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=";
        // 删除永久素材
        public static final String MATERIAL_DEL_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=";
        // 修改永久图文素材
        public static final String MATERIAL_UPDATE_NEWS = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=";
        // 获取素材总数
        public static final String MATERIAL_GET_COUNT = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=";
        // 获取素材列表
        public static final String MATERIAL_BATCH_GET = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=";
    }

}


text:
<?php
namespace Bpost;

use TijsVerkoyen\Bpost\Bpost\Order\Address;
use TijsVerkoyen\Bpost\Bpost\Order\Sender;

class SenderTest extends \PHPUnit_Framework_TestCase
{
    /**
     * Create a generic DOM Document
     *
     * @return \DOMDocument
     */
    private static function createDomDocument()
    {
        $document = new \DOMDocument('1.0', 'utf-8');
        $document->preserveWhiteSpace = false;
        $document->formatOutput = true;

        return $document;
    }

    /**
     * Tests Sender->toXML
     */
    public function testToXML()
    {
        $data = array(
            'name' => 'Tijs Verkoyen',
            'company' => 'Sumo Coders',
            'address' => array(
                'streetName' => 'Afrikalaan',
                'number' => '289',
                'box' => '3',
                'postalCode' => '9000',
                'locality' => 'Gent',
                'countryCode' => 'BE',
            ),
            'emailAddress' => 'bpost@verkoyen.eu',
            'phoneNumber' => '+32 9 395 02 51',
        );

        $expectedDocument = self::createDomDocument();
        $sender = $expectedDocument->createElement('sender');
        foreach ($data as $key => $value) {
            $key = 'common:' . $key;
            if ($key == 'common:address') {
                $address = $expectedDocument->createElement($key);
                foreach ($value as $key2 => $value2) {
                    $key2 = 'common:' . $key2;
                    $address->appendChild(
                        $expectedDocument->createElement($key2, $value2)
                    );
                }
                $sender->appendChild($address);
            } else {
                $sender->appendChild(
                    $expectedDocument->createElement($key, $value)
                );
            }
        }
        $expectedDocument->appendChild($sender);

        $actualDocument = self::createDomDocument();
        $address = new Address(
            $data['address']['streetName'],
            $data['address']['number'],
            $data['address']['box'],
            $data['address']['postalCode'],
            $data['address']['locality'],
            $data['address']['countryCode']
        );
        $sender = new Sender();
        $sender->setName($data['name']);
        $sender->setCompany($data['company']);
        $sender->setAddress($address);
        $sender->setEmailAddress($data['emailAddress']);
        $sender->setPhoneNumber($data['phoneNumber']);
        $actualDocument->appendChild(
            $sender->toXML($actualDocument, null)
        );

        $this->assertSame($expectedDocument->saveXML(), $actualDocument->saveXML());
    }

    /**
     * Test validation in the setters
     */
    public function testFaultyProperties()
    {
        $sender = new Sender();

        try {
            $sender->setEmailAddress(str_repeat('a', 51));
        } catch (\Exception $e) {
            $this->assertInstanceOf('TijsVerkoyen\Bpost\Exception', $e);
            $this->assertSame('Invalid length, maximum is 50.', $e->getMessage());
        }

        try {
            $sender->setPhoneNumber(str_repeat('a', 21));
        } catch (\Exception $e) {
            $this->assertInstanceOf('TijsVerkoyen\Bpost\Exception', $e);
            $this->assertSame('Invalid length, maximum is 20.', $e->getMessage());
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
<ion-view title="Mobile Table Inspector">
	<ion-content>
		<ion-list>
		  <ion-item class="item item-button-right" ng-click="showTable(table.Name);" ng-repeat="table in tables">
		  	<span>{{table.Name}}</span>
		    <button ng-click="syncTable(table.Name); $event.stopPropagation();" class="button button-positive" ng-show="(table.Name.indexOf('__ap') >= 0 || table.Name.indexOf('__mc') >= 0) && table.Name.indexOf('SnapShot') < 0 && recovery">
		    	Force Sync
		    </button>
		    <button ng-click="syncTable(table.Name); $event.stopPropagation();" class="button button-positive" ng-show="(table.Name.indexOf('__ap') >= 0 || table.Name.indexOf('__mc') >= 0) && table.Name.indexOf('SnapShot') < 0 && ! recovery" style="right:160px !important;">
		    	Sync
		    </button>
		    <button ng-click="saveTableToML(table.Name); $event.stopPropagation();" class="button button-energized" ng-show="table.Name.indexOf('SnapShot') < 0 && table.Name.indexOf('syncLib') < 0 && ! recovery">
		    	Save to ML
		    </button>
		  </ion-item>
		</ion-list>
  </ion-content>
</ion-view>


text:
package ch.rasc.bsoncodec.test.pojo;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bson.types.ObjectId;

import ch.rasc.bsoncodec.annotation.BsonDocument;

@BsonDocument
public class StringPojo {

	private ObjectId id;

	private String scalar;
	private String[] array;
	private String[][] array2;
	private List<String> list;
	private Set<String> set;
	private Map<Integer, String> map;

	public ObjectId getId() {
		return this.id;
	}

	public void setId(ObjectId id) {
		this.id = id;
	}

	public String getScalar() {
		return this.scalar;
	}

	public void setScalar(String scalar) {
		this.scalar = scalar;
	}

	public String[] getArray() {
		return this.array;
	}

	public void setArray(String[] array) {
		this.array = array;
	}

	public String[][] getArray2() {
		return this.array2;
	}

	public void setArray2(String[][] array2) {
		this.array2 = array2;
	}

	public List<String> getList() {
		return this.list;
	}

	public void setList(List<String> list) {
		this.list = list;
	}

	public Set<String> getSet() {
		return this.set;
	}

	public void setSet(Set<String> set) {
		this.set = set;
	}

	public Map<Integer, String> getMap() {
		return this.map;
	}

	public void setMap(Map<Integer, String> map) {
		this.map = map;
	}

}


text:
(function (left, right) {
  if (right != null && right[Symbol.hasInstance]) {
    return right[Symbol.hasInstance](left);
  } else {
    return left instanceof right;
  }
});


text:
package org.schedoscope.scheduler.actors

import akka.actor.ActorSystem
import akka.testkit.{ImplicitSender, TestActorRef, TestKit, TestProbe}
import org.scalatest.mock.MockitoSugar
import org.scalatest.{BeforeAndAfterAll, FlatSpecLike, Matchers}
import org.schedoscope.{Settings, TestUtils}
import org.schedoscope.dsl.{ExternalView, transformations}
import org.schedoscope.dsl.Parameter._
import org.schedoscope.dsl.transformations._
import org.schedoscope.scheduler.driver.{DriverRunHandle, DriverRunSucceeded}
import org.schedoscope.scheduler.messages._
import org.schedoscope.scheduler.states.CreatedByViewManager
import test.views.{ProductBrand, ViewWithExternalDeps}

class TableActorSpec extends TestKit(ActorSystem("schedoscope"))
  with ImplicitSender
  with FlatSpecLike
  with Matchers
  with BeforeAndAfterAll
  with MockitoSugar {

  override def afterAll() = {
    TestKit.shutdownActorSystem(system)
  }

  trait TableActorTest {
    lazy val settings = Settings()

    val viewManagerActor = TestProbe()

    val transformationManagerActor = TestProbe()
    val schemaManagerRouter = TestProbe()
    val viewSchedulingListenerManagerActor = TestProbe()

    val brandViewActor = TestProbe()
    val productViewActor = TestProbe()

    val view = ProductBrand(p("ec0106"), p("2014"), p("01"), p("01"))
    val brandDependency = view.dependencies.head
    val productDependency = view.dependencies(1)

    val viewActor = TestActorRef(TableActor.props(
      Map(view -> CreatedByViewManager(view)),
      settings,
      Map(brandDependency.tableName -> brandViewActor.ref,
        productDependency.tableName -> productViewActor.ref),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    def materializeProductBrandView(pbView: ProductBrand): Unit = {
      val brandDep = pbView.brand()
      val productDep = pbView.product()

      viewActor ! CommandForView(None, pbView, MaterializeView())

      brandViewActor.expectMsg(CommandForView(Some(pbView), brandDep, MaterializeView()))
      brandViewActor.reply(CommandForView(Some(brandDep),
        pbView,
        ViewMaterialized(brandDep, incomplete = false, 1L, errors = false)))

      productViewActor.expectMsg(CommandForView(Some(pbView), productDep, MaterializeView()))
      productViewActor.reply(CommandForView(Some(productDep),
        pbView,
        ViewMaterialized(productDep, incomplete = false, 1L, errors = false)))

      transformationManagerActor.expectMsg(pbView)
      val success = CommandForView(None, pbView, TransformationSuccess(mock[DriverRunHandle[HiveTransformation]],
        mock[DriverRunSucceeded[HiveTransformation]],
        true))
      transformationManagerActor.reply(success)

      expectMsgType[ViewMaterialized]

      transformationManagerActor.expectMsg(Touch(pbView.fullPath + "/_SUCCESS"))
    }
  }

  trait TableActorStubbingTest extends TableActorTest {
    override lazy val settings = TestUtils.createSettings("schedoscope.development.enabled=true",
      "schedoscope.development.viewUrls = [test.views/ProductBrand]")
  }

  trait TableActorNestedStubbingTest extends TableActorTest {
    override lazy val settings = TestUtils.createSettings("schedoscope.development.enabled=true",
      "schedoscope.development.viewUrls = [test.views/ProductBrand, test.views/Product]")
  }

  trait TableActorStubbingSshTest extends TableActorTest {
    override lazy val settings = TestUtils.createSettings("schedoscope.development.enabled=true",
      "schedoscope.development.viewUrls = [test.views/ProductBrand]",
      "schedoscope.development.sshEnabled = true",
      "schedoscope.development.sshTarget = bambam")
  }

  "The TableActor" should "send materialize to deps" in new TableActorTest {
    viewActor ! CommandForView(None, view, MaterializeView())
    info(s"${view.tableName}")

    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeView()))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))
  }

  it should "add new dependencies" in new TableActorTest {
    val emptyDepsViewActor = system.actorOf(TableActor.props(
      Map(view -> CreatedByViewManager(view)),
      Settings(),
      Map(),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    emptyDepsViewActor ! NewTableActorRef(brandDependency, brandViewActor.ref)
    emptyDepsViewActor ! NewTableActorRef(productDependency, productViewActor.ref)

    emptyDepsViewActor ! CommandForView(None, view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeView()))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))

  }

  it should "ask if he doesn't know another ViewActor" in new TableActorTest {
    val emptyDepsViewActor = system.actorOf(TableActor.props(
      Map(view -> CreatedByViewManager(view)),
      Settings(),
      Map(),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    emptyDepsViewActor ! CommandForView(None, view, MaterializeView())

    viewManagerActor.expectMsg(DelegateMessageToView(brandDependency,
      CommandForView(Some(view), brandDependency, MaterializeView())))
    viewManagerActor.expectMsg(DelegateMessageToView(productDependency,
      CommandForView(Some(view), productDependency, MaterializeView())))
  }

  it should "send a message to the transformation actor when ready to transform" in new TableActorTest {
    viewActor ! CommandForView(None, view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeView()))
    brandViewActor.reply(CommandForView(Some(brandDependency),
      view,
      ViewMaterialized(brandDependency, incomplete = false, 1L, errors = false)))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))
    productViewActor.reply(CommandForView(Some(productDependency),
      view,
      ViewMaterialized(productDependency, incomplete = false, 1L, errors = false)))

    transformationManagerActor.expectMsg(view)
  }

  it should "materialize a view successfully" in new TableActorTest {

    viewActor ! CommandForView(None, view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeView()))
    brandViewActor.reply(CommandForView(Some(brandDependency),
      view,
      ViewMaterialized(brandDependency, incomplete = false, 1L, errors = false)))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))
    productViewActor.reply(CommandForView(Some(productDependency),
      view,
      ViewMaterialized(productDependency, incomplete = false, 1L, errors = false)))

    transformationManagerActor.expectMsg(view)
    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[HiveTransformation]],
      mock[DriverRunSucceeded[HiveTransformation]],
      true))
    transformationManagerActor.reply(success)

    expectMsgType[ViewMaterialized]
  }

  it should "materialize a view successfully (message from view)" in new TableActorTest {

    viewActor ! CommandForView(Some(brandDependency), view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeView()))
    brandViewActor.reply(CommandForView(Some(brandDependency),
      view,
      ViewMaterialized(brandDependency, incomplete = false, 1L, errors = false)))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))
    productViewActor.reply(CommandForView(Some(productDependency),
      view,
      ViewMaterialized(productDependency, incomplete = false, 1L, errors = false)))

    transformationManagerActor.expectMsg(view)
    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[HiveTransformation]],
      mock[DriverRunSucceeded[HiveTransformation]],
      true))
    transformationManagerActor.reply(success)

    //the view should reply with an command for view if the materialize message came from a view
    expectMsgType[CommandForView]
  }

  it should "materialize an external view" in new TableActorTest {

    val viewWithExt = ViewWithExternalDeps(p("ec0101"), p("2016"), p("11"), p("07"))
    val extView = viewWithExt.dependencies.head
    val extActor = TestProbe()
    val actorWithExt = system.actorOf(TableActor.props(
      Map(viewWithExt -> CreatedByViewManager(viewWithExt)),
      Settings(),
      Map(extView.tableName -> extActor.ref),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    actorWithExt ! CommandForView(None, viewWithExt, MaterializeView())
    extActor.expectMsg(CommandForView(Some(viewWithExt), extView, MaterializeExternalView()))
    extActor.reply(CommandForView(Some(extView), viewWithExt, ViewMaterialized(extView, incomplete = false, 1L, errors = false)))
    transformationManagerActor.expectMsg(viewWithExt)
    val success = TransformationSuccess(mock[DriverRunHandle[HiveTransformation]], mock[DriverRunSucceeded[HiveTransformation]], true)
    transformationManagerActor.reply(CommandForView(None, viewWithExt, success))

    expectMsgType[ViewMaterialized]
  }

  it should "materialize a stubbed view successfully" in new TableActorTest {

    viewActor ! CommandForView(None, view, MaterializeViewAsStub())

    //dependencies should not be notified
    brandViewActor.expectNoMsg()
    productViewActor.expectNoMsg()

    val transformCommand = transformationManagerActor.expectMsg(view)
    transformCommand.transformation() shouldBe a[DistCpTransformation]

    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[MapreduceBaseTransformation]],
      mock[DriverRunSucceeded[MapreduceBaseTransformation]],
      true))
    transformationManagerActor.reply(success)

    expectMsgType[ViewMaterialized]
  }

  it should "materialize a stubbed view over ssh successfully" in new TableActorStubbingSshTest {

    viewActor ! CommandForView(None, view, MaterializeViewAsStub())

    //dependencies should not be notified
    brandViewActor.expectNoMsg()
    productViewActor.expectNoMsg()

    val transformCommand = transformationManagerActor.expectMsg(view)
    transformCommand.transformation() shouldBe a[ShellTransformation]

    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[ShellTransformation]],
      mock[DriverRunSucceeded[ShellTransformation]],
      true))
    transformationManagerActor.reply(success)

    expectMsgType[ViewMaterialized]
  }

  it should "stub its dependencies if configured" in new TableActorStubbingTest {
    viewActor ! CommandForView(None, view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeViewAsStub()))
    brandViewActor.reply(CommandForView(Some(brandDependency),
      view,
      ViewMaterialized(brandDependency, incomplete = false, 1L, errors = false)))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeViewAsStub()))
    productViewActor.reply(CommandForView(Some(productDependency),
      view,
      ViewMaterialized(productDependency, incomplete = false, 1L, errors = false)))

    transformationManagerActor.expectMsg(view)
    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[HiveTransformation]],
      mock[DriverRunSucceeded[HiveTransformation]],
      true))
    transformationManagerActor.reply(success)

    expectMsgType[ViewMaterialized]
  }

  it should "not stub a dependency if in stub mode" in new TableActorNestedStubbingTest {
    viewActor ! CommandForView(None, view, MaterializeView())
    brandViewActor.expectMsg(CommandForView(Some(view), brandDependency, MaterializeViewAsStub()))
    brandViewActor.reply(CommandForView(Some(brandDependency),
      view,
      ViewMaterialized(brandDependency, incomplete = false, 1L, errors = false)))
    productViewActor.expectMsg(CommandForView(Some(view), productDependency, MaterializeView()))
    productViewActor.reply(CommandForView(Some(productDependency),
      view,
      ViewMaterialized(productDependency, incomplete = false, 1L, errors = false)))

    transformationManagerActor.expectMsg(view)
    val success = CommandForView(None, view, TransformationSuccess(mock[DriverRunHandle[HiveTransformation]],
      mock[DriverRunSucceeded[HiveTransformation]],
      true))
    transformationManagerActor.reply(success)

    expectMsgType[ViewMaterialized]
  }

  it should "initialize a new view" in new TableActorTest {
    val newView = ProductBrand(p("ec0106"), p("2017"), p("12"), p("13"))
    viewActor ! InitializeViews(List(newView))
    schemaManagerRouter.expectMsg(AddPartitions(List(newView)))
    schemaManagerRouter.reply(TransformationMetadata(Map(newView -> ("test", 1L))))
  }

  it should "materialize multiple views" in new TableActorTest {
    //start two new views
    val newView = ProductBrand(p("ec0106"), p("2017"), p("12"), p("13"))
    viewActor ! InitializeViews(List(newView))
    schemaManagerRouter.expectMsg(AddPartitions(List(newView)))
    schemaManagerRouter.reply(TransformationMetadata(Map(newView -> ("test", 1L))))

    materializeProductBrandView(view)
    materializeProductBrandView(newView)
  }

  "A external view" should "reload it's state and ignore it's deps" in new TableActorTest {
    val extView = ExternalView(ProductBrand(p("ec0101"), p("2016"), p("11"), p("07")))

    val extActor = system.actorOf(TableActor.props(
      Map(extView -> CreatedByViewManager(extView)),
      Settings(),
      Map(),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    extActor ! CommandForView(None, extView, MaterializeExternalView())

    schemaManagerRouter.expectMsg(GetMetaDataForMaterialize(extView,
      MaterializeViewMode.DEFAULT,
      self))

    schemaManagerRouter.reply(CommandForView(None, extView, MetaDataForMaterialize((extView, ("checksum", 1L)),
      MaterializeViewMode.DEFAULT,
      self)))

    expectMsgType[ViewMaterialized]

  }

  it should "stub its dependencies if dev mode on and dependency is external" in new TableActorStubbingTest {

    val viewWithExt = ViewWithExternalDeps(p("ec0101"), p("2016"), p("11"), p("07"))
    val extView = viewWithExt.dependencies.head
    val extActor = TestProbe()
    val actorWithExt = system.actorOf(TableActor.props(
      Map(viewWithExt -> CreatedByViewManager(viewWithExt)),
      settings,
      Map(extView.tableName -> extActor.ref),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    actorWithExt ! CommandForView(None, viewWithExt, MaterializeView())
    extActor.expectMsg(CommandForView(Some(viewWithExt), extView, MaterializeViewAsStub()))
    extActor.reply(CommandForView(Some(extView), viewWithExt, ViewMaterialized(extView, incomplete = false, 1L, errors = false)))
    transformationManagerActor.expectMsg(viewWithExt)
    val success = TransformationSuccess(mock[DriverRunHandle[HiveTransformation]], mock[DriverRunSucceeded[HiveTransformation]], true)
    transformationManagerActor.reply(CommandForView(None, viewWithExt, success))

    expectMsgType[ViewMaterialized]
  }

  "A view" should "reload it's state and ignore it's deps when called view external materialize" in new TableActorTest {
    val viewNE = ProductBrand(p("ec0101"), p("2016"), p("11"), p("07"))
    val viewE = ExternalView(ProductBrand(p("ec0101"), p("2016"), p("11"), p("07")))

    val extActor = system.actorOf(TableActor.props(
      Map(viewE -> CreatedByViewManager(viewE)),
      Settings(),
      Map(),
      viewManagerActor.ref,
      transformationManagerActor.ref,
      schemaManagerRouter.ref,
      viewSchedulingListenerManagerActor.ref))

    extActor ! CommandForView(None, viewE, MaterializeExternalView())

    schemaManagerRouter.expectMsg(GetMetaDataForMaterialize(viewE,
      MaterializeViewMode.DEFAULT,
      self))

    schemaManagerRouter.reply(CommandForView(None, viewE, MetaDataForMaterialize((viewE, ("checksum", 1L)),
      MaterializeViewMode.DEFAULT,
      self)))

    expectMsgType[ViewMaterialized]

  }

  //TODO: test multi view actors

}


text:
package com.kerchin.yellownote.data.bean;

/**
 * Created by Kerchin on 2016/4/12 0012.
 */
public class GetDataHelper {
    public final static byte statusNone = 22;//整体获取
    public final static byte statusFirstGet = 0;//整体获取
//    public final static byte statusZero = 1;//数据为空
    public final static byte statusRespond = 2;//数据反馈
    public final static byte statusRefresh = 3;//数据刷新
    public final static byte statusLoadMore = 4;//获取更多
    public final static byte handle4none = 99;//创建adapter4folder并应用于ListView
    public final static byte handle4firstGet = 100;//创建adapter4folder并应用于ListView
    public final static byte handle4respond = 101;//由于新增、删除、修改影响note视图
    public final static byte handle4refresh = 102;//由于isChangedFolder refresh
    public final static byte handle4loadMore = 103;//手动获取更多
//    public final static byte handle4zero = 104;//从有到无
    public final static byte handle4empty = 105;//从有到无
    public final static byte handle4error = 106;//从有到无
    public byte status = 0;//当前状态
    public String statusName = "";//当前状态名
    public byte handleCode = 0;

    public void none(){
        status = statusNone;
        statusName = "none";
        handleCode = handle4none;
    }

    public void firstGet(){
        status = statusFirstGet;
        statusName = "firstGet";
        handleCode = handle4firstGet;
    }

//    public void zero(){
//        status = statusZero;
//        statusName = "zero";
//        handleCode = handle4zero;
//    }

    public void respond(){
        status = statusRespond;
        statusName = "respond";
        handleCode = handle4respond;
    }

    public void refresh(){
        status = statusRefresh;
        statusName = "refresh";
        handleCode = handle4refresh;
    }

    public void loadMore() {
        status = statusLoadMore;
        statusName = "loadMore";
        handleCode = handle4loadMore;
    }
}


text:
using System;
using System.Linq;
using ImageQuery.Environment;
using ImageQuery.Environment.Attributes;
using ImageQuery.Query.Value;

namespace ImageQuery.Library
{
    public static class Utility
    {
        [QueryFunction("print")]
        public static IQueryValue Print(IEnvironment env, IQueryValue[] args)
        {
            Console.ForegroundColor = ConsoleColor.Blue;
            if (args.Length == 0)
            {
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine(string.Join(" ", args.Select(v => v.ToString()).ToArray()));
            }

            Console.ForegroundColor = ConsoleColor.White;

            return new NullValue();
        }

        [QueryFunction("par")]
        public static IQueryValue PrintAndReturn(IEnvironment env, IQueryValue[] args)
        {
            FunctionUtils.CheckArgumentCountEqual("par", 1, args.Length);

            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine(args[0].ToString());
            Console.ForegroundColor = ConsoleColor.White;

            return args[0];
        }

        [QueryFunction("null")]
        public static IQueryValue Null(IEnvironment env, IQueryValue[] args)
        {
            return new NullValue();
        }
    }
}


text:
PYTHON_VERSION_COMPATIBILITY = "PY3"

DEPS = [
  'gold_upload',
  'recipe_engine/path',
  'recipe_engine/platform',
  'recipe_engine/properties',
  'recipe_engine/python',
  'recipe_engine/step',
  'flavor',
  'run',
  'vars',
]

def RunSteps(api):
  api.vars.setup()
  api.flavor.setup('dm')
  api.gold_upload.upload()

def GenTests(api):
  yield (
      api.test('upload_tests') +
      api.properties(buildername='Test-Android-Clang-Pixel2XL-Some-GPU-arm64-Debug-All',
                     repository='https://skia.googlesource.com/skia.git',
                     gs_bucket='skia-infra-gm',
                     patch_ref='89/456789/12',
                     patch_set=7,
                     patch_issue=1234,
                     revision='abc123',
                     path_config='kitchen',
                     swarm_out_dir='[SWARM_OUT_DIR]')
  )
  yield (
      api.test('upload_mac') +
      api.properties(buildername='Test-Mac12-Clang-MacBookPro16.2-GPU-IntelIrisPlus-x86_64-Debug-All-Graphite',
                     repository='https://skia.googlesource.com/skia.git',
                     gs_bucket='skia-infra-gm',
                     patch_ref='89/456789/12',
                     patch_set=7,
                     patch_issue=1234,
                     revision='abc123',
                     path_config='kitchen',
                     swarm_out_dir='[SWARM_OUT_DIR]') +
      api.platform('mac', 64)
  )


text:
using System;

public class GenExc<S,T> : Exception {
}

public delegate void ThrowDelegate ();

public class Gen<T> {
	public void catcher<S> (ThrowDelegate thrower) {
		try {
			thrower ();
		}
		catch (GenExc<S,T>) {
		}
	}

	public static void staticCatcher<S> (ThrowDelegate thrower) {
		try {
			thrower ();
		}
		catch (GenExc<S,T>) {
		}
	}
}

public class main {
	static void throwObjectObject () {
		throw new GenExc<object, object> ();
	}

	static void throwStringObject () {
		throw new GenExc<string, object> ();
	}

	static int Main () {
		Gen<object> go = new Gen<object> ();

		try {
			go.catcher<object> (new ThrowDelegate (main.throwObjectObject));
			Gen<object>.staticCatcher<object> (new ThrowDelegate (main.throwObjectObject));
			go.catcher<string> (new ThrowDelegate (main.throwStringObject));
			Gen<object>.staticCatcher<string> (new ThrowDelegate (main.throwStringObject));
		}
		catch {
			return 1;
		}

		try {
			go.catcher<object> (new ThrowDelegate (main.throwStringObject));
			return 1;
		}
		catch {
		}
		try {
			Gen<object>.staticCatcher<object> (new ThrowDelegate (main.throwStringObject));
			return 1;
		}
		catch {
		}

		try {
			go.catcher<string> (new ThrowDelegate (main.throwObjectObject));
			return 1;
		}
		catch {
		}
		try {
			Gen<object>.staticCatcher<string> (new ThrowDelegate (main.throwObjectObject));
			return 1;
		}
		catch {
		}

		return 0;
	}
}


text:
namespace Google.Cloud.BigQuery.DataTransfer.V1.Snippets
{
    // [START bigquerydatatransfer_v1_generated_DataTransferService_ScheduleTransferRuns_sync_flattened_resourceNames]
    using Google.Cloud.BigQuery.DataTransfer.V1;
    using Google.Protobuf.WellKnownTypes;

    public sealed partial class GeneratedDataTransferServiceClientSnippets
    {
        /// <summary>Snippet for ScheduleTransferRuns</summary>
        /// <remarks>
        /// This snippet has been automatically generated and should be regarded as a code template only.
        /// It will require modifications to work:
        /// - It may require correct/in-range values for request initialization.
        /// - It may require specifying regional endpoints when creating the service client as shown in
        ///   https://cloud.google.com/dotnet/docs/reference/help/client-configuration#endpoint.
        /// </remarks>
        public void ScheduleTransferRunsResourceNames()
        {
            // Create client
            DataTransferServiceClient dataTransferServiceClient = DataTransferServiceClient.Create();
            // Initialize request argument(s)
            TransferConfigName parent = TransferConfigName.FromProjectTransferConfig("[PROJECT]", "[TRANSFER_CONFIG]");
            Timestamp startTime = new Timestamp();
            Timestamp endTime = new Timestamp();
            // Make the request
#pragma warning disable CS0612
            ScheduleTransferRunsResponse response = dataTransferServiceClient.ScheduleTransferRuns(parent, startTime, endTime);
#pragma warning restore CS0612
        }
    }
    // [END bigquerydatatransfer_v1_generated_DataTransferService_ScheduleTransferRuns_sync_flattened_resourceNames]
}


text:
#include "El.hpp"

namespace El {

template<typename T,typename S>
void AxpyTrapezoid
( UpperOrLower uplo, S alphaS, const Matrix<T>& X, Matrix<T>& Y, Int offset )
{
    DEBUG_ONLY(
        CSE cse("AxpyTrapezoid");
        if( X.Height() != X.Width() || Y.Height() != Y.Width() ||
            X.Height() != Y.Height() )
            LogicError("Nonconformal AxpyTrapezoid");
    )
    const T alpha = T(alphaS);
    const Int m = X.Height();
    const Int n = X.Width();
    if( uplo == UPPER )
    {
        for( Int j=0; j<n; ++j )
        {
            const Int iSize = Max(Min(j+1-offset,m),0);
            blas::Axpy
            ( iSize, alpha, X.LockedBuffer(0,j), 1, Y.Buffer(0,j), 1 );
        }
    }
    else
    {
        for( Int j=0; j<n; ++j )
        {
            const Int i = Max(Min(j-offset,m),0);
            blas::Axpy( m-i, alpha, X.LockedBuffer(i,j), 1, Y.Buffer(i,j), 1 );
        }
    }
}

template<typename T,typename S>
void AxpyTrapezoid
( UpperOrLower uplo, S alphaS,
  const SparseMatrix<T>& X, SparseMatrix<T>& Y, Int offset )
{
    DEBUG_ONLY(CSE cse("AxpyTrapezoid"))
    if( X.Height() != Y.Height() || X.Width() != Y.Width() )
        LogicError("X and Y must have the same dimensions");
    const T alpha = T(alphaS);
    const Int numEntries = X.NumEntries();
    Y.Reserve( Y.NumEntries()+numEntries );
    for( Int k=0; k<numEntries; ++k )
    {
        const Int i = X.Row(k);
        const Int j = X.Col(k);
        if( (uplo==UPPER && j-i >= offset) || (uplo==LOWER && j-i <= offset) )
            Y.QueueUpdate( i, j, alpha*X.Value(k) );
    }
    Y.ProcessQueues();
}

template<typename T,typename S>
void AxpyTrapezoid
( UpperOrLower uplo, S alphaS,
  const AbstractDistMatrix<T>& X, AbstractDistMatrix<T>& Y, Int offset )
{
    DEBUG_ONLY(
        CSE cse("AxpyTrapezoid");
        AssertSameGrids( X, Y );
        if( X.Height() != X.Width() || Y.Height() != Y.Width() ||
            X.Height() != Y.Height() )
            LogicError("Nonconformal AxpyTrapezoid");
    )
    const T alpha = T(alphaS);

    const DistData XDistData = X.DistData();
    const DistData YDistData = Y.DistData();

    if( XDistData == YDistData )
    {
        const Int localHeight = X.LocalHeight();
        const Int localWidth = X.LocalWidth();
        const T* XBuffer = X.LockedBuffer();
        T* YBuffer = Y.Buffer();
        const Int XLDim = X.LDim();
        const Int YLDim = Y.LDim();
        if( uplo == UPPER )
        {
            for( Int jLoc=0; jLoc<localWidth; ++jLoc )
            {
                const Int j = X.GlobalCol(jLoc);
                const Int localHeightAbove = X.LocalRowOffset(j+1-offset);
                blas::Axpy
                ( localHeightAbove, alpha,
                  &XBuffer[jLoc*XLDim], 1, &YBuffer[jLoc*YLDim], 1 );
            }
        }
        else
        {
            for( Int jLoc=0; jLoc<localWidth; ++jLoc )
            {
                const Int j = X.GlobalCol(jLoc);
                const Int localHeightAbove = X.LocalRowOffset(j-offset);
                const Int localHeightBelow = localHeight - localHeightAbove;
                blas::Axpy
                ( localHeightBelow, alpha,
                  &XBuffer[localHeightAbove+jLoc*XLDim], 1,
                  &YBuffer[localHeightAbove+jLoc*YLDim], 1 );
            }
        }
    }
    else
    {
        unique_ptr<AbstractDistMatrix<T>>
          XCopy( Y.Construct(Y.Grid(),Y.Root()) );
        XCopy->AlignWith( YDistData );
        Copy( X, *XCopy );
        AxpyTrapezoid( uplo, alpha, *XCopy, Y, offset );
    }
}

template<typename T,typename S>
void AxpyTrapezoid
( UpperOrLower uplo, S alphaS,
  const DistSparseMatrix<T>& X, DistSparseMatrix<T>& Y, Int offset )
{
    DEBUG_ONLY(CSE cse("AxpyTrapezoid"))
    if( X.Height() != Y.Height() || X.Width() != Y.Width() )
        LogicError("X and Y must have the same dimensions");
    if( X.Comm() != Y.Comm() )
        LogicError("X and Y must have the same communicator");
    const T alpha = T(alphaS);
    const Int numLocalEntries = X.NumLocalEntries();
    const Int firstLocalRow = X.FirstLocalRow();
    Y.Reserve( Y.NumLocalEntries()+numLocalEntries );
    for( Int k=0; k<numLocalEntries; ++k )
    {
        const Int i = X.Row(k);
        const Int j = X.Col(k);
        if( (uplo==UPPER && j-i >= offset) || (uplo==LOWER && j-i <= offset) )
            Y.QueueLocalUpdate( i-firstLocalRow, j, alpha*X.Value(k) );
    }
    Y.ProcessLocalQueues();
}

#define PROTO_TYPES(T,S) \
  template void AxpyTrapezoid \
  ( UpperOrLower uplo, S alpha, \
    const Matrix<T>& A, Matrix<T>& B, Int offset ); \
  template void AxpyTrapezoid \
  ( UpperOrLower uplo, S alpha, \
    const AbstractDistMatrix<T>& A, AbstractDistMatrix<T>& B, Int offset ); \
  template void AxpyTrapezoid \
  ( UpperOrLower uplo, S alpha, \
    const SparseMatrix<T>& A, SparseMatrix<T>& B, Int offset ); \
  template void AxpyTrapezoid \
  ( UpperOrLower uplo, S alpha, \
    const DistSparseMatrix<T>& A, DistSparseMatrix<T>& B, Int offset );

#define PROTO_INT(T) PROTO_TYPES(T,T)

#define PROTO_REAL(T) \
  PROTO_TYPES(T,Int) \
  PROTO_TYPES(T,T)

#define PROTO_COMPLEX(T) \
  PROTO_TYPES(T,Int) \
  PROTO_TYPES(T,Base<T>) \
  PROTO_TYPES(T,T)

#define EL_ENABLE_QUAD
#include "El/macros/Instantiate.h"

} // namespace El


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <meta name="Content-Type" content="text/html; charset=utf-8" />
<title>Documentation by YARD 0.6.4</title>
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />

(no frames)

  Class List
  Method List
  File List

Documentation by YARD 0.6.4

Alphabetic Index

File Listing

README

Namespace Listing A-Z

A

                  ActionMailer

                  ActsAsMailReceiver

                    (MailEngine)

B

                  Base

                    (ActionMailer)

                  Base

                    (MailEngine::Sendgrid)

                  Base

                    (MailEngine)

C

                  ClassMethods

                    (MailEngine::Sendgrid::Base)

                  ClassMethods

                    (MailEngine::ActsAsMailReceiver)

                  Collector

                    (ActionMailer)

                  Configuration

                    (MailEngine)

                  CopyMigrations

                    (MailEngine)

                  CopyResources

                    (MailEngine)

                  CreateConfig

                    (MailEngine)

E

                  Engine

                    (MailEngine)

F

                  FilterSetting

                    (MailEngine::Sendgrid)

H

                  HtmlDocumentAssetsReplacer

                    (MailEngine)

I

                  Install

                    (MailEngine)

                  InstanceMethods

                    (MailEngine::Sendgrid::Base)

L

                  LiquidView

M

                  MailEngine

                  MailLogSubscriber

                    (MailEngine)

                  MailTemplateResolver

                    (MailEngine)

R

                  RestApi

                    (MailEngine::Sendgrid)

                  RestApiError

                    (MailEngine::Sendgrid)

S

                  Sendgrid

                    (MailEngine)

                  SmtpApi

                    (MailEngine::Sendgrid)

Z

                  ZipProcessor

                    (MailEngine)

  Generated on Mon Mar 14 22:31:43 2011 by
  yard
  0.6.4 (ruby-1.8.7).


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using OSky.Core.Data;

namespace OSky.UI.Models.Flow
{
    /// <summary>
    /// 实体类——表单流程关联信息
    /// </summary>
    [Description("工作流-表单流程关联信息")]
    public class WorkFlowRelateForm : Entity<Guid>, IAudited, ICreatedTime
    {
        /// <summary>
        /// 所属流程Id
        /// </summary>
        [Display(Name = "所属流程Id")]
        public Guid FlowDesignId { get; set; }
        /// <summary>
        /// 表单信息Id
        /// </summary>
        [Display(Name = "表单信息Id")]
        public Guid FlowFormId { get; set; }
        /// <summary>
        /// 状态信息:0 启用 1 停用
        /// </summary>
        [DisplayName("状态信息")]
        public short Status { get; set; }
        /// <summary>
        /// 获取或设置 创建者Id
        /// </summary>
        [Required, StringLength(50), Description("创建者Id")]
        public string CreatorUserId { get; set; }
        /// <summary>
        /// 获取设置 信息创建时间
        /// </summary>
        [Description("信息创建时间")]
        public DateTime CreatedTime { get; set; }
        /// <summary>
        /// 获取或设置 最后更新者Id
        /// </summary>
        [StringLength(50), Description("最后更新者Id")]
        public string LastUpdatorUserId { get; set; }
        /// <summary>
        /// 获取或设置 最后更新时间
        /// </summary>
        [Description("最后更新时间")]
        public DateTime? LastUpdatedTime { get; set; }

        /// <summary>
        /// 流程信息
        /// </summary>
        public virtual WorkFlowDesign FlowDesign { get; set; }
        /// <summary>
        /// 表单信息
        /// </summary>
        public virtual WorkFlowForm FlowForm { get; set; }
    }
}


text:
<!DOCTYPE html>

  <meta charset="utf-8" />

  <title>[译][Angular2] Attribute Directives</title>

  <meta name="author" content="wukn" />
  <meta name="description" content=" 属性指令用于改变DOM元素的外观或行为。

" />

    <meta name="twitter:card" content="summary" />
    <meta name="twitter:site" content="@gohugoio" />
    <meta name="twitter:title" content="[译][Angular2] Attribute Directives" />
    <meta name="twitter:description" content=" 属性指令用于改变DOM元素的外观或行为。

" />
    <meta name="twitter:image" content="https://wukn.github.io/img/avatar.jpg" />

  <meta property="og:type" content="article" />
  <meta property="og:title" content="[译][Angular2] Attribute Directives" />
  <meta property="og:description" content=" 属性指令用于改变DOM元素的外观或行为。

" />
  <meta property="og:url" content="https://wukn.github.io/2017/03/01/angular2-attribute-directives/" />
  <meta property="og:image" content="https://wukn.github.io/img/avatar.jpg" />

<meta name="generator" content="Hugo 0.46" />

<link rel="canonical" href="https://wukn.github.io/2017/03/01/angular2-attribute-directives/" />
<link rel="alternative" href="https://wukn.github.io/index.xml" title="wukn blog" type="application/atom+xml" />

<meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="format-detection" content="telephone=no,email=no,adress=no" />
<meta http-equiv="Cache-Control" content="no-transform" />

<meta name="robots" content="index,follow" />
<meta name="referrer" content="origin-when-cross-origin" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="wukn blog" />
<meta name="msapplication-tooltip" content="wukn blog" />
<meta name='msapplication-navbutton-color' content="#5fbf5e" />
<meta name="msapplication-TileColor" content="#5fbf5e" />
<meta name="msapplication-TileImage" content="/img/tile-image-windows.png" />
<link rel="icon" href="https://wukn.github.io/img/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="https://wukn.github.io/img/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="https://wukn.github.io/img/favicon-32x32.png" />
<link rel="icon" sizes="192x192" href="https://wukn.github.io/img/touch-icon-android.png" />
<link rel="apple-touch-icon" href="https://wukn.github.io/img/touch-icon-apple.png" />
<link rel="mask-icon" href="https://wukn.github.io/img/safari-pinned-tab.svg" color="#5fbf5e" />

<link rel="stylesheet" href="//cdn.bootcss.com/video.js/6.2.8/alt/video-js-cdn.min.css" />

<link rel="stylesheet" href="https://wukn.github.io/css/bundle.css" />

wukn blog

~ Stay Hungry, Stay Foolish ~

  <button class="menu-toggle" type="button">

  </button>

Main Menu

            Home

            Works

            Tags

            About

Social Networks

[译][Angular2] Attribute Directives

@wukn · Mar 1, 2017 · 2 min read

属性指令用于改变DOM元素的外观或行为。

指令综述

Angular中共有三种指令:

组件:带模板的指令。组件是三种指令中最常见的。

结构指令:通过添加或移除DOM元素来改变DOM布局。结构指令用于改变视图的结构。例如NgFor和NgIf。

属性指令:改变元素、组件或另一个指令的外观或元素。属性指令被当做元素的属性来使用。例如NgStyle。

构建一个简单的属性指令

最简单的属性指令就是一个带有@Directive注解的controller类,注解中指定了标识属性的选择器。controller类实现期望的指令行为。

接下来演示构建一个myHighlight属性指令,它的作用是当用户鼠标悬停在元素上时改变它的背景颜色。可以这样使用它:

<p myHighlight>Highlight me!</p>

按照Quick Start中创建一个项目attribute-directives。

创建文件src/app/highlight.directive.ts:

import { Directive, ElementRef, Input } from '@angular/core';
@Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'yellow';
    }
}

从Angular的core中引入:

Directive:提供@Directive装饰器

ElementRef:注入到指令的构造函数中以便于在代码中访问DOM元素

Input:允许数据从绑定表达式流向指令

@Directive注解中指定了一个CSS选择器。一个属性的CSS选择器是一个放在中括号里的属性名。在这里属性的选择器是[myHighlight]。Angular会定位模板中所有拥有名为myHighlight的属性的元素。

Angular会为每个匹配的元素创建一个指令的controller类的实例,并将ElementRef注入到构造函数中。ElementRef是一个Service,通过它的nativeElement属性可以直接访问DOM元素。

在模板中为元素使用属性指令

为了使用HighlightDirective,我们创建一个模板:

创建模板文件app.component.html:

<!-- src/app/app.component.html -->

<h1>My First Attribute Directive</h1>
<p myHighlight>Highlight me!</p>

修改AppComponent中的模板配置:

// src/app/app.component.ts

import { Component } from '@angular/core';
@Component({
  moduleId: module.id,
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class AppComponent {
  color: string;
}

接下来,在NgModule的declarations元数据中引入Highlight,这样Angular遇到模板中的myHighlight才知道该把他解析成指令。

// src/app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HighlightDirective } from './highlight.directive';
@NgModule({
  imports: [ BrowserModule ],
  declarations: [
    AppComponent,
    HighlightDirective
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

现在运行应用,可以看到:

响应用户初始化事件

目前myHighlight只是简单的给元素添加背景色。我们可以为指令添加一些动态的效果。比如可以响应鼠标的进入和移出事件来为元素设置或取消背景色。

在import中添加HostListener,Input也即将用到,一并添加上:

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

添加两个响应鼠标进入和离开的事件处理器:

@HostListener('mouseenter') onMouseEnter() {
  this.highlight('yellow');
}

@HostListener('mouseleave') onMouseLeave() {
  this.highlight(null);
}

private highlight(color: string) {
  this.el.nativeElement.style.backgroundColor = color;
}

@HostListener用于订阅使用了该指令的元素的事件。

当然我们也可以使用标准的JavaScript来访问DOM元素和附加事件监听。但这至少有三个问题:

必须手动的写对应事件的监听器

在指令销毁时需要在代码中移除事件监听,以免内存泄露

直接调用DOM的API并不是一个很好的选择

修改指令的构造函数,注入DOM元素el供事件处理函数调用:

constructor(private el: ElementRef) { }

完整的代码如下:

// src/app/highlight.directive.ts

import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
  selector: '[myHighlight]'
})
export class HighlightDirective {
  constructor(private el: ElementRef) { }
  @HostListener('mouseenter') onMouseEnter() {
    this.highlight('yellow');
  }
  @HostListener('mouseleave') onMouseLeave() {
    this.highlight(null);
  }
  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

现在运行应用,当鼠标不是停留在"Highlight me"这一行时是没有背景色的,鼠标移上去之后就有了(截图的时候鼠标不见了…):

使用@Input数据绑定向指令传递数据

现在颜色是硬编码在指令中。我们将它改成可设置的。

为指令添加一个highlightColor属性:

@Input() highlightColor: string;

注意,这里用到了@Input装饰器。它让指令的highlightColor属性可绑定。这里用的是input属性,是因为数据从绑定表达式流向指令。

向AppComponent的模板中添加指令的绑定:

<p myHighlight highlightColor="yellow">Highlighted in yellow</p>
<p myHighlight [highlightColor]="'orange'">Highlighted in orange</p>

为AppComponent添加一个color属性:

export class AppComponent {
  color = 'yellow';
}

使用属性绑定来控制颜色:

<p myHighlight [highlightColor]="color">Highlighted with parent component's color</p>

也可以同时使用指令并绑定属性:

<p [myHighlight]="color">Highlight me!</p>

[myHighlight]会同时应用指令并绑定属性。但是需要将指令的highlightColor属性名改成myHighlight。

@Input() myHighlight: string;

但是myHighlight作为属性名太糟糕了。我们可以绑定一个@Input别名:

@Input('myHighlight') highlightColor: string;

在指令内部可以用属性名highlightColor,在指令外部可以绑定myHighlight。

既然绑定了highlightColor属性,那么就需要修改onMouseEnter()的方法了:

@HostListener('mouseenter') onMouseEnter() {
  this.highlight(this.highlightColor || 'red');
}

完整的代码如下:

// src/app/highlight.directive.ts

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[myHighlight]'
})
export class HighlightDirective {

  constructor(private el: ElementRef) { }

  @Input('myHighlight') highlightColor: string;

  @HostListener('mouseenter') onMouseEnter() {
    this.highlight(this.highlightColor || 'red');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.highlight(null);
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

我们将AppComponent改成选择颜色的方式。更新app.component.html:

<h1>My First Attribute Directive</h1>

<h4>Pick a highlight color</h4>
<div>
  <input type="radio" name="colors" (click)="color='lightgreen'">Green
  <input type="radio" name="colors" (click)="color='yellow'">Yellow
  <input type="radio" name="colors" (click)="color='cyan'">Cyan
</div>
<p [myHighlight]="color">Highlight me!</p>

将AppComponent.color还原回去:

export class AppComponent {
  color: string;
}

效果如下:

绑定另一个属性

现在这个指令有了一个可设置的属性。我们还可以再添加属性用于绑定。

例如,现在的默认颜色是硬编码的,我们将它也改成可绑定的。

为指令添加input属性defaultColor:

@Input() defaultColor: string;

修改指令的onMouseEnter,先尝试使用highlightColor,然后是defaultColor,当两个属性都未定义时才使用red:

@HostListener('mouseenter') onMouseEnter() {
  this.highlight(this.highlightColor || this.defaultColor || 'red');
}

现在问题来了,怎样在模板中绑定第二个属性呢?

跟组件类似,我们可以在模板中添加任意多的指令属性绑定,如下:

<p [myHighlight]="color" defaultColor="violet">
  Highlight me too!
</p>

Angular会知道defaultColor绑定是属于HighlightDirective的,因为指令中这个属性使用@Input标记为public类型了。

参考资料:

Angular2 Documentation - Attribute Directives

Angular2

        © Creative Commons Attribution-NonCommercial 4.0 International License.This post was published 525 days ago, content in the post may be inaccurate, even wrong now, please take risk yourself.

© 2017-2018 wukn blog

Powered by Hugo with theme Nuo.