@zzzen/pyright-internal 1.2.0-dev.20250119 → 1.2.0-dev.20250202

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/analyzer/backgroundAnalysisProgram.d.ts +1 -0
  2. package/dist/analyzer/backgroundAnalysisProgram.js +3 -0
  3. package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
  4. package/dist/analyzer/binder.js +24 -12
  5. package/dist/analyzer/binder.js.map +1 -1
  6. package/dist/analyzer/checker.d.ts +1 -1
  7. package/dist/analyzer/checker.js +29 -24
  8. package/dist/analyzer/checker.js.map +1 -1
  9. package/dist/analyzer/dataClasses.js +4 -4
  10. package/dist/analyzer/dataClasses.js.map +1 -1
  11. package/dist/analyzer/enums.js +140 -126
  12. package/dist/analyzer/enums.js.map +1 -1
  13. package/dist/analyzer/importResolver.d.ts +3 -2
  14. package/dist/analyzer/importResolver.js +80 -79
  15. package/dist/analyzer/importResolver.js.map +1 -1
  16. package/dist/analyzer/parseTreeUtils.d.ts +1 -0
  17. package/dist/analyzer/parseTreeUtils.js +14 -0
  18. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  19. package/dist/analyzer/pythonPathUtils.d.ts +2 -0
  20. package/dist/analyzer/pythonPathUtils.js +20 -11
  21. package/dist/analyzer/pythonPathUtils.js.map +1 -1
  22. package/dist/analyzer/service.js +2 -5
  23. package/dist/analyzer/service.js.map +1 -1
  24. package/dist/analyzer/tuples.d.ts +1 -0
  25. package/dist/analyzer/tuples.js +34 -0
  26. package/dist/analyzer/tuples.js.map +1 -1
  27. package/dist/analyzer/typeEvaluator.js +90 -49
  28. package/dist/analyzer/typeEvaluator.js.map +1 -1
  29. package/dist/analyzer/typeGuards.js +10 -7
  30. package/dist/analyzer/typeGuards.js.map +1 -1
  31. package/dist/backgroundAnalysis.js +2 -0
  32. package/dist/backgroundAnalysis.js.map +1 -1
  33. package/dist/backgroundThreadBase.d.ts +1 -0
  34. package/dist/backgroundThreadBase.js +5 -8
  35. package/dist/backgroundThreadBase.js.map +1 -1
  36. package/dist/common/envVarUtils.js +4 -0
  37. package/dist/common/envVarUtils.js.map +1 -1
  38. package/dist/common/languageServerInterface.d.ts +1 -1
  39. package/dist/common/realFileSystem.d.ts +1 -1
  40. package/dist/common/realFileSystem.js +10 -2
  41. package/dist/common/realFileSystem.js.map +1 -1
  42. package/dist/common/serviceProvider.d.ts +1 -0
  43. package/dist/common/serviceProvider.js +8 -0
  44. package/dist/common/serviceProvider.js.map +1 -1
  45. package/dist/languageServerBase.d.ts +3 -3
  46. package/dist/languageServerBase.js +7 -4
  47. package/dist/languageServerBase.js.map +1 -1
  48. package/dist/languageService/analyzerServiceExecutor.js +4 -1
  49. package/dist/languageService/analyzerServiceExecutor.js.map +1 -1
  50. package/dist/localization/localize.d.ts +4 -7
  51. package/dist/localization/localize.js +4 -2
  52. package/dist/localization/localize.js.map +1 -1
  53. package/dist/localization/package.nls.cs.json +8 -6
  54. package/dist/localization/package.nls.de.json +8 -6
  55. package/dist/localization/package.nls.en-us.json +12 -4
  56. package/dist/localization/package.nls.es.json +8 -6
  57. package/dist/localization/package.nls.fr.json +8 -6
  58. package/dist/localization/package.nls.it.json +8 -6
  59. package/dist/localization/package.nls.ja.json +8 -6
  60. package/dist/localization/package.nls.ko.json +8 -6
  61. package/dist/localization/package.nls.pl.json +8 -6
  62. package/dist/localization/package.nls.pt-br.json +8 -6
  63. package/dist/localization/package.nls.qps-ploc.json +4 -2
  64. package/dist/localization/package.nls.ru.json +8 -6
  65. package/dist/localization/package.nls.tr.json +8 -6
  66. package/dist/localization/package.nls.zh-cn.json +8 -6
  67. package/dist/localization/package.nls.zh-tw.json +8 -6
  68. package/dist/pyright.js +11 -4
  69. package/dist/pyright.js.map +1 -1
  70. package/dist/server.d.ts +2 -1
  71. package/dist/server.js +1 -1
  72. package/dist/server.js.map +1 -1
  73. package/dist/tests/config.test.js +451 -427
  74. package/dist/tests/config.test.js.map +1 -1
  75. package/dist/tests/harness/fourslash/fourSlashTypes.d.ts +2 -1
  76. package/dist/tests/harness/fourslash/fourSlashTypes.js +2 -0
  77. package/dist/tests/harness/fourslash/fourSlashTypes.js.map +1 -1
  78. package/dist/tests/harness/fourslash/testState.d.ts +3 -1
  79. package/dist/tests/harness/fourslash/testState.js +30 -23
  80. package/dist/tests/harness/fourslash/testState.js.map +1 -1
  81. package/dist/tests/importResolver.test.js +537 -527
  82. package/dist/tests/importResolver.test.js.map +1 -1
  83. package/dist/tests/sourceFile.test.js +1 -0
  84. package/dist/tests/sourceFile.test.js.map +1 -1
  85. package/dist/tests/testUtils.js +1 -0
  86. package/dist/tests/testUtils.js.map +1 -1
  87. package/dist/tests/typeEvaluator1.test.js +1 -1
  88. package/dist/tests/typeEvaluator3.test.js +4 -0
  89. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  90. package/dist/tests/typeEvaluator4.test.js +5 -1
  91. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  92. package/dist/tests/typeEvaluator5.test.js +1 -1
  93. package/dist/tests/typeEvaluator6.test.js +4 -0
  94. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  95. package/dist/tests/uri.test.js +3 -0
  96. package/dist/tests/uri.test.js.map +1 -1
  97. package/dist/tests/zipfs.test.js +2 -0
  98. package/dist/tests/zipfs.test.js.map +1 -1
  99. package/dist/workspaceFactory.d.ts +2 -1
  100. package/dist/workspaceFactory.js.map +1 -1
  101. package/package.json +1 -1
