当前位置: 首页>>代码示例>>Java>>正文


Java Logger类代码示例

本文整理汇总了Java中org.jitsi.util.Logger的典型用法代码示例。如果您正苦于以下问题:Java Logger类的具体用法?Java Logger怎么用?Java Logger使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。


Logger类属于org.jitsi.util包,在下文中一共展示了Logger类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Java代码示例。

示例1: RawUdpTransportManager

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Initializes a new <tt>RawUdpTransportManager</tt> instance.
 *
 * @param channel the <tt>Channel</tt> which is initializing the new
 * instance
 */
public RawUdpTransportManager(Channel channel)
    throws IOException
{
    super();

    this.channel = channel;
    this.logger
        = Logger.getLogger(
                classLogger,
                channel.getContent().getConference().getLogger());
    addChannel(channel);

    streamConnector = createStreamConnector();
    /*
     * Each candidate harvest modifies the generation and the IDs of the RTP
     * and RTCP candidates.
     */
    generation = 0;
    rtpCandidateID = generateCandidateID();
    rtcpCandidateID = generateCandidateID();
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:28,代码来源:RawUdpTransportManager.java

示例2: dominantSpeakerChanged

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Notifies this instance that {@link #speechActivity} has identified a
 * speaker switch event in this multipoint conference and there is now a new
 * dominant speaker.
 */
private void dominantSpeakerChanged()
{
    Endpoint dominantSpeaker = speechActivity.getDominantEndpoint();

    if (logger.isInfoEnabled())
    {
        String id
            = dominantSpeaker == null ? "null" : dominantSpeaker.getID();
        logger.info(Logger.Category.STATISTICS,
                    "ds_change," + getLoggingId()
                    + " ds_id=" + id);
    }

    if (dominantSpeaker != null)
    {
        broadcastMessage(
                createDominantSpeakerEndpointChangeEvent(
                    dominantSpeaker.getID()));

        if (isRecording() && (recorderEventHandler != null))
        {
            recorderEventHandler.dominantSpeakerChanged(dominantSpeaker);
        }
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:31,代码来源:Conference.java

示例3: JibriSession

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Creates new {@link JibriSession} instance.
 * @param owner the session owner which will be notified about this session
 * state changes.
 * @param roomName the name if the XMPP MUC room (full address).
 * @param pendingTimeout how many seconds this session can wait in pending
 * state, before trying another Jibri instance or failing with an error.
 * @param connection the XMPP connection which will be used to send/listen
 * for packets.
 * @param scheduledExecutor the executor service which will be used to
 * schedule pending timeout task execution.
 * @param jibriDetector the Jibri detector which will be used to select
 * Jibri instance.
 * @param isSIP <tt>true</tt> if it's a SIP session or <tt>false</tt> for
 * a regular live streaming Jibri type of session.
 * @param sipAddress a SIP address if it's a SIP session
 * @param displayName a display name to be used by Jibri participant
 * entering the conference once the session starts.
 * @param streamID a live streaming ID if it's not a SIP session
 * @param logLevelDelegate logging level delegate which will be used to
 * select logging level for this instance {@link #logger}.
 */
public JibriSession(
        JibriSession.Owner          owner,
        EntityBareJid               roomName,
        long                        pendingTimeout,
        XmppConnection              connection,
        ScheduledExecutorService    scheduledExecutor,
        JibriDetector               jibriDetector,
        boolean                     isSIP,
        String                      sipAddress,
        String                      displayName,
        String                      streamID,
        Logger                      logLevelDelegate)
{
    this.owner = owner;
    this.roomName = roomName;
    this.scheduledExecutor
        = Objects.requireNonNull(scheduledExecutor, "scheduledExecutor");
    this.pendingTimeout = pendingTimeout;
    this.isSIP = isSIP;
    this.jibriDetector = jibriDetector;
    this.sipAddress = sipAddress;
    this.displayName = displayName;
    this.streamID = streamID;
    this.xmpp = connection;
    logger = Logger.getLogger(classLogger, logLevelDelegate);
}
 
开发者ID:jitsi,项目名称:jicofo,代码行数:49,代码来源:JibriSession.java

示例4: ChatRoomRoleAndPresence

import org.jitsi.util.Logger; //导入依赖的package包/类
public ChatRoomRoleAndPresence(JitsiMeetConferenceImpl conference,
                               ChatRoom chatRoom)
{
    this.conference = Objects.requireNonNull(conference, "conference");
    this.chatRoom = Objects.requireNonNull(chatRoom, "chatRoom");

    this.logger = Logger.getLogger(classLogger, conference.getLogger());
}
 
开发者ID:jitsi,项目名称:jicofo,代码行数:9,代码来源:ChatRoomRoleAndPresence.java

示例5: SctpConnection

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Initializes a new <tt>SctpConnection</tt> instance.
 *
 * @param id the string identifier of this connection instance
 * @param content the <tt>Content</tt> which is initializing the new
 * instance
 * @param endpoint the <tt>Endpoint</tt> of newly created instance
 * @param remoteSctpPort the SCTP port used by remote peer
 * @param channelBundleId the ID of the channel-bundle this
 * <tt>SctpConnection</tt> is to be a part of (or <tt>null</tt> if no it is
 * not to be a part of a channel-bundle).
 * @throws Exception if an error occurs while initializing the new instance
 */
public SctpConnection(
        String id,
        Content content,
        Endpoint endpoint,
        int remoteSctpPort,
        String channelBundleId,
        Boolean initiator)
    throws Exception
{
    super(
            content,
            id,
            channelBundleId,
            IceUdpTransportPacketExtension.NAMESPACE,
            initiator);

    logger
        = Logger.getLogger(classLogger, content.getConference().getLogger());
    setEndpoint(endpoint);
    packetQueue
        = new RawPacketQueue(
            false,
            getClass().getSimpleName() + "-" + endpoint.getID(),
            handler);

    this.remoteSctpPort = remoteSctpPort;
    this.debugId = generateDebugId();
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:42,代码来源:SctpConnection.java

示例6: IceUdpTransportManager

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Initializes a new <tt>IceUdpTransportManager</tt> instance.
 *
 * @param conference the <tt>Conference</tt> which created this
 * <tt>TransportManager</tt>.
 * @param controlling {@code true} if the new instance is to serve as a
 * controlling ICE agent and passive DTLS endpoint; otherwise, {@code false}
 * @param numComponents the number of ICE components that this instance is
 * to start with.
 * @param iceStreamName the name of the ICE stream to be created by this
 * instance.
 * @param id an identifier of the {@link IceUdpTransportManager}.
 * @throws IOException
 */
public IceUdpTransportManager(Conference conference,
                              boolean controlling,
                              int numComponents,
                              String iceStreamName,
                              String id)
    throws IOException
{
    this.conference = conference;
    this.id = id;
    this.controlling = controlling;
    this.numComponents = numComponents;
    this.rtcpmux = numComponents == 1;
    this.logger = Logger.getLogger(classLogger, conference.getLogger());
    this.transportCCEngine = new TransportCCEngine(diagnosticContext);

    // Setup the diagnostic context.
    conference.appendDiagnosticInformation(diagnosticContext);
    diagnosticContext.put("transport", hashCode());

    dtlsControl = createDtlsControl();

    iceAgent = createIceAgent(controlling, iceStreamName, rtcpmux);
    iceAgent.addStateChangeListener(iceAgentStateChangeListener);
    iceStream = iceAgent.getStream(iceStreamName);
    iceStream.addPairChangeListener(iceStreamPairChangeListener);

    EventAdmin eventAdmin = conference.getEventAdmin();
    if (eventAdmin != null)
    {
        eventAdmin.sendEvent(EventFactory.transportCreated(this));
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:47,代码来源:IceUdpTransportManager.java

示例7: VideoChannel

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Initializes a new <tt>VideoChannel</tt> instance which is to have a
 * specific ID. The initialization is to be considered requested by a
 * specific <tt>Content</tt>.
 *
 * @param content the <tt>Content</tt> which is initializing the new
 * instance
 * @param id the ID of the new instance. It is expected to be unique within
 * the list of <tt>Channel</tt>s listed in <tt>content</tt> while the new
 * instance is listed there as well.
 * @param channelBundleId the ID of the channel-bundle this
 * <tt>VideoChannel</tt> is to be a part of (or <tt>null</tt> if no it is
 * not to be a part of a channel-bundle).
 * @param transportNamespace the namespace of transport used by this
 * channel. Can be either {@link IceUdpTransportPacketExtension#NAMESPACE}
 * or {@link RawUdpTransportPacketExtension#NAMESPACE}.
 * @param initiator the value to use for the initiator field, or
 * <tt>null</tt> to use the default value.
 * @throws Exception if an error occurs while initializing the new instance
 */
VideoChannel(Content content,
             String id,
             String channelBundleId,
             String transportNamespace,
             Boolean initiator)
    throws Exception
{
    super(content, id, channelBundleId, transportNamespace, initiator);

    logger
        = Logger.getLogger(
                classLogger,
                content.getConference().getLogger());

    this.lipSyncHack
        = cfg != null && cfg.getBoolean(ENABLE_LIPSYNC_HACK_PNAME, true)
        ? new LipSyncHack(this) : null;

    disableLastNNotifications = cfg != null
        && cfg.getBoolean(DISABLE_LASTN_NOTIFICATIONS_PNAME, false);

    initializeTransformerEngine();

    if (cfg != null && cfg.getBoolean(LOG_OVERSENDING_STATS_PNAME, false))
    {
        logOversendingStatsRunnable = createLogOversendingStatsRunnable();
        getRecurringExecutor().registerRecurringRunnable(
            logOversendingStatsRunnable);
    }
    else
    {
        logOversendingStatsRunnable = null;
    }

    getRecurringExecutor().registerRecurringRunnable(bandwidthProbing);
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:57,代码来源:VideoChannel.java

示例8: getTransportManager

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Returns, the <tt>TransportManager</tt> instance for the channel-bundle
 * with ID <tt>channelBundleId</tt>. If no instance exists and
 * <tt>create</tt> is <tt>true</tt>, one will be created.
 *
 * @param channelBundleId the ID of the channel-bundle for which to return
 * the <tt>TransportManager</tt>.
 * @param create whether to create a new instance, if one doesn't exist.
 * @param initiator determines ICE controlling/controlled and DTLS role.
 * @return the <tt>TransportManager</tt> instance for the channel-bundle
 * with ID <tt>channelBundleId</tt>.
 */
IceUdpTransportManager getTransportManager(
        String channelBundleId,
        boolean create,
        boolean initiator)
{
    IceUdpTransportManager transportManager;

    synchronized (transportManagers)
    {
        transportManager = transportManagers.get(channelBundleId);
        if (transportManager == null && create && !isExpired())
        {
            try
            {
                transportManager
                    = new IceUdpTransportManager(
                        this, initiator, 1, channelBundleId);
            }
            catch (IOException ioe)
            {
                throw new UndeclaredThrowableException(ioe);
            }
            transportManagers.put(channelBundleId, transportManager);

            logger.info(Logger.Category.STATISTICS,
                        "create_ice_tm," + getLoggingId()
                        + " ufrag=" + transportManager.getLocalUfrag()
                        + ",bundle=" + channelBundleId
                        + ",initiator=" + initiator);
        }
    }

    return transportManager;
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:47,代码来源:Conference.java

示例9: getLogger

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Returns the <tt>Logger</tt> used by this instance.
 */
public Logger getLogger()
{
    return logger;
}
 
开发者ID:jitsi,项目名称:jicofo,代码行数:8,代码来源:JitsiMeetConferenceImpl.java

示例10: RtpChannel

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Initializes a new <tt>Channel</tt> instance which is to have a specific
 * ID. The initialization is to be considered requested by a specific
 * <tt>Content</tt>.
 *
 * @param content the <tt>Content</tt> which is initializing the new
 * instance
 * @param id the ID of the new instance. It is expected to be unique within
 * the list of <tt>Channel</tt>s listed in <tt>content</tt> while the new
 * instance is listed there as well.
 * @param channelBundleId the ID of the channel-bundle this
 * <tt>RtpChannel</tt> is to be a part of (or <tt>null</tt> if no it is
 * not to be a part of a channel-bundle).
 * @param transportNamespace the namespace of the transport to be used by
 * the new instance. Can be either
 * {@link IceUdpTransportPacketExtension#NAMESPACE} or
 * {@link RawUdpTransportPacketExtension#NAMESPACE}.
 * @param initiator the value to use for the initiator field, or
 * <tt>null</tt> to use the default value.
 * @throws Exception if an error occurs while initializing the new instance
 */
public RtpChannel(
        Content content,
        String id,
        String channelBundleId,
        String transportNamespace,
        Boolean initiator)
    throws Exception
{
    super(content, id, channelBundleId, transportNamespace, initiator);

    logger
        = Logger.getLogger(
                classLogger,
                content.getConference().getLogger());

    /*
     * In the case of content mixing, each Channel has its own local
     * synchronization source identifier (SSRC), which Jitsi Videobridge
     * pre-announces.
     */
    initialLocalSSRC = Videobridge.RANDOM.nextLong() & 0xffffffffL;

    Conference conference = content.getConference();
    conference.addPropertyChangeListener(propertyChangeListener);

    conferenceSpeechActivity = conference.getSpeechActivity();
    if (conferenceSpeechActivity != null)
    {
        /*
         * The PropertyChangeListener will weakly reference this instance
         * and will unregister itself from the conference sooner or later.
         */
         conferenceSpeechActivity.addPropertyChangeListener(
                 propertyChangeListener);
    }

    content.addPropertyChangeListener(propertyChangeListener);

    if (IceUdpTransportPacketExtension.NAMESPACE.equals(
                    this.transportNamespace))
    {
        this.verifyRemoteAddress = false;
    }

    touch();
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:68,代码来源:RtpChannel.java

示例11: initialize

import org.jitsi.util.Logger; //导入依赖的package包/类
void initialize(RTPLevelRelayType rtpLevelRelayType)
    throws IOException
{
    super.initialize();

    MediaService mediaService = getMediaService();
    MediaType mediaType = getContent().getMediaType();

    synchronized (streamSyncRoot)
    {
        TransportManager transportManager = getTransportManager();
        TransportCCEngine transportCCEngine
            = transportManager.getTransportCCEngine();

        stream
            = mediaService.createMediaStream(
                    null,
                    mediaType,
                    getSrtpControl());

         // Add the PropertyChangeListener to the MediaStream prior to
         // performing further initialization so that we do not miss changes
         // to the values of properties we may be interested in.
        stream.addPropertyChangeListener(streamPropertyChangeListener);
        stream.setName(getID());
        stream.setProperty(RtpChannel.class.getName(), this);

        if (stream instanceof MediaStreamImpl)
        {
            MediaStreamImpl streamImpl = (MediaStreamImpl) stream;
            DiagnosticContext diagnosticContext
                = streamImpl.getDiagnosticContext();

            getContent().getConference()
                .appendDiagnosticInformation(diagnosticContext);
        }

        if (transformEngine != null)
        {
            stream.setExternalTransformer(transformEngine);
        }
        if (transportCCEngine != null)
        {
            stream.setTransportCCEngine(transportCCEngine);
        }

        logger.info(Logger.Category.STATISTICS,
                    "create_stream," + getLoggingId());

        /*
         * The attribute rtp-level-relay-type specifies the
         * vale of pretty much the most important Channel
         * property given that Jitsi Videobridge implements
         * an RTP-level relay. Consequently, it is
         * intuitively a sign of common sense to take the
         * value into account as possible.
         *
         * The attribute rtp-level-relay-type is optional.
         * If a value is not specified, then the Channel
         * rtpLevelRelayType is to not be changed.
         */
        if (rtpLevelRelayType != null)
        {
            setRTPLevelRelayType(rtpLevelRelayType);
        }

        // The transport manager could be already connected, in which case
        // (since we just created the stream), any previous calls to
        // transportConnected() have failed to start the stream. So trigger
        // one now, to make sure that the stream is started.
        if (transportManager.isConnected())
        {
            transportConnected();
        }
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:77,代码来源:RtpChannel.java

示例12: expire

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * {@inheritDoc}
 *
 * Closes {@link #transformEngine}. Normally this would be done by
 * {@link #stream} when it is being closed, but we have observed cases (e.g.
 * when running health checks) where it doesn't happen, and since
 * {@link #transformEngine} is part of this {@code RtpChannel}, the latter
 * assumes the responsibility of releasing its resources.
 */
@Override
public boolean expire()
{
    if (!super.expire())
    {
        // Already expired.
        return false;
    }

    if (getContent().getConference().includeInStatistics())
    {
        Conference.Statistics conferenceStatistics
            = getContent().getConference().getStatistics();
        conferenceStatistics.totalChannels.incrementAndGet();

        long lastPayloadActivityTime = getLastPayloadActivityTime();
        long lastTransportActivityTime = getLastTransportActivityTime();

        if (lastTransportActivityTime == 0)
        {
            // Check for ICE failures.
            conferenceStatistics.totalNoTransportChannels.incrementAndGet();
        }

        if (lastPayloadActivityTime == 0)
        {
            // Check for payload.
            conferenceStatistics.totalNoPayloadChannels.incrementAndGet();
        }

        TrackStats streamStats
            = stream.getMediaStreamStats().getSendStats();
        logger.info(Logger.Category.STATISTICS,
                    "expire_ch_stats," + getLoggingId() +
                        " bRecv=" + statistics.bytesReceived +
                        ",bSent=" + statistics.bytesSent +
                        ",pRecv=" + statistics.packetsReceived +
                        ",pSent=" + statistics.packetsSent +
                        ",bRetr=" + streamStats.getBytesRetransmitted() +
                        ",bNotRetr=" + streamStats.getBytesNotRetransmitted() +
                        ",pRetr=" + streamStats.getPacketsRetransmitted() +
                        ",pNotRetr=" + streamStats.getPacketsNotRetransmitted() +
                        ",pMiss=" + streamStats.getPacketsMissingFromCache());
    }
    TransformEngine transformEngine = this.transformEngine;
    if (transformEngine != null)
    {
        PacketTransformer t = transformEngine.getRTPTransformer();
        if (t != null)
        {
            t.close();
        }

        t = transformEngine.getRTCPTransformer();
        if (t != null)
        {
            t.close();
        }
    }

    return true;
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:72,代码来源:RtpChannel.java

示例13: onSctpNotification

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Implements notification in order to track socket state.
 */
@Override
public void onSctpNotification(SctpSocket socket,
                               SctpNotification notification)
{
    synchronized (syncRoot)
    {
        if (logger.isDebugEnabled())
        {
            // SCTP_SENDER_DRY_EVENT is logged too often. It means that the
            // data queue is now empty and we don't care.
            if (SctpNotification.SCTP_SENDER_DRY_EVENT
                != notification.sn_type)
            {
                logger.info(Logger.Category.STATISTICS,
                            "sctp_notification," + getLoggingId()
                                + " notification=" + notification);
            }
        }

        switch (notification.sn_type)
        {
        case SctpNotification.SCTP_ASSOC_CHANGE:
            SctpNotification.AssociationChange assocChange
                = (SctpNotification.AssociationChange) notification;

            switch (assocChange.state)
            {
            case SctpNotification.AssociationChange.SCTP_COMM_UP:
                if (!assocIsUp)
                {
                    boolean wasReady = isReady();

                    assocIsUp = true;
                    if (isReady() && !wasReady)
                        notifySctpConnectionReady();
                }
                break;

            case SctpNotification.AssociationChange.SCTP_COMM_LOST:
            case SctpNotification.AssociationChange.SCTP_SHUTDOWN_COMP:
            case SctpNotification.AssociationChange.SCTP_CANT_STR_ASSOC:
                closeStream();
                break;
            }
            break;
        }
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:52,代码来源:SctpConnection.java

示例14: iceAgentStateChange

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * Notifies this instance about a change of the value of the <tt>state</tt>
 * property of {@link #iceAgent}.
 *
 * @param ev a <tt>PropertyChangeEvent</tt> which specifies the old and new
 * values of the <tt>state</tt> property of {@link #iceAgent}.
 */
private void iceAgentStateChange(PropertyChangeEvent ev)
{
    // Log the changes in the ICE processing state of this
    // IceUdpTransportManager for the purposes of debugging.

    boolean interrupted = false;

    try
    {
        IceProcessingState oldState = (IceProcessingState) ev.getOldValue();
        IceProcessingState newState = (IceProcessingState) ev.getNewValue();

        logger.info(Logger.Category.STATISTICS,
                    "ice_state_change," + getLoggingId()
                    + " old_state=" + oldState
                    + ",new_state=" + newState);

        EventAdmin eventAdmin = conference.getEventAdmin();
        if (eventAdmin != null)
        {
            eventAdmin.sendEvent(
                    EventFactory.transportStateChanged(
                            this,
                            oldState,
                            newState));
        }
    }
    catch (Throwable t)
    {
        if (t instanceof InterruptedException)
        {
            interrupted = true;
        }
        else if (t instanceof ThreadDeath)
        {
            throw (ThreadDeath) t;
        }
    }
    finally
    {
        if (interrupted)
        {
            Thread.currentThread().interrupt();
        }
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:54,代码来源:IceUdpTransportManager.java

示例15: startConnectivityEstablishment

import org.jitsi.util.Logger; //导入依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public void startConnectivityEstablishment(
        IceUdpTransportPacketExtension transport)
{
    doStartConnectivityEstablishment(transport);

    synchronized (connectThreadSyncRoot)
    {
        if (connectThread == null)
        {
            connectThread = new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {
                        wrapupConnectivityEstablishment();
                    }
                    catch (OperationFailedException ofe)
                    {
                        logger.info(
                            "Failed to connect IceUdpTransportManager: "
                                     + ofe);

                        synchronized (connectThreadSyncRoot)
                        {
                            connectThread = null;
                            return;
                        }
                    }

                    // XXX The value of the field iceAgent is null at times.
                    Agent iceAgent = IceUdpTransportManager.this.iceAgent;

                    if (iceAgent == null)
                    {
                        // This TransportManager has (probably) been closed.
                        return;
                    }

                    IceProcessingState state = iceAgent.getState();

                    if (state.isEstablished())
                    {
                        onIceConnected();
                    }
                    else
                    {
                        logger.log(Level.WARNING,
                                   Logger.Category.STATISTICS,
                                   "ice_failed," + getLoggingId()
                                   + " state=" + state);
                    }
                }
            };

            connectThread.setDaemon(true);
            connectThread.setName("IceUdpTransportManager connect thread");
            connectThread.start();
        }
    }
}
 
开发者ID:jitsi,项目名称:jitsi-videobridge,代码行数:67,代码来源:IceUdpTransportManager.java


注:本文中的org.jitsi.util.Logger类示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。