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


C++ QQmlEnginePrivate::v4engine方法代码示例

本文整理汇总了C++中QQmlEnginePrivate::v4engine方法的典型用法代码示例。如果您正苦于以下问题:C++ QQmlEnginePrivate::v4engine方法的具体用法?C++ QQmlEnginePrivate::v4engine怎么用?C++ QQmlEnginePrivate::v4engine使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在QQmlEnginePrivate的用法示例。


在下文中一共展示了QQmlEnginePrivate::v4engine方法的10个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。

示例1: valueScope

QQmlBinding *
QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt)
{
    if (id < 0)
        return 0;

    QQmlBinding *rv = 0;

    QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
    QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
    if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
        QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
        Q_ASSERT(typeData);

        if (QQmlCompiledData *cdata = typeData->compiledData()) {
            QV4::ExecutionEngine *v4 = engine->v4engine();
            QV4::Scope valueScope(v4);
            QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
            QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction));
            rv = new QQmlBinding(function, obj, ctxtdata);
        }

        typeData->release();
    }

    return rv;
}
开发者ID:tizenorg,项目名称:platform.upstream.qtdeclarative,代码行数:27,代码来源:qqmlbinding.cpp

示例2: evaluate

// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
    Q_ASSERT (context() && engine());

    if (!expressionFunctionValid())
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::Scope scope(ep->v4engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.

    QVarLengthArray<int, 9> dummy;
    //TODO: lookup via signal index rather than method index as an optimization
    int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
    int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
    int argCount = argsTypes ? *argsTypes : 0;

    QV4::ScopedCallData callData(scope, argCount);
    for (int ii = 0; ii < argCount; ++ii) {
        int type = argsTypes[ii + 1];
        //### ideally we would use metaTypeToJS, however it currently gives different results
        //    for several cases (such as QVariant type and QObject-derived types)
        //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
        if (type == QMetaType::QVariant) {
            callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
        } else if (type == QMetaType::Int) {
            //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
            callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
        } else if (type == qMetaTypeId<QQmlV4Handle>()) {
            callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
        } else if (ep->isQObject(type)) {
            if (!*reinterpret_cast<void* const *>(a[ii + 1]))
                callData->args[ii] = QV4::Primitive::nullValue();
            else
                callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
        } else {
            callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
        }
    }

    QQmlJavaScriptExpression::evaluate(callData, 0);

    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
开发者ID:OniLink,项目名称:Qt5-Rehost,代码行数:47,代码来源:qqmlboundsignal.cpp

示例3: QQmlJavaScriptExpression

QT_BEGIN_NAMESPACE

QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
                                                     QQmlContextData *ctxt, QObject *scope, const QString &expression,
                                                     const QString &fileName, quint16 line, quint16 column,
                                                     const QString &handlerName,
                                                     const QString &parameterString)
    : QQmlJavaScriptExpression(),
      m_index(index),
      m_target(target)
{
    init(ctxt, scope);

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::ExecutionEngine *v4 = ep->v4engine();

    QString function;

    // Add some leading whitespace to account for the binding's column offset.
    // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
    function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
    function += QStringLiteral("(function ");
    function += handlerName;
    function += QLatin1Char('(');

    if (parameterString.isEmpty()) {
        QString error;
        //TODO: look at using the property cache here (as in the compiler)
        //      for further optimization
        QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
        function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error);

        if (!error.isEmpty()) {
            qmlInfo(scopeObject()) << error;
            return;
        }
    } else
        function += parameterString;

    function += QStringLiteral(") { ");
    function += expression;
    function += QStringLiteral(" })");

    m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));

    if (m_function.isNullOrUndefined())
        return; // could not evaluate function.  Not valid.

}
开发者ID:OniLink,项目名称:Qt5-Rehost,代码行数:49,代码来源:qqmlboundsignal.cpp

示例4: expressionIdentifier

QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
{
    QQmlBinding *This = static_cast<QQmlBinding *>(e);

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine);
    QV4::Scope scope(ep->v4engine());
    QV4::ScopedValue f(scope, This->v4function.value());
    QV4::Function *function = f->asFunctionObject()->function();

    QString url = function->sourceFile();
    quint16 lineNumber = function->compiledFunction->location.line;
    quint16 columnNumber = function->compiledFunction->location.column;

    return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber);
}
开发者ID:Drakey83,项目名称:steamlink-sdk,代码行数:15,代码来源:qqmlbinding.cpp