@@ -81,6 +81,7 @@ const tuples_1 = require("./tuples");
81
81
  const typeCacheUtils_1 = require("./typeCacheUtils");
82
82
  const typedDicts_1 = require("./typedDicts");
83
83
  const typeEvaluatorTypes_1 = require("./typeEvaluatorTypes");
84
+ const typeGuards_1 = require("./typeGuards");
84
85
  const TypePrinter = __importStar(require("./typePrinter"));
85
86
  const types_1 = require("./types");
86
87
  const typeUtils_1 = require("./typeUtils");
@@ -146,9 +147,9 @@ const maxDeclarationsToUseForInference = 64;
146
147
  // Maximum number of times to attempt effective type evaluation
147
148
  // of a variable that has no type declaration.
148
149
  const maxEffectiveTypeEvaluationAttempts = 16;
149
- // Maximum number of combinatoric union type expansions allowed
150
+ // Maximum number of combinatoric argument type expansions allowed
150
151
  // when resolving an overload.
151
- const maxOverloadUnionExpansionCount = 64;
152
+ const maxOverloadArgTypeExpansionCount = 64;
152
153
  // Maximum number of recursive function return type inference attempts
153
154
  // that can be concurrently pending before we give up.
154
155
  const maxInferFunctionReturnRecursionCount = 12;
