Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2013-07-22 18:25:37 +04:00
21 changed files with 339 additions and 90 deletions
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="core-api" />
<orderEntry type="module" module-name="IntelliLang" />
<orderEntry type="module" module-name="python" />
</component>
</module>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<idea-plugin version="2">
<extensions defaultExtensionNs="org.intellij.intelliLang">
<languageSupport implementation="com.jetbrains.python.intelliLang.PyLanguageInjectionSupport"/>
<injectionConfig config="pyInjections.xml"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<patterns.patternClass className="com.jetbrains.python.patterns.PythonPatterns" alias="py"/>
</extensions>
</idea-plugin>
@@ -0,0 +1,32 @@
package com.jetbrains.python.intelliLang;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.patterns.PythonPatterns;
import com.jetbrains.python.psi.PyElement;
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport {
@NonNls private static final String SUPPORT_ID = "python";
@NotNull
@Override
public String getId() {
return SUPPORT_ID;
}
@NotNull
@Override
public Class[] getPatternClasses() {
return new Class[] { PythonPatterns.class };
}
@Override
public boolean useDefaultInjector(PsiElement host) {
return host instanceof PyElement;
}
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="LanguageInjectionConfiguration">
<injection language="SQLite" injector-id="python">
<display-name>sqlite3</display-name>
<place><![CDATA[pyLiteralExpression().and(pyMethodArgument("execute", 0, "_sqlite3.Connection"))]]></place>
<place><![CDATA[pyLiteralExpression().and(pyMethodArgument("executemany", 0, "_sqlite3.Connection"))]]></place>
<place><![CDATA[pyLiteralExpression().and(pyMethodArgument("execute", 0, "_sqlite3.Cursor"))]]></place>
<place><![CDATA[pyLiteralExpression().and(pyMethodArgument("executemany", 0, "_sqlite3.Cursor"))]]></place>
</injection>
<injection language="SQL" injector-id="python">
<display-name>"SQL select/delete/insert/update/create"</display-name>
<place><![CDATA[pyLiteralExpression().withText(string().matchesBrics(" *(((SELECT|DELETE) .*FROM)|((INSERT|REPLACE) .*INTO)|(UPDATE .* SET)|((CREATE|DROP|ALTER) +(TABLE|INDEX))) .*"))]]></place>
</injection>
</component>
+4
View File
@@ -54,3 +54,7 @@ restClient
puppet
fileWatcher
terminal
IntelliLang
IntelliLang-xml
IntelliLang-js
IntelliLang-python
-59
View File
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<exe4j version="3.1.3">
<application name="PyCharm"/>
<executable name="pycharm"
type="1"
iconSet="true"
iconFile="../../python/resources/PyCharm.ico"
executableDir="bin"
redirectStderr="false"
stderrFile="error.log"
redirectStdout="false"
stdoutFile="output.log"
failOnStderrOutput="true"
executableMode="1"
changeWorkingDirectory="true"
workingDirectory="."
singleInstance="true"
serviceStartType="2"
serviceDependencies=""
serviceDescription=""
jreLocation="">
<messageSet language="English"/>
<versionInfo include="true"
companyName="JetBrains s.r.o"
fileDescription=""
legalCopyright="Copyright JetBrains s.r.o., (c) 2000-__YEAR__"
productVersion="__PRODUCT_VERSION__"
internalName="idea"/>
</executable>
<splashScreen show="true" autoOff="true" alwaysOnTop="false" width="400" height="300" bitmapFile="../../python/resources/pycharm_logo.png">
<text>
<statusLine x="10" y="208" text="" font="Arial" fontSize="8" fontColor="0,0,0" fontWeight="500"/>
<versionLine x="10" y="231" text="" font="Arial" fontSize="8" fontColor="0,0,0" fontWeight="500"/>
</text>
</splashScreen>
<java mainClass="com.intellij.idea.Main"
vmParameters="&quot;-Xbootclasspath/a:${EXE4J_EXEDIR}/../lib/boot.jar&quot; &quot;-Didea.properties.file=${PYCHARM_PROPERTIES}&quot; -Didea.platform.prefix=Python -Didea.no.jre.check=true &quot;-Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__&quot;"
arguments=""
allowVMPassthroughParameters="true"
minVersion="1.6"
maxVersion=""
preferredVM=""
allowBetaVM="true"
jdkOnly="false">
<searchSequence>
<envVar name="PYCHARM_JDK"/>
<directory location="./jre"/>
<registry/>
<envVar name="JDK_HOME"/>
</searchSequence>
<classPath>
__CLASS_PATH__
</classPath>
<nativeLibraryDirectories>
<directory name="./bin"/>
</nativeLibraryDirectories>
</java>
<includedFiles/>
</exe4j>
+1 -1
View File
@@ -26,7 +26,7 @@ private List<String> pycharmPlatformApiModules() {
private List pycharmImplementationModules() { //modules to put into pycharm.jar
return ["yaml", "graph", "coverage-common", "python", "python-ide", "python-openapi", "python-psi-api"]
return ["yaml", "graph", "coverage-common", "python", "python-ide", "python-openapi", "python-psi-api", "duplicates", "duplicates-xml"]
}
class Paths {
+6
View File
@@ -41,6 +41,12 @@
<orderEntry type="module" module-name="vagrant" />
<orderEntry type="module" module-name="pycharm-maya" />
<orderEntry type="module" module-name="terminal" />
<orderEntry type="module" module-name="duplicates" />
<orderEntry type="module" module-name="duplicates-xml" />
<orderEntry type="module" module-name="IntelliLang" />
<orderEntry type="module" module-name="IntelliLang-js" />
<orderEntry type="module" module-name="IntelliLang-python" />
<orderEntry type="module" module-name="IntelliLang-xml" />
</component>
</module>
@@ -288,7 +288,7 @@ public class PyRequirement {
@NotNull
private static List<PyRequirement> parse(@NotNull String s, @Nullable VirtualFile anchor, @NotNull Set<VirtualFile> visited) {
final List<PyRequirement> result = new ArrayList<PyRequirement>();
final Set<PyRequirement> result = new LinkedHashSet<PyRequirement>();
for (String line : StringUtil.splitByLines(s)) {
final String trimmed = line.trim();
if (!trimmed.isEmpty()) {
@@ -301,7 +301,7 @@ public class PyRequirement {
}
}
}
return result;
return new ArrayList<PyRequirement>(result);
}
@NotNull
+1
View File
@@ -25,6 +25,7 @@
<orderEntry type="module" module-name="chronon-embedder" />
<orderEntry type="module" module-name="python-remote-interpreter" scope="TEST" />
<orderEntry type="module" module-name="duplicates" scope="TEST" />
<orderEntry type="module" module-name="duplicates-xml" scope="TEST" />
</component>
</module>
@@ -0,0 +1,29 @@
package com.jetbrains.python.patterns;
import com.intellij.patterns.InitialPatternCondition;
import com.intellij.patterns.PsiElementPattern;
import com.jetbrains.python.psi.PyElement;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyElementPattern<T extends PyElement, Self extends PyElementPattern<T, Self>> extends PsiElementPattern<T, Self> {
public PyElementPattern(final Class<T> aClass) {
super(aClass);
}
public PyElementPattern(@NotNull final InitialPatternCondition<T> condition) {
super(condition);
}
public static class Capture<T extends PyElement> extends PyElementPattern<T, Capture<T>> {
public Capture(final Class<T> aClass) {
super(aClass);
}
public Capture(@NotNull final InitialPatternCondition<T> condition) {
super(condition);
}
}
}
@@ -0,0 +1,111 @@
package com.jetbrains.python.patterns;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.patterns.InitialPatternCondition;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class PythonPatterns extends PlatformPatterns {
public static PyElementPattern.Capture<PyLiteralExpression> pyLiteralExpression() {
return new PyElementPattern.Capture<PyLiteralExpression>(new InitialPatternCondition<PyLiteralExpression>(PyLiteralExpression.class) {
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
return o instanceof PyLiteralExpression;
}
});
}
public static PyElementPattern.Capture<PyExpression> pyArgument(final String functionName, final int index) {
return new PyElementPattern.Capture<PyExpression>(new InitialPatternCondition<PyExpression>(PyExpression.class) {
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
return isCallArgument(o, functionName, index);
}
});
}
public static PyElementPattern.Capture<PyExpression> pyModuleFunctionArgument(final String functionName, final int index, final String moduleName) {
return new PyElementPattern.Capture<PyExpression>(new InitialPatternCondition<PyExpression>(PyExpression.class) {
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
Callable function = resolveCalledFunction(o, functionName, index);
if (!(function instanceof PyFunction)) {
return false;
}
ScopeOwner scopeOwner = PsiTreeUtil.getParentOfType(function, ScopeOwner.class);
if (!(scopeOwner instanceof PyFile)) {
return false;
}
return moduleName.equals(FileUtil.getNameWithoutExtension(scopeOwner.getName()));
}
});
}
public static PyElementPattern.Capture<PyExpression> pyMethodArgument(final String functionName, final int index, final String classQualifiedName) {
return new PyElementPattern.Capture<PyExpression>(new InitialPatternCondition<PyExpression>(PyExpression.class) {
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
Callable function = resolveCalledFunction(o, functionName, index);
if (!(function instanceof PyFunction)) {
return false;
}
ScopeOwner scopeOwner = PsiTreeUtil.getParentOfType(function, ScopeOwner.class);
if (!(scopeOwner instanceof PyClass)) {
return false;
}
return classQualifiedName.equals(((PyClass)scopeOwner).getQualifiedName());
}
});
}
private static Callable resolveCalledFunction(Object o, String functionName, int index) {
if (!isCallArgument(o, functionName, index)) {
return null;
}
PyExpression expression = (PyExpression) o;
PyCallExpression call = (PyCallExpression) expression.getParent().getParent();
// TODO is it better or worse to allow implicits here?
PyResolveContext context = PyResolveContext.noImplicits()
.withTypeEvalContext(TypeEvalContext.codeAnalysis(expression.getContainingFile()));
PyCallExpression.PyMarkedCallee callee = call.resolveCallee(context);
return callee != null ? callee.getCallable() : null;
}
private static boolean isCallArgument(Object o, String functionName, int index) {
if (!(o instanceof PyExpression)) {
return false;
}
PsiElement parent = ((PyExpression)o).getParent();
if (!(parent instanceof PyArgumentList)) {
return false;
}
PsiElement parent1 = parent.getParent();
if (!(parent1 instanceof PyCallExpression)) {
return false;
}
PyExpression methodExpression = ((PyCallExpression)parent1).getCallee();
if (!(methodExpression instanceof PyReferenceExpression)) {
return false;
}
String referencedName = ((PyReferenceExpression)methodExpression).getReferencedName();
if (referencedName == null || !referencedName.equals(functionName)) {
return false;
}
int i = 0;
for (PsiElement child : parent.getChildren()) {
if (i == index) {
return child == o;
}
i++;
}
return false;
}
}
@@ -26,6 +26,6 @@ import static com.jetbrains.python.psi.types.PyTypeTokenTypes.*;
[\r\n]+ { return NL; }
[\ \t] { return SPACE; }
(":py"?":class:`"[~!]?)|("`")|([A-Z]"{")|("}") { return MARKUP; }
("or")|("of")|("from")|("to")|[,\(\)\.] { return OP; }
("or")|("of")|("from")|("to")|[,\(\)\.\[\]|] { return OP; }
[T-Z] { return PARAMETER; }
[A-Za-z_][A-Za-z_0-9]* { return IDENTIFIER; }
@@ -253,6 +253,9 @@ public class PyTypeChecker {
final Map<PyGenericType, PyType> substitutions = collectCallGenerics(function, receiver, context);
for (Map.Entry<PyExpression, PyNamedParameter> entry : arguments.entrySet()) {
final PyNamedParameter p = entry.getValue();
if (p.isPositionalContainer() || p.isKeywordContainer()) {
continue;
}
final PyType argType = context.getType(entry.getKey());
final PyType paramType = context.getType(p);
if (!match(paramType, argType, context, substitutions)) {
@@ -1,4 +1,4 @@
/* The following code was generated by JFlex 1.4.3 on 6/24/13 5:23 PM */
/* The following code was generated by JFlex 1.4.3 on 7/19/13 2:41 PM */
package com.jetbrains.python.psi.types;
@@ -11,7 +11,7 @@ import static com.jetbrains.python.psi.types.PyTypeTokenTypes.*;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 6/24/13 5:23 PM from the specification file
* on 7/19/13 2:41 PM from the specification file
* <tt>/home/user/src/idea/tools/lexer/../../python/src/com/jetbrains/python/psi/types/PyType.flex</tt>
*/
public class PyTypeLexer implements FlexLexer {
@@ -37,9 +37,9 @@ public class PyTypeLexer implements FlexLexer {
private static final String ZZ_CMAP_PACKED =
"\11\0\1\2\1\1\2\0\1\1\22\0\1\2\1\13\6\0\2\24"+
"\2\0\1\24\1\0\1\24\1\0\12\27\1\3\6\0\23\14\7\25"+
"\4\0\1\26\1\12\1\10\1\26\1\6\2\26\1\21\5\26\1\7"+
"\1\22\1\26\1\17\1\4\1\26\1\20\1\11\1\23\4\26\1\5"+
"\1\26\1\15\1\0\1\16\1\13\uff81\0";
"\1\24\1\0\1\24\1\0\1\26\1\12\1\10\1\26\1\6\2\26"+
"\1\21\5\26\1\7\1\22\1\26\1\17\1\4\1\26\1\20\1\11"+
"\1\23\4\26\1\5\1\26\1\15\1\24\1\16\1\13\uff81\0";
/**
* Translates characters to character classes
@@ -254,7 +254,7 @@ public class PyTypeLexer implements FlexLexer {
char [] map = new char[0x10000];
int i = 0; /* index in packed string */
int j = 0; /* index in unpacked array */
while (i < 92) {
while (i < 98) {
int count = packed.charAt(i++);
char value = packed.charAt(i++);
do map[j++] = value; while (--count > 0);
@@ -161,24 +161,50 @@ public class PyTypeParser {
.named("simple-expr");
final FunctionalParser<ParseResult, PyElementType> paramExpr =
simpleExpr.thenSkip(op("of")).then(simpleExpr)
.map(new Function<Pair<ParseResult, ParseResult>, ParseResult>() {
simpleExpr.thenSkip(op("[")).then(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op("]"))
.map(new Function<Pair<Pair<ParseResult, ParseResult>, List<ParseResult>>, ParseResult>() {
@Override
public ParseResult fun(Pair<ParseResult, ParseResult> value) {
final ParseResult firstResult = value.getFirst();
final ParseResult secondResult = value.getSecond();
final ParseResult result = firstResult.merge(secondResult);
final PyType firstType = firstResult.getType();
final PyType secondType = secondResult.getType();
if (firstType != null) {
if (firstType instanceof PyClassType && secondType != null) {
return result.withType(new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, secondType));
public ParseResult fun(Pair<Pair<ParseResult, ParseResult>, List<ParseResult>> value) {
final Pair<ParseResult, ParseResult> firstPair = value.getFirst();
final ParseResult first = firstPair.getFirst();
final ParseResult second = firstPair.getSecond();
final List<ParseResult> third = value.getSecond();
final PyType firstType = first.getType();
if (firstType instanceof PyClassType) {
final List<PyType> tupleTypes = new ArrayList<PyType>();
tupleTypes.add(second.getType());
ParseResult result = first;
result = result.merge(second);
for (ParseResult r : third) {
tupleTypes.add(r.getType());
result = result.merge(r);
}
return result.withType(firstType);
final PyType elementType = third.isEmpty() ? second.getType() :
PyTupleType.create(anchor, tupleTypes.toArray(new PyType[tupleTypes.size()]));
final PyCollectionTypeImpl type = new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, elementType);
return result.withType(type);
}
return EMPTY_RESULT;
}
})
.or(simpleExpr.thenSkip(op("of")).then(simpleExpr)
.map(new Function<Pair<ParseResult, ParseResult>, ParseResult>() {
@Override
public ParseResult fun(Pair<ParseResult, ParseResult> value) {
final ParseResult firstResult = value.getFirst();
final ParseResult secondResult = value.getSecond();
final ParseResult result = firstResult.merge(secondResult);
final PyType firstType = firstResult.getType();
final PyType secondType = secondResult.getType();
if (firstType != null) {
if (firstType instanceof PyClassType && secondType != null) {
return result.withType(new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, secondType));
}
return result.withType(firstType);
}
return EMPTY_RESULT;
}
}))
.or(simpleExpr.thenSkip(op("from")).then(simpleExpr).thenSkip(op("to")).then(simpleExpr)
.map(new Function<Pair<Pair<ParseResult, ParseResult>, ParseResult>, ParseResult>() {
@Override
@@ -200,7 +226,7 @@ public class PyTypeParser {
.named("param-expr");
final FunctionalParser<ParseResult, PyElementType> unionExpr =
paramExpr.then(many(op("or").skipThen(paramExpr)))
paramExpr.then(many(op("or").or(op("|")).skipThen(paramExpr)))
.map(new Function<Pair<ParseResult, List<ParseResult>>, ParseResult>() {
@Override
public ParseResult fun(Pair<ParseResult, List<ParseResult>> value) {
@@ -63,7 +63,7 @@ public abstract class PythonCommandLineState extends CommandLineState {
private Boolean myMultiprocessDebug = null;
public boolean isDebug() {
return isDebug(getConfigurationSettings());
return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunnerId());
}
public static ServerSocket createServerSocket() throws ExecutionException {
@@ -78,10 +78,6 @@ public abstract class PythonCommandLineState extends CommandLineState {
return serverSocket;
}
protected static boolean isDebug(ConfigurationPerRunnerSettings configurationSettings) {
return PyDebugRunner.PY_DEBUG_RUNNER.equals(configurationSettings.getRunnerId());
}
public PythonCommandLineState(AbstractPythonRunConfiguration runConfiguration, ExecutionEnvironment env, List<Filter> filters) {
super(env);
myConfig = runConfiguration;
@@ -153,8 +149,10 @@ public abstract class PythonCommandLineState extends CommandLineState {
// Extend command line
RunnerSettings runnerSettings = getRunnerSettings();
PythonRunConfigurationExtensionsManager.getInstance()
.patchCommandLine(myConfig, runnerSettings, commandLine, getConfigurationSettings().getRunnerId());
String runnerId = getEnvironment().getRunnerId();
if (runnerId != null) {
PythonRunConfigurationExtensionsManager.getInstance().patchCommandLine(myConfig, runnerSettings, commandLine, runnerId);
}
Sdk sdk = PythonSdkType.findSdkByPath(myConfig.getInterpreterPath());
@@ -0,0 +1,10 @@
from distutils.core import setup
requires = [
'mynose'
]
setup(name='foo',
version=0.1,
install_requires=requires,
tests_require=requires)
@@ -0,0 +1,2 @@
<warning descr="Package requirement 'mynose' is not satisfied">print("Hello, World!")
</warning>
@@ -184,4 +184,47 @@ public class PyTypeParserTest extends PyTestCase {
final PyType bound = genericType.getBound();
assertInstanceOf(bound, PyUnionType.class);
}
public void testBracketSingleParam() {
myFixture.configureByFile("typeParser/typeParser.py");
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "list[int]");
assertInstanceOf(type, PyCollectionType.class);
final PyCollectionType collectionType = (PyCollectionType)type;
assertNotNull(collectionType);
assertEquals("list", collectionType.getName());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback());
assertNotNull(elementType);
assertEquals("int", elementType.getName());
}
public void testBracketMultipleParams() {
myFixture.configureByFile("typeParser/typeParser.py");
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "dict[str, int]");
assertInstanceOf(type, PyCollectionType.class);
final PyCollectionType collectionType = (PyCollectionType)type;
assertNotNull(collectionType);
assertEquals("dict", collectionType.getName());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback());
assertNotNull(elementType);
assertInstanceOf(elementType, PyTupleType.class);
final PyTupleType tupleType = (PyTupleType)elementType;
final PyType first = tupleType.getElementType(0);
assertNotNull(first);
assertEquals("str", first.getName());
final PyType second = tupleType.getElementType(1);
assertNotNull(second);
assertEquals("int", second.getName());
}
public void testUnionOrOperator() {
myFixture.configureByFile("typeParser/typeParser.py");
final PyUnionType type = (PyUnionType)PyTypeParser.getTypeByName(myFixture.getFile(), "MyObject | str | unicode");
assertNotNull(type);
final Collection<PyType> members = type.getMembers();
assertEquals(3, members.size());
final List<PyType> list = new ArrayList<PyType>(members);
assertClassType(list.get(0), "MyObject");
assertClassType(list.get(1), "str");
assertClassType(list.get(2), "unicode");
}
}
@@ -7,6 +7,8 @@ import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.psi.stubs.StubUpdatingIndex;
import com.intellij.util.indexing.FileBasedIndex;
import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NonNls;
@@ -59,8 +61,9 @@ public class PythonMockSdk {
String mock_stubs_path = mock_path + PythonSdkType.SKELETON_DIR_NAME;
sdkModificator.addRoot(LocalFileSystem.getInstance().refreshAndFindFileByPath(mock_stubs_path), PythonSdkType.BUILTIN_ROOT_TYPE);
//PythonSdkType.setupSdkPaths(sdkModificator, null);
sdkModificator.commitChanges();
FileBasedIndex.getInstance().requestRebuild(StubUpdatingIndex.INDEX_ID);
return sdk;
}
}