示例5: evaluate

QVariant QQmlBinding::evaluate()
{
    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
    QV4::Scope scope(ep->v4engine());
    ep->referenceScarceResources();

    bool isUndefined = false;

    QV4::ScopedValue f(scope, v4function.value());
    QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined));

    ep->dereferenceScarceResources();

    return ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
}
开发者ID:Drakey83,项目名称:steamlink-sdk,代码行数:15,代码来源:qqmlbinding.cpp

示例6: evaluate

// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
    Q_ASSERT (context() && engine());

    if (invalidParameterName())
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::Scope scope(ep->v4engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
    {
        if (!expressionFunctionValid()) {
            Q_ASSERT(!m_extra.isNull());
            QString expression;

            // Add some leading whitespace to account for the binding's column offset.
            // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
            expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2);
            expression += QStringLiteral("(function ");
            expression += m_extra->m_handlerName;
            expression += QLatin1Char('(');

            if (m_extra->m_parameterString.isEmpty()) {
                QString error;
                //TODO: look at using the property cache here (as in the compiler)
                //      for further optimization
                QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
                expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error);

                if (!error.isEmpty()) {
                    qmlInfo(scopeObject()) << error;
                    setInvalidParameterName(true);
                    ep->dereferenceScarceResources();
                    return;
                }
            } else
                expression += m_extra->m_parameterString;

            expression += QStringLiteral(") { ");
            expression += m_extra->m_expression;
            expression += QStringLiteral(" })");

            m_extra->m_expression.clear();
            m_extra->m_handlerName.clear();
            m_extra->m_parameterString.clear();

            m_v8function = evalFunction(context(), scopeObject(), expression,
                                        m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope);

            if (m_v8function.isNullOrUndefined()) {
                ep->dereferenceScarceResources();
                return; // could not evaluate function.  Not valid.
            }

            setExpressionFunctionValid(true);
        }

        QV8Engine *engine = ep->v8engine();
        QVarLengthArray<int, 9> dummy;
        //TODO: lookup via signal index rather than method index as an optimization
        int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
        int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0);
        int argCount = argsTypes ? *argsTypes : 0;

        QV4::ScopedValue f(scope, m_v8function.value());
        QV4::ScopedCallData callData(scope, argCount);
        for (int ii = 0; ii < argCount; ++ii) {
            int type = argsTypes[ii + 1];
            //### ideally we would use metaTypeToJS, however it currently gives different results
            //    for several cases (such as QVariant type and QObject-derived types)
            //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
            if (type == QMetaType::QVariant) {
                callData->args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1]));
            } else if (type == QMetaType::Int) {
                //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
                callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
            } else if (type == qMetaTypeId<QQmlV4Handle>()) {
                callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
            } else if (ep->isQObject(type)) {
                if (!*reinterpret_cast<void* const *>(a[ii + 1]))
                    callData->args[ii] = QV4::Primitive::nullValue();
                else
                    callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
            } else {
                callData->args[ii] = engine->fromVariant(QVariant(type, a[ii + 1]));
            }
        }

        QQmlJavaScriptExpression::evaluate(context(), f, callData, 0);
    }
    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
开发者ID:tizenorg,项目名称:platform.upstream.qtdeclarative,代码行数:95,代码来源:qqmlboundsignal.cpp

示例7: update