@@ -2908,7 +2909,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
2908
2909
  case 54 /* ParseNodeType.TypeAnnotation */: {
2909
2910
  let annotationType = getTypeOfAnnotation(target.d.annotation, {
2910
2911
  varTypeAnnotation: true,
2911
- allowFinal: ParseTreeUtils.isFinalAllowedForAssignmentTarget(target.d.valueExpr),
2912
+ allowFinal: isFinalAllowedForAssignmentTarget(target.d.valueExpr),
2912
2913
  allowClassVar: isClassVarAllowedForAssignmentTarget(target.d.valueExpr),
2913
2914
  });
2914
2915
  if (annotationType) {
@@ -2960,16 +2961,28 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
2960
2961
  }
2961
2962
  }
2962
2963
  function isClassVarAllowedForAssignmentTarget(targetNode) {
2964
+ // ClassVar is allowed only in a class body.
2963
2965
  const classNode = ParseTreeUtils.getEnclosingClass(targetNode, /* stopAtFunction */ true);
2964
2966
  if (!classNode) {
2965
2967
  return false;
2966
2968
  }
2967
2969
  // ClassVar is not allowed in a TypedDict or a NamedTuple class.
2970
+ return !isInTypedDictOrNamedTuple(classNode);
2971
+ }
2972
+ function isFinalAllowedForAssignmentTarget(targetNode) {
2973
+ const classNode = ParseTreeUtils.getEnclosingClass(targetNode, /* stopAtFunction */ true);
2974
+ // Final is not allowed in the body of a TypedDict or NamedTuple class.
2975
+ if (classNode && isInTypedDictOrNamedTuple(classNode)) {
2976
+ return false;
2977
+ }
2978
+ return ParseTreeUtils.isFinalAllowedForAssignmentTarget(targetNode);
2979
+ }
2980
+ function isInTypedDictOrNamedTuple(classNode) {
2968
2981
  const classType = getTypeOfClass(classNode)?.classType;
2969
2982
  if (!classType) {
2970
2983
  return false;
2971
2984
  }
2972
- return !types_1.ClassType.isTypedDictClass(classType) && !classType.shared.namedTupleEntries;
2985
+ return types_1.ClassType.isTypedDictClass(classType) || !!classType.shared.namedTupleEntries;
2973
2986
  }
2974
2987
  function verifyRaiseExceptionType(node, allowNone) {
2975
2988
  const baseExceptionType = getBuiltInType(node, 'BaseException');
@@ -3265,7 +3278,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
3265
3278
  return true;
3266
3279
  }
3267
3280
  if ((0, types_1.isTypeVar)(type)) {
3268
- return true;
3281
+ if (type.props?.specialForm || type.props?.typeAliasInfo) {
3282
+ return true;
3283
+ }
3269
3284
  }
3270
3285
  // Exempts class types that are created by calling NewType, NamedTuple, etc.
3271
3286
  if ((0, types_1.isClass)(type) && !type.priv.includeSubclasses && types_1.ClassType.isValidTypeAliasClass(type)) {
@@ -6610,7 +6625,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6610
6625
  const speculativeNode = getSpeculativeNodeForCall(errorNode);
6611
6626
  // Start by evaluating the types of the arguments without any expected
6612
6627
  // type. Also, filter the list of overloads based on the number of
6613
- // positional and named arguments that are present. We do all of this
6628
+ // positional and keyword arguments that are present. We do all of this
6614
6629
  // speculatively because we don't want to record any types in the type
6615
6630
  // cache or record any diagnostics at this stage.
6616
6631
  useSpeculativeMode(speculativeNode, () => {
@@ -6716,9 +6731,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6716
6731
  });
6717
6732
  });
6718
6733
  }
6719
- expandedArgTypes = expandArgUnionTypes(contextFreeArgTypes, expandedArgTypes);
6734
+ expandedArgTypes = expandArgTypes(contextFreeArgTypes, expandedArgTypes);
6720
6735
  // Check for combinatoric explosion and break out of loop.