void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
{
    if (!enabledFlag() || !context() || !context()->isValid())
        return;

    // Check that the target has not been deleted
    if (QQmlData::wasDeleted(object()))
        return;

    QString url;
    quint16 lineNumber;
    quint16 columnNumber;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
    QV4::Scope scope(ep->v4engine());
    QV4::ScopedFunctionObject f(scope, v4function.value());
    Q_ASSERT(f);
    if (f->bindingKeyFlag()) {
        Q_ASSERT(f->as<QV4::QQmlBindingFunction>());
        QQmlSourceLocation loc = static_cast<QV4::QQmlBindingFunction *>(f.getPointer())->d()->bindingLocation;
        url = loc.sourceFile;
        lineNumber = loc.line;
        columnNumber = loc.column;
    } else {
        QV4::Function *function = f->asFunctionObject()->function();
        Q_ASSERT(function);

        url = function->sourceFile();
        lineNumber = function->compiledFunction->location.line;
        columnNumber = function->compiledFunction->location.column;
    }

    int lineNo = qmlSourceCoordinate(lineNumber);
    int columnNo = qmlSourceCoordinate(columnNumber);

    QQmlTrace trace("General Binding Update");
    trace.addDetail("URL", url);
    trace.addDetail("Line", lineNo);
    trace.addDetail("Column", columnNo);

    if (!updatingFlag()) {
        QQmlBindingProfiler prof(ep->profiler, url, lineNo, columnNo);
        setUpdatingFlag(true);

        QQmlAbstractExpression::DeleteWatcher watcher(this);

        if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {

            int idx = m_core.coreIndex;
            Q_ASSERT(idx != -1);

            QQmlBinding *t = this;
            int status = -1;
            void *a[] = { &t, 0, &status, &flags };
            QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);

        } else {
            ep->referenceScarceResources();

            bool isUndefined = false;

            QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined));

            trace.event("writing binding result");

            bool needsErrorLocationData = false;
            if (!watcher.wasDeleted() && !hasError())
                needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
                                                                    this, result, isUndefined, flags);

            if (!watcher.wasDeleted()) {

                if (needsErrorLocationData)
                    delayedError()->setErrorLocation(QUrl(url), lineNumber, columnNumber);

                if (hasError()) {
                    if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
                } else {
                    clearError();
                }

            }

            ep->dereferenceScarceResources();
        }

        if (!watcher.wasDeleted())
            setUpdatingFlag(false);
    } else {
        QQmlProperty p = property();
        QQmlAbstractBinding::printBindingLoopError(p);
    }
}
开发者ID:Drakey83,项目名称:steamlink-sdk,代码行数:93,代码来源:qqmlbinding.cpp

示例8: precompile


//.........这里部分代码省略.........
        if (lastDotIndex != -1) {
            enclosingNamespace = qualifier.left(lastDotIndex);
            qualifier = qualifier.mid(lastDotIndex+1);
        }

        compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace);
#if 0
        QQmlScriptData *scriptData = script.script->scriptData();
        scriptData->addref();
        compiledData->scripts << scriptData;
#endif
    }

    // resolve component boundaries and aliases
    if (!resolveComponentBoundariesAndAliases())
        return false;

    // Compile JS binding expressions and signal handlers
    if (!compilation->document->javaScriptCompilationUnit) {
        // We can compile script strings ahead of time, but they must be compiled
        // without type optimizations as their scope is always entirely dynamic.
        scanScriptStrings();

        // TBD: check how it uses importCache
        // TBD: check how links with other scripts
        QmlIR::JSCodeGen v4CodeGenerator(compilation->urlString, compilation->document->code, &compilation->document->jsModule,
                                         &compilation->document->jsParserEngine, compilation->document->program,
                                         compiledData->importCache, &compilation->document->jsGenerator.stringTable);
        JSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
        if (!jsCodeGen.generateCodeForComponents())
            return false;

        simplifyJavaScriptBindingExpressions();

        QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(compilation->engine);
        QV4::ExecutionEngine *v4 = enginePrivate->v4engine();
        // TBD: store unlinked binaries
#if 0
        QScopedPointer<QV4::EvalInstructionSelection> isel(
                    v4->iselFactory->create(enginePrivate, v4->executableAllocator,
                                            &compilation->document->jsModule, &compilation->document->jsGenerator));
#endif
        QScopedPointer<QmcInstructionSelection> isel(
                    new QmcInstructionSelection(enginePrivate, v4->executableAllocator,
                                            &compilation->document->jsModule, &compilation->document->jsGenerator));
        isel->setUseFastLookups(false);
        compilation->document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false);
        compilation->linkData = isel->linkData();
        compilation->exceptionReturnLabels = isel->exceptionReturnLabelsData();
        compilation->exceptionPropagationJumps = isel->exceptionPropagationJumpsData();
#if CPU(ARM_THUMB2)
        compilation->jumpsToLinkData = isel->linkRecordData();
        compilation->unlinkedCodeData = isel->unlinkedCodeData();