6721
- if (!expandedArgTypes || expandedArgTypes.length > maxOverloadUnionExpansionCount) {
6736
+ if (!expandedArgTypes || expandedArgTypes.length > maxOverloadArgTypeExpansionCount) {
6722
6737
  break;
6723
6738
  }
6724
6739
  }
@@ -6737,12 +6752,13 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6737
6752
  return { argumentErrors: true, isTypeIncomplete, overloadsUsedForCall: [] };
6738
6753
  }
6739
6754
  // Replaces each item in the expandedArgTypes with n items where n is
6740
- // the number of subtypes in a union. The contextFreeArgTypes parameter
6741
- // represents the types of the arguments evaluated with no bidirectional
6742
- // type inference (i.e. without the help of the corresponding parameter's
6743
- // expected type). If the function returns undefined, that indicates that
6744
- // all unions have been expanded, and no more expansion is possible.
6745
- function expandArgUnionTypes(contextFreeArgTypes, expandedArgTypes) {
6755
+ // the number of subtypes in a union or other expandable type.
6756
+ // The contextFreeArgTypes parameter represents the types of the arguments
6757
+ // evaluated with no bidirectional type inference (i.e. without the help of
6758
+ // the corresponding parameter's expected type). If the function returns
6759
+ // undefined, that indicates that all types have been expanded, and no
6760
+ // more expansion is possible.
6761
+ function expandArgTypes(contextFreeArgTypes, expandedArgTypes) {
6746
6762
  // Find the rightmost already-expanded argument.
6747
6763
  let indexToExpand = contextFreeArgTypes.length - 1;
6748
6764
  while (indexToExpand >= 0 && !expandedArgTypes[0][indexToExpand]) {
@@ -6753,28 +6769,24 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6753
6769
  if (indexToExpand >= contextFreeArgTypes.length) {
6754
6770
  return undefined;
6755
6771
  }
6756
- let unionToExpand;
6772
+ let expandedTypes;
6757
6773
  while (indexToExpand < contextFreeArgTypes.length) {
6758
6774
  // Is this a union type? If so, we can expand it.
6759
6775
  const argType = contextFreeArgTypes[indexToExpand];
6760
- if ((0, types_1.isUnion)(argType)) {
6761
- unionToExpand = makeTopLevelTypeVarsConcrete(argType);
6762
- break;
6763
- }
6764
- else if ((0, types_1.isTypeVar)(argType) && types_1.TypeVarType.hasConstraints(argType)) {
6765
- unionToExpand = makeTopLevelTypeVarsConcrete(argType);
6776
+ expandedTypes = expandArgType(argType);
6777
+ if (expandedTypes) {
6766
6778
  break;
6767
6779
  }
6768
6780
  indexToExpand++;
6769
6781
  }
6770
6782
  // We have nothing left to expand.
6771
- if (!unionToExpand) {
6783
+ if (!expandedTypes) {
6772
6784
  return undefined;
6773
6785
  }
6774
6786
  // Expand entry indexToExpand.
6775
6787
  const newExpandedArgTypes = [];
6776
6788
  expandedArgTypes.forEach((preExpandedTypes) => {
6777
- (0, typeUtils_1.doForEachSubtype)(unionToExpand, (subtype) => {
6789
+ expandedTypes.forEach((subtype) => {
6778
6790
  const expandedTypes = [...preExpandedTypes];
6779
6791
  expandedTypes[indexToExpand] = subtype;
6780
6792
  newExpandedArgTypes.push(expandedTypes);
@@ -6782,6 +6794,29 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6782
6794
  });
6783
6795
  return newExpandedArgTypes;
6784
6796
  }
6797
+ function expandArgType(type) {
6798
+ const expandedTypes = [];
6799
+ // Expand any top-level type variables with constraints.
6800
+ type = makeTopLevelTypeVarsConcrete(type);
6801
+ (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
6802
+ if ((0, types_1.isClassInstance)(subtype)) {
6803
+ // Expand any bool or Enum literals.
6804
+ const expandedLiteralTypes = (0, typeGuards_1.enumerateLiteralsForType)(evaluatorInterface, subtype);
6805
+ if (expandedLiteralTypes) {
6806
+ (0, collectionUtils_1.appendArray)(expandedTypes, expandedLiteralTypes);
6807
+ return;
6808
+ }
6809
+ // Expand any fixed-size tuples.
6810
+ const expandedTuples = (0, tuples_1.expandTuple)(subtype, maxOverloadArgTypeExpansionCount);
6811
+ if (expandedTuples) {
6812
+ (0, collectionUtils_1.appendArray)(expandedTypes, expandedTuples);
6813
+ return;
6814
+ }
6815
+ }
6816
+ expandedTypes.push(subtype);
6817
+ });
6818
+ return expandedTypes.length > 1 ? expandedTypes : undefined;
6819
+ }
6785
6820
  // Validates that the arguments can be assigned to the call's parameter
6786
6821
  // list, specializes the call based on arg types, and returns the
6787
6822
  // specialized type of the return value. If it detects an error along
@@ -7566,9 +7601,6 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7566
7601
  listElementType = getTypeOfIterator({ type: argType, isIncomplete: argTypeResult.isIncomplete },
7567
7602
  /* isAsync */ false, errorNode,
7568
7603
  /* emitNotIterableError */ false)?.type;
7569
- if (paramInfo.param.category !== 1 /* ParamCategory.ArgsList */) {
7570
- matchedUnpackedListOfUnknownLength = true;
7571
- }
7572
7604
  }
7573
7605
  const funcArg = listElementType
7574
7606
  ? {
@@ -14078,7 +14110,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
14078
14110
  else {
14079
14111
  const annotationType = getTypeOfAnnotation(node.d.annotation, {
14080
14112
  varTypeAnnotation: true,
14081
- allowFinal: ParseTreeUtils.isFinalAllowedForAssignmentTarget(node.d.valueExpr),
14113
+ allowFinal: isFinalAllowedForAssignmentTarget(node.d.valueExpr),
14082
14114
  allowClassVar: isClassVarAllowedForAssignmentTarget(node.d.valueExpr),
14083
14115
  });
14084
14116
  writeTypeCache(node.d.valueExpr, { type: annotationType }, 0 /* EvalFlags.None */);
@@ -14190,7 +14222,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
14190
14222
  if (annotationNode === annotationParent.d.annotationComment) {
14191
14223
  getTypeOfAnnotation(annotationNode, {
14192
14224
  varTypeAnnotation: true,
14193
- allowFinal: ParseTreeUtils.isFinalAllowedForAssignmentTarget(annotationParent.d.leftExpr),
14225
+ allowFinal: isFinalAllowedForAssignmentTarget(annotationParent.d.leftExpr),
14194
14226
  allowClassVar: isClassVarAllowedForAssignmentTarget(annotationParent.d.leftExpr),
14195
14227
  });
14196
14228
  }
@@ -15735,7 +15767,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
15735
15767
  ? declaration.node.parent
15736
15768
  : declaration.node;
15737
15769
  const allowClassVar = isClassVarAllowedForAssignmentTarget(declNode);
15738
- const allowFinal = ParseTreeUtils.isFinalAllowedForAssignmentTarget(declNode);
15770
+ const allowFinal = isFinalAllowedForAssignmentTarget(declNode);
15739
15771
  const allowRequired = ParseTreeUtils.isRequiredAllowedForAssignmentTarget(declNode) ||
15740
15772
  !!declaration.isInInlinedTypedDict;
15741
15773
  declaredType = getTypeOfAnnotation(typeAnnotationNode, {
@@ -18904,26 +18936,35 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
18904
18936
  if (remainingParams.length > 0 ||
18905
18937
  !effectiveSrcParamSpec ||
18906
18938
  !(0, types_1.isTypeSame)(effectiveSrcParamSpec, effectiveDestParamSpec, { ignoreTypeFlags: true })) {
18907
- const remainingFunction = types_1.FunctionType.createInstance('', '', '', effectiveSrcType.shared.flags | 64 /* FunctionTypeFlags.SynthesizedMethod */, effectiveSrcType.shared.docString);
18908
- remainingFunction.shared.deprecatedMessage = effectiveSrcType.shared.deprecatedMessage;
18909
- remainingFunction.shared.typeVarScopeId = effectiveSrcType.shared.typeVarScopeId;
18910
- remainingFunction.priv.constructorTypeVarScopeId = effectiveSrcType.priv.constructorTypeVarScopeId;
18911
- remainingFunction.shared.methodClass = effectiveSrcType.shared.methodClass;
18912
- remainingParams.forEach((param) => {
18913
- types_1.FunctionType.addParam(remainingFunction, param);
18914
- });
18915
- if (effectiveSrcParamSpec) {
18916
- types_1.FunctionType.addParamSpecVariadics(remainingFunction, (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec));
18917
- }
18918
- if (!assignType(effectiveDestParamSpec, remainingFunction, /* diag */ undefined, constraints, flags)) {
18919
- // If we couldn't assign the function to the ParamSpec, see if we can
18920
- // assign only the ParamSpec. This is possible if there were no
18921
- // remaining parameters.
18922
- if (remainingParams.length > 0 ||
18923
- !effectiveSrcParamSpec ||
18924
- !assignType((0, typeUtils_1.convertToInstance)(effectiveDestParamSpec), (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec),
18925
- /* diag */ undefined, constraints, flags)) {
18926
- canAssign = false;
18939
+ const effectiveSrcPosCount = isContra ? destPositionalCount : srcPositionalCount;
18940
+ const effectiveDestPosCount = isContra ? srcPositionalCount : destPositionalCount;
18941
+ // If the src and dest both have ParamSpecs but the src has additional positional
18942
+ // parameters that have not been matched to dest positional parameters (probably due
18943
+ // to a Concatenate), don't attempt to assign the remaining parameters to the ParamSpec.
18944
+ if (!effectiveSrcParamSpec || effectiveSrcPosCount >= effectiveDestPosCount) {
18945
+ const remainingFunction = types_1.FunctionType.createInstance('', '', '', effectiveSrcType.shared.flags | 64 /* FunctionTypeFlags.SynthesizedMethod */, effectiveSrcType.shared.docString);
18946
+ remainingFunction.shared.deprecatedMessage = effectiveSrcType.shared.deprecatedMessage;
18947
+ remainingFunction.shared.typeVarScopeId = effectiveSrcType.shared.typeVarScopeId;
18948
+ remainingFunction.priv.constructorTypeVarScopeId =
18949
+ effectiveSrcType.priv.constructorTypeVarScopeId;
18950
+ remainingFunction.shared.methodClass = effectiveSrcType.shared.methodClass;
18951
+ remainingParams.forEach((param) => {
18952
+ types_1.FunctionType.addParam(remainingFunction, param);
18953
+ });
18954
+ if (effectiveSrcParamSpec) {
18955
+ types_1.FunctionType.addParamSpecVariadics(remainingFunction, (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec));
18956
+ }
18957
+ if (!assignType(effectiveDestParamSpec, remainingFunction,
18958
+ /* diag */ undefined, constraints, flags)) {
18959
+ // If we couldn't assign the function to the ParamSpec, see if we can
18960
+ // assign only the ParamSpec. This is possible if there were no
18961
+ // remaining parameters.
18962
+ if (remainingParams.length > 0 ||
18963
+ !effectiveSrcParamSpec ||
18964
+ !assignType((0, typeUtils_1.convertToInstance)(effectiveDestParamSpec), (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec),
18965
+ /* diag */ undefined, constraints, flags)) {
18966
+ canAssign = false;
18967
+ }
18927
18968
  }
18928
18969
  }
18929
18970
  }