#endif
    }

    // Generate QML compiled type data structures

    QmlIR::QmlUnitGenerator qmlGenerator;
    QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*compilation->document);

    Q_ASSERT(compilation->document->javaScriptCompilationUnit);
    Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
    // The js unit owns the data and will free the qml unit.
    compilation->document->javaScriptCompilationUnit->data = &qmlUnit->header;

    compiledData->compilationUnit = compilation->document->javaScriptCompilationUnit;
    if (compiledData->compilationUnit)
        compiledData->compilationUnit->ref();
    compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData

    // add to type registry
    // qqmltypecompiler.cpp:248
    if (compiledData->isCompositeType()) {
        if (compilation->singleton)
            qmlUnit->header.flags |= QV4::CompiledData::Unit::IsSingleton;
        QQmlEnginePrivate::get(compilation->engine)->registerInternalCompositeType(compiledData);
    } else {
        if (compilation->singleton) {
             qmlUnit->header.flags = qmlUnit->header.flags | QV4::CompiledData::Unit::IsSingleton;
        }

        const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
        QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
        Q_ASSERT(typeRef);
        if (typeRef->component) {
            compiledData->metaTypeId = typeRef->component->metaTypeId;
            compiledData->listMetaTypeId = typeRef->component->listMetaTypeId;
        } else {
            compiledData->metaTypeId = typeRef->type->typeId();
            compiledData->listMetaTypeId = typeRef->type->qListTypeId();
        }
    }

    // Sanity check property bindings and compile custom parsers
    if (!validateProperties())
        return false;

    return true;
}
开发者ID:toby20130333,项目名称:qmlc,代码行数:101,代码来源:qmctypecompiler.cpp

示例9: metaCall


//.........这里部分代码省略.........
                    int flags = *reinterpret_cast<int*>(a[3]);
                    if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
                        QQmlData *targetData = QQmlData::get(target);
                        if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
                            QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
                            if (binding) binding->destroy();
                        }
                    }
                }

                if (d->isValueTypeAlias()) {
                    // Value type property
                    QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType());
                    Q_ASSERT(valueType);

                    valueType->read(target, d->propertyIndex());
                    int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);

                    if (c == QMetaObject::WriteProperty)
                        valueType->write(target, d->propertyIndex(), 0x00);

                    return rv;

                } else {
                    return QMetaObject::metacall(target, c, d->propertyIndex(), a);
                }

            }
            return -1;

        }

    } else if(c == QMetaObject::InvokeMetaMethod) {

        if (id >= methodOffset()) {

            id -= methodOffset();
            int plainSignals = metaData->signalCount + metaData->propertyCount +
                               metaData->aliasCount;
            if (id < plainSignals) {
                activate(object, _id, a);
                return -1;
            }

            id -= plainSignals;

            if (id < metaData->methodCount) {
                if (!ctxt->engine)
                    return -1; // We can't run the method

                QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine);
                ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
                QV4::Scope scope(ep->v4engine());


                QV4::Scoped<QV4::FunctionObject> function(scope, method(id));
                if (!function) {
                    // The function was not compiled.  There are some exceptional cases which the
                    // expression rewriter does not rewrite properly (e.g., \r-terminated lines
                    // are not rewritten correctly but this bug is deemed out-of-scope to fix for
                    // performance reasons; see QTBUG-24064) and thus compilation will have failed.
                    QQmlError e;
                    e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")).
                                     arg(QLatin1String(QMetaObject::method(_id).methodSignature().constData())));
                    ep->warning(e);
                    return -1; // The dynamic method with that id is not available.
                }

                QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;

                QV4::ScopedCallData callData(scope, data->parameterCount);
                callData->thisObject = ep->v8engine()->global();

                for (int ii = 0; ii < data->parameterCount; ++ii)
                    callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);

                QV4::ScopedValue result(scope);
                QV4::ExecutionContext *ctx = function->engine()->currentContext();
                result = function->call(callData);
                if (scope.hasException()) {
                    QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
                    if (error.isValid())
                        ep->warning(error);
                    if (a[0]) *(QVariant *)a[0] = QVariant();
                } else {
                    if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
                }

                ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
                return -1;
            }
            return -1;
        }
    }

    if (parent.isT1())
        return parent.asT1()->metaCall(object, c, _id, a);
    else
        return object->qt_metacall(c, _id, a);
}
开发者ID:Drakey83,项目名称:steamlink-sdk,代码行数:101,代码来源:qqmlvmemetaobject.cpp

示例10: ensureQObjectWrapper

void QQmlVMEMetaObject::ensureQObjectWrapper()
{
    QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
    QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine();
    QV4::QObjectWrapper::wrap(v4, object);
}
开发者ID:Drakey83,项目名称:steamlink-sdk,代码行数:6,代码来源:qqmlvmemetaobject.cpp


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