text:
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.psi.types;

import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.ResolveResult;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.codeInsight.typing.PyProtocolsKt;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyTypeProvider;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.pyi.PyiFile;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

import static com.jetbrains.python.codeInsight.typing.PyProtocolsKt.inspectProtocolSubclass;
import static com.jetbrains.python.psi.PyUtil.as;
import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.*;

/**
 * @author vlan
 */
public class PyTypeChecker {
  private PyTypeChecker() {
  }

  /**
   * See {@link PyTypeChecker#match(PyType, PyType, TypeEvalContext, Map)} for description.
   */
  public static boolean match(@Nullable PyType expected, @Nullable PyType actual, @NotNull TypeEvalContext context) {
    return match(expected, actual, new MatchContext(context, new HashMap<>())).orElse(true);
  }

  /**
   * Checks whether a type {@code actual} can be placed where {@code expected} is expected.
   *
   * For example {@code int} matches {@code object}, while {@code str} doesn't match {@code int}.
   * Work for builtin types, classes, tuples etc.
   *
   * Whether it's unknown if {@code actual} match {@code expected} the method returns {@code true}.
   *
   * @implNote This behavior may be changed in future by replacing {@code boolean} with {@code Optional<Boolean>} and updating the clients.
   *
   * @param expected expected type
   * @param actual type to be matched against expected
   * @param context type evaluation context
   * @param substitutions map of substitutions for {@code expected} type
   * @return {@code false} if {@code expected} and {@code actual} don't match, true otherwise
   */
  public static boolean match(@Nullable PyType expected,
                              @Nullable PyType actual,
                              @NotNull TypeEvalContext context,
                              @NotNull Map<PyGenericType, PyType> substitutions) {
    return match(expected, actual, new MatchContext(context, substitutions)).orElse(true);
  }

  @NotNull
  private static Optional<Boolean> match(@Nullable PyType expected, @Nullable PyType actual, @NotNull MatchContext context) {
    final Pair<PyType, PyType> types = Pair.create(expected, actual);
    if (context.matching.contains(types)) return Optional.of(true);

    context.matching.add(types);
    final Optional<Boolean> result = matchImpl(expected, actual, context);
    context.matching.remove(types);

    return result;
  }

  /**
   * Perform type matching.
   *
   * Implementation details:
   *

   *
The method mutates {@code context.substitutions} map adding new entries into it
   *
The order of match subroutine calls is important
   *
The method may recursively call itself
   *

   */
  @NotNull
  private static Optional<Boolean> matchImpl(@Nullable PyType expected, @Nullable PyType actual, @NotNull MatchContext context) {
    if (expected instanceof PyClassType) {
      Optional<Boolean> match = matchObject((PyClassType)expected, actual);
      if (match.isPresent()) {
        return match;
      }
    }

    if (expected instanceof PyInstantiableType && actual instanceof PyInstantiableType) {
      Optional<Boolean> match = match((PyInstantiableType)expected, (PyInstantiableType)actual, context);
      if (match.isPresent()) {
        return match;
      }
    }

    if (expected instanceof PyGenericType) {
      return Optional.of(match((PyGenericType)expected, actual, context));
    }

    if (expected == null || actual == null || isUnknown(actual, context.context)) {
      return Optional.of(true);
    }

    if (actual instanceof PyUnionType) {
      return Optional.of(match(expected, (PyUnionType)actual, context));
    }

    if (expected instanceof PyUnionType) {
      return Optional.of(match((PyUnionType)expected, actual, context));
    }

    if (expected instanceof PyClassType && actual instanceof PyClassType) {
      Optional<Boolean> match = match((PyClassType)expected, (PyClassType)actual, context);
      if (match.isPresent()) {
        return match;
      }
    }

    if (actual instanceof PyStructuralType && ((PyStructuralType)actual).isInferredFromUsages()) {
      return Optional.of(true);
    }

    if (expected instanceof PyStructuralType) {
      return Optional.of(match((PyStructuralType)expected, actual, context.context));
    }

    if (actual instanceof PyStructuralType && expected instanceof PyClassType) {
      final Set<String> expectedAttributes = ((PyClassType)expected).getMemberNames(true, context.context);
      return Optional.of(expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames()));
    }

    if (actual instanceof PyCallableType && expected instanceof PyCallableType) {
      final PyCallableType expectedCallable = (PyCallableType)expected;
      final PyCallableType actualCallable = (PyCallableType)actual;
      final Optional<Boolean> match = match(expectedCallable, actualCallable, context);
      if (match.isPresent()) {
        return match;
      }
    }

    return Optional.of(matchNumericTypes(expected, actual));
  }

  /**
   * Check whether {@code expected} is Python *object* or *type*.
   *
   * {@see PyTypeChecker#match(PyType, PyType, TypeEvalContext, Map)}
   */
  @NotNull
  private static Optional<Boolean> matchObject(@NotNull PyClassType expected, @Nullable PyType actual) {
    if (ArrayUtil.contains(expected.getName(), PyNames.OBJECT, PyNames.TYPE)) {
      final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(expected.getPyClass());
      if (expected.equals(builtinCache.getObjectType())) {
        return Optional.of(true);
      }
      if (expected.equals(builtinCache.getTypeType()) &&
          actual instanceof PyInstantiableType && ((PyInstantiableType)actual).isDefinition()) {
        return Optional.of(true);
      }
    }
    return Optional.empty();
  }

  @NotNull
  private static Optional<Boolean> match(@NotNull PyInstantiableType expected, @NotNull PyInstantiableType actual,
                                         @NotNull MatchContext context) {
    if (expected instanceof PyGenericType && typeVarAcceptsBothClassAndInstanceTypes((PyGenericType)expected)) {
      return Optional.empty();
    }

    if (expected.isDefinition() ^ actual.isDefinition()) {
      if (actual.isDefinition() &&
          actual instanceof PyClassLikeType &&
          matchClassObjectAndMetaclass(expected, (PyClassLikeType)actual, context)) {
        return Optional.of(true);
      }
      return Optional.of(false);
    }

    return Optional.empty();
  }

  /**
   * Match {@code actual} versus {@code PyGenericType expected}.
   *
   * The method mutates {@code context.substitutions} map adding new entries into it
   */
  private static boolean match(@NotNull PyGenericType expected, @Nullable PyType actual, @NotNull MatchContext context) {
    final PyType substitution = context.substitutions.get(expected);
    PyType bound = expected.getBound();
    // Promote int in Type[TypeVar('T', int)] to Type[int] before checking that bounds match
    if (expected.isDefinition() && bound instanceof PyInstantiableType) {
      bound = ((PyInstantiableType)bound).toClass();
    }

    Optional<Boolean> match = match(bound, actual, context);
    if (match.isPresent() && !match.get()) {
      return false;
    }

    if (substitution != null) {
      if (expected.equals(actual) || substitution.equals(expected)) {
        return true;
      }
      if (context.recursive) {
        Optional<Boolean> recursiveMatch = match(substitution, actual, context.notRecursive());
        if (recursiveMatch.isPresent()) {
          return recursiveMatch.get();
        }
      }
      return false;
    }

    if (actual != null) {
      context.substitutions.put(expected, actual);
    }
    else if (bound != null) {
      context.substitutions.put(expected, bound);
    }

    return true;
  }

  private static boolean match(@NotNull PyType expected, @NotNull PyUnionType actual, @NotNull MatchContext context) {
    if (expected instanceof PyTupleType) {
      Optional<Boolean> match = match((PyTupleType)expected, actual, context);
      if (match.isPresent()) {
        return match.get();
      }
    }

    return StreamEx.of(actual.getMembers()).anyMatch(type -> match(expected, type, context).orElse(false));
  }

  @NotNull
  private static Optional<Boolean> match(@NotNull PyTupleType expected, @NotNull PyUnionType actual, @NotNull MatchContext context) {
    final int elementCount = expected.getElementCount();

    if (!expected.isHomogeneous() && consistsOfSameElementNumberTuples(actual, elementCount)) {
      return Optional.of(substituteExpectedElementsWithUnions(expected, elementCount, actual, context));
    }

    return Optional.empty();
  }

  private static boolean match(@NotNull PyUnionType expected, @NotNull PyType actual, @NotNull MatchContext context) {
    return StreamEx.of(expected.getMembers()).anyMatch(type -> match(type, actual, context).orElse(true));
  }

  @NotNull
  private static Optional<Boolean> match(@NotNull PyClassType expected, @NotNull PyClassType actual, @NotNull MatchContext context) {
    if (expected.equals(actual)) {
      return Optional.of(true);
    }

    if (expected instanceof PyTupleType && actual instanceof PyTupleType) {
      return match((PyTupleType)expected, (PyTupleType)actual, context);
    }

    final PyClass superClass = expected.getPyClass();
    final PyClass subClass = actual.getPyClass();
    final boolean matchClasses = matchClasses(superClass, subClass, context.context);

    if (PyProtocolsKt.isProtocol(expected, context.context) && !matchClasses) {
      if (expected instanceof PyCollectionType && !matchGenerics((PyCollectionType)expected, actual, context)) {
        return Optional.of(false);
      }

      for (kotlin.Pair<PyTypedElement, List<RatedResolveResult>> pair : inspectProtocolSubclass(expected, actual, context.context)) {
        final List<RatedResolveResult> subclassElements = pair.getSecond();
        if (ContainerUtil.isEmpty(subclassElements)) {
          return Optional.of(false);
        }

        final PyType protocolElementType = context.context.getType(pair.getFirst());

        final boolean elementResult = StreamEx
          .of(subclassElements)
          .map(ResolveResult::getElement)
          .select(PyTypedElement.class)
          .map(context.context::getType)
          .anyMatch(subclassElementType -> match(protocolElementType, subclassElementType, context).orElse(true));

        if (!elementResult) {
          return Optional.of(false);
        }
      }

      final PyType originalProtocolGenericType = StreamEx
        .of(Extensions.getExtensions(PyTypeProvider.EP_NAME))
        .map(provider -> provider.getGenericType(superClass, context.context))
        .findFirst(Objects::nonNull)
        .orElse(null);

      // actual was matched against protocol definition above
      // and here protocol usage is matched against its definition to update substitutions
      match(expected, originalProtocolGenericType, context);

      return Optional.of(true);
    }

    if (expected instanceof PyCollectionType) {
      return Optional.of(match((PyCollectionType)expected, actual, context));
    }

    if (matchClasses) {
      if (expected instanceof PyTypingNewType && !expected.equals(actual) && superClass.equals(subClass)) {
        return Optional.of(actual.getAncestorTypes(context.context).contains(expected));
      }
      return Optional.of(true);
    }

    if (expected.equals(actual)) {
      return Optional.of(true);
    }
    return Optional.empty();
  }

  @NotNull
  private static Optional<Boolean> match(@NotNull PyTupleType expected, @NotNull PyTupleType actual, @NotNull MatchContext context) {
    if (!expected.isHomogeneous() && !actual.isHomogeneous()) {
      if (expected.getElementCount() != actual.getElementCount()) {
        return Optional.of(false);
      }

      for (int i = 0; i < expected.getElementCount(); i++) {
        if (!match(expected.getElementType(i), actual.getElementType(i), context).orElse(true)) {
          return Optional.of(false);
        }
      }
      return Optional.of(true);
    }

    if (expected.isHomogeneous() && !actual.isHomogeneous()) {
      final PyType expectedElementType = expected.getIteratedItemType();
      for (int i = 0; i < actual.getElementCount(); i++) {
        if (!match(expectedElementType, actual.getElementType(i), context).orElse(true)) {
          return Optional.of(false);
        }
      }
      return Optional.of(true);
    }

    if (!expected.isHomogeneous() && actual.isHomogeneous()) {
      return Optional.of(false);
    }

    return match(expected.getIteratedItemType(), actual.getIteratedItemType(), context);
  }

  private static boolean match(@NotNull PyCollectionType expected, @NotNull PyClassType actual, @NotNull MatchContext context) {
    if (actual instanceof PyTupleType) {
      return match(expected, (PyTupleType)actual, context);
    }

    final PyClass superClass = expected.getPyClass();
    final PyClass subClass = actual.getPyClass();

    return matchClasses(superClass, subClass, context.context) && matchGenerics(expected, actual, context);
  }

  private static boolean match(@NotNull PyCollectionType expected, @NotNull PyTupleType actual, @NotNull MatchContext context) {
    if (!matchClasses(expected.getPyClass(), actual.getPyClass(), context.context)) {
      return false;
    }

    final PyType superElementType = expected.getIteratedItemType();
    final PyType subElementType = actual.getIteratedItemType();

    if (!match(superElementType, subElementType, context).orElse(true)) {
      return false;
    }

    return true;
  }

  private static boolean match(@NotNull PyStructuralType expected, @NotNull PyType actual, @NotNull TypeEvalContext context) {
    if (actual instanceof PyStructuralType) {
      return match(expected, (PyStructuralType)actual);
    }
    if (actual instanceof PyClassType) {
      return match(expected, (PyClassType)actual, context);
    }
    if (actual instanceof PyModuleType) {
      final PyFile module = ((PyModuleType)actual).getModule();
      if (module.getLanguageLevel().isAtLeast(LanguageLevel.PYTHON37) && definesGetAttr(module, context)) {
        return true;
      }
    }

    final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
    return StreamEx
      .of(expected.getAttributeNames())
      .noneMatch(attribute -> ContainerUtil.isEmpty(actual.resolveMember(attribute, null, AccessDirection.READ, resolveContext)));
  }

  private static boolean match(@NotNull PyStructuralType expected, @NotNull PyStructuralType actual) {
    if (expected.isInferredFromUsages()) {
      return true;
    }
    return expected.getAttributeNames().containsAll(actual.getAttributeNames());
  }

  private static boolean match(@NotNull PyStructuralType expected, @NotNull PyClassType actual, @NotNull TypeEvalContext context) {
    if (overridesGetAttr(actual.getPyClass(), context)) {
      return true;
    }
    final Set<String> actualAttributes = actual.getMemberNames(true, context);
    return actualAttributes.containsAll(expected.getAttributeNames());
  }

  @NotNull
  private static Optional<Boolean> match(@NotNull PyCallableType expected, @NotNull PyCallableType actual, @NotNull MatchContext context) {
    if (expected.isCallable() && actual.isCallable()) {
      final List<PyCallableParameter> expectedParameters = expected.getParameters(context.context);
      final List<PyCallableParameter> actualParameters = actual.getParameters(context.context);
      if (expectedParameters != null && actualParameters != null) {
        final int size = Math.min(expectedParameters.size(), actualParameters.size());
        for (int i = 0; i < size; i++) {
          final PyCallableParameter expectedParam = expectedParameters.get(i);
          final PyCallableParameter actualParam = actualParameters.get(i);
          // TODO: Check named and star params, not only positional ones
          if (!match(expectedParam.getType(context.context), actualParam.getType(context.context), context).orElse(true)) {
            return Optional.of(false);
          }
        }
      }
      if (!match(expected.getReturnType(context.context), actual.getReturnType(context.context), context).orElse(true)) {
        return Optional.of(false);
      }
      return Optional.of(true);
    }
    return Optional.empty();
  }

  private static boolean matchClassObjectAndMetaclass(@NotNull PyType expected,
                                                      @NotNull PyClassLikeType actual,
                                                      @NotNull MatchContext context) {

    if (!actual.isDefinition()) {
      return false;
    }
    final PyClassLikeType metaClass = actual.getMetaClassType(context.context, true);
    return metaClass != null && match(expected, metaClass, context).orElse(true);
  }

  private static boolean typeVarAcceptsBothClassAndInstanceTypes(@NotNull PyGenericType typeVar) {
    return !typeVar.isDefinition() && typeVar.getBound() == null;
  }

  private static boolean consistsOfSameElementNumberTuples(@NotNull PyUnionType unionType, int elementCount) {
    for (PyType type : unionType.getMembers()) {
      if (type instanceof PyTupleType) {
        final PyTupleType tupleType = (PyTupleType)type;

        if (!tupleType.isHomogeneous() && elementCount != tupleType.getElementCount()) {
          return false;
        }
      }
      else {
        return false;
      }
    }

    return true;
  }

  private static boolean substituteExpectedElementsWithUnions(@NotNull PyTupleType expected,
                                                              int elementCount,
                                                              @NotNull PyUnionType actual,
                                                              @NotNull MatchContext context) {
    for (int i = 0; i < elementCount; i++) {
      final int currentIndex = i;

      final PyType elementType = PyUnionType.union(
        StreamEx
          .of(actual.getMembers())
          .select(PyTupleType.class)
          .map(type -> type.getElementType(currentIndex))
          .toList()
      );

      if (!match(expected.getElementType(i), elementType, context).orElse(true)) {
        return false;
      }
    }

    return true;
  }

  private static boolean matchGenerics(@NotNull PyCollectionType expected, @NotNull PyType actual, @NotNull MatchContext context) {
    // TODO: Match generic parameters based on the correspondence between the generic parameters of subClass and its base classes
    final List<PyType> superElementTypes = expected.getElementTypes();
    final PyCollectionType actualCollectionType = as(actual, PyCollectionType.class);
    final List<PyType> subElementTypes = actualCollectionType != null ?
                                         actualCollectionType.getElementTypes() :
                                         Collections.emptyList();
    for (int i = 0; i < superElementTypes.size(); i++) {
      final PyType subElementType = i < subElementTypes.size() ? subElementTypes.get(i) : null;
      if (!match(superElementTypes.get(i), subElementType, context).orElse(true)) {
        return false;
      }
    }
    return true;
  }

  private static boolean matchNumericTypes(PyType expected, PyType actual) {
    final String superName = expected.getName();
    final String subName = actual.getName();
    final boolean subIsBool = "bool".equals(subName);
    final boolean subIsInt = PyNames.TYPE_INT.equals(subName);
    final boolean subIsLong = PyNames.TYPE_LONG.equals(subName);
    final boolean subIsFloat = "float".equals(subName);
    final boolean subIsComplex = "complex".equals(subName);
    if (superName == null || subName == null ||
        superName.equals(subName) ||
        (PyNames.TYPE_INT.equals(superName) && subIsBool) ||
        ((PyNames.TYPE_LONG.equals(superName) || PyNames.ABC_INTEGRAL.equals(superName)) && (subIsBool || subIsInt)) ||
        (("float".equals(superName) || PyNames.ABC_REAL.equals(superName)) && (subIsBool || subIsInt || subIsLong)) ||
        (("complex".equals(superName) || PyNames.ABC_COMPLEX.equals(superName)) && (subIsBool || subIsInt || subIsLong || subIsFloat)) ||
        (PyNames.ABC_NUMBER.equals(superName) && (subIsBool || subIsInt || subIsLong || subIsFloat || subIsComplex))) {
      return true;
    }
    return false;
  }

  public static boolean isUnknown(@Nullable PyType type, @NotNull TypeEvalContext context) {
    return isUnknown(type, true, context);
  }

  public static boolean isUnknown(@Nullable PyType type, boolean genericsAreUnknown, @NotNull TypeEvalContext context) {
    if (type == null || (genericsAreUnknown && type instanceof PyGenericType)) {
      return true;
    }
    if (type instanceof PyFunctionType) {
      final PyCallable callable = ((PyFunctionType)type).getCallable();
      if (callable instanceof PyDecoratable &&
          PyKnownDecoratorUtil.hasUnknownOrChangingReturnTypeDecorator((PyDecoratable)callable, context)) {
        return true;
      }
    }
    if (type instanceof PyUnionType) {
      final PyUnionType union = (PyUnionType)type;
      for (PyType t : union.getMembers()) {
        if (isUnknown(t, genericsAreUnknown, context)) {
          return true;
        }
      }
    }
    return false;
  }

  @Nullable
  public static PyType toNonWeakType(@Nullable PyType type, @NotNull TypeEvalContext context) {
    if (type instanceof PyUnionType) {
      final PyUnionType unionType = (PyUnionType)type;
      if (unionType.isWeak()) {
        return unionType.excludeNull(context);
      }
    }
    return type;
  }

  public static boolean hasGenerics(@Nullable PyType type, @NotNull TypeEvalContext context) {
    final Set<PyGenericType> collected = new HashSet<>();
    collectGenerics(type, context, collected, new HashSet<>());
    return !collected.isEmpty();
  }

  private static void collectGenerics(@Nullable PyType type, @NotNull TypeEvalContext context, @NotNull Set<PyGenericType> collected,
                                      @NotNull Set<PyType> visited) {
    if (visited.contains(type)) {
      return;
    }
    visited.add(type);
    if (type instanceof PyGenericType) {
      collected.add((PyGenericType)type);
    }
    else if (type instanceof PyUnionType) {
      final PyUnionType union = (PyUnionType)type;
      for (PyType t : union.getMembers()) {
        collectGenerics(t, context, collected, visited);
      }
    }
    else if (type instanceof PyTupleType) {
      final PyTupleType tuple = (PyTupleType)type;
      final int n = tuple.isHomogeneous() ? 1 : tuple.getElementCount();
      for (int i = 0; i < n; i++) {
        collectGenerics(tuple.getElementType(i), context, collected, visited);
      }
    }
    else if (type instanceof PyCollectionType) {
      final PyCollectionType collection = (PyCollectionType)type;
      for (PyType elementType : collection.getElementTypes()) {
        collectGenerics(elementType, context, collected, visited);
      }
    }
    else if (type instanceof PyCallableType) {
      final PyCallableType callable = (PyCallableType)type;
      final List<PyCallableParameter> parameters = callable.getParameters(context);
      if (parameters != null) {
        for (PyCallableParameter parameter : parameters) {
          if (parameter != null) {
            collectGenerics(parameter.getType(context), context, collected, visited);
          }
        }
      }
      collectGenerics(callable.getReturnType(context), context, collected, visited);
    }
  }

  @Nullable
  public static PyType substitute(@Nullable PyType type, @NotNull Map<PyGenericType, PyType> substitutions,
                                  @NotNull TypeEvalContext context) {
    if (hasGenerics(type, context)) {
      if (type instanceof PyGenericType) {
        final PyGenericType typeVar = (PyGenericType)type;
        PyType substitution = substitutions.get(typeVar);
        if (substitution == null) {
          if (!typeVar.isDefinition()) {
            final PyInstantiableType<?> classType = as(substitutions.get(typeVar.toClass()), PyInstantiableType.class);
            if (classType != null) {
              substitution = classType.toInstance();
            }
          }
          else {
            final PyInstantiableType<?> instanceType = as(substitutions.get(typeVar.toInstance()), PyInstantiableType.class);
            if (instanceType != null) {
              substitution = instanceType.toClass();
            }
          }
        }
        if (substitution instanceof PyGenericType && !typeVar.equals(substitution) && substitutions.containsKey(substitution)) {
          return substitute(substitution, substitutions, context);
        }
        return substitution;
      }
      else if (type instanceof PyUnionType) {
        final PyUnionType union = (PyUnionType)type;
        final List<PyType> results = new ArrayList<>();
        for (PyType t : union.getMembers()) {
          final PyType subst = substitute(t, substitutions, context);
          results.add(subst);
        }
        return PyUnionType.union(results);
      }
      else if (type instanceof PyCollectionTypeImpl) {
        final PyCollectionTypeImpl collection = (PyCollectionTypeImpl)type;
        final List<PyType> elementTypes = collection.getElementTypes();
        final List<PyType> substitutes = new ArrayList<>();
        for (PyType elementType : elementTypes) {
          substitutes.add(substitute(elementType, substitutions, context));
        }
        return new PyCollectionTypeImpl(collection.getPyClass(), collection.isDefinition(), substitutes);
      }
      else if (type instanceof PyTupleType) {
        final PyTupleType tupleType = (PyTupleType)type;
        final PyClass tupleClass = tupleType.getPyClass();

        final List<PyType> oldElementTypes = tupleType.isHomogeneous()
                                             ? Collections.singletonList(tupleType.getIteratedItemType())
                                             : tupleType.getElementTypes();

        final List<PyType> newElementTypes =
          ContainerUtil.map(oldElementTypes, elementType -> substitute(elementType, substitutions, context));

        return new PyTupleType(tupleClass, newElementTypes, tupleType.isHomogeneous());
      }
      else if (type instanceof PyCallableType) {
        final PyCallableType callable = (PyCallableType)type;
        List<PyCallableParameter> substParams = null;
        final List<PyCallableParameter> parameters = callable.getParameters(context);
        if (parameters != null) {
          substParams = new ArrayList<>();
          for (PyCallableParameter parameter : parameters) {
            final PyType substType = substitute(parameter.getType(context), substitutions, context);
            final PyParameter psi = parameter.getParameter();
            final PyCallableParameter subst = psi != null ?
                                              PyCallableParameterImpl.psi(psi, substType) :
                                              PyCallableParameterImpl.nonPsi(parameter.getName(), substType, parameter.getDefaultValue());
            substParams.add(subst);
          }
        }
        final PyType substResult = substitute(callable.getReturnType(context), substitutions, context);
        return new PyCallableTypeImpl(substParams, substResult);
      }
    }
    return type;
  }

  @Nullable
  public static Map<PyGenericType, PyType> unifyGenericCall(@Nullable PyExpression receiver,
                                                            @NotNull Map<PyExpression, PyCallableParameter> arguments,
                                                            @NotNull TypeEvalContext context) {
    final Map<PyGenericType, PyType> substitutions = unifyReceiver(receiver, context);
    for (Map.Entry<PyExpression, PyCallableParameter> entry : getRegularMappedParameters(arguments).entrySet()) {
      final PyCallableParameter paramWrapper = entry.getValue();
      PyType actualType = context.getType(entry.getKey());
      if (paramWrapper.isSelf()) {
        // TODO find out a better way to pass the corresponding function inside
        final PyParameter param = paramWrapper.getParameter();
        final PyFunction function = as(ScopeUtil.getScopeOwner(param), PyFunction.class);
        if (function != null && function.getModifier() == PyFunction.Modifier.CLASSMETHOD) {
          final StreamEx<PyType> types;
          if (actualType instanceof PyUnionType) {
            types = StreamEx.of(((PyUnionType)actualType).getMembers());
          }
          else {
            types = StreamEx.of(actualType);
          }
          actualType = types
            .select(PyClassLikeType.class)
            .map(PyClassLikeType::toClass)
            .select(PyType.class)
            .foldLeft(PyUnionType::union)
            .orElse(actualType);
        }
      }
      final PyType expectedType = paramWrapper.getArgumentType(context);
      if (!match(expectedType, actualType, context, substitutions)) {
        return null;
      }
    }
    if (!matchContainer(getMappedPositionalContainer(arguments), getArgumentsMappedToPositionalContainer(arguments), substitutions,
                        context)) {
      return null;
    }
    if (!matchContainer(getMappedKeywordContainer(arguments), getArgumentsMappedToKeywordContainer(arguments), substitutions, context)) {
      return null;
    }
    return substitutions;
  }

  private static boolean matchContainer(@Nullable PyCallableParameter container, @NotNull List<PyExpression> arguments,
                                        @NotNull Map<PyGenericType, PyType> substitutions, @NotNull TypeEvalContext context) {
    if (container == null) {
      return true;
    }
    final List<PyType> types = ContainerUtil.map(arguments, context::getType);
    return match(container.getArgumentType(context), PyUnionType.union(types), context, substitutions);
  }

  @NotNull
  public static Map<PyGenericType, PyType> unifyReceiver(@Nullable PyExpression receiver, @NotNull TypeEvalContext context) {
    final Map<PyGenericType, PyType> substitutions = new LinkedHashMap<>();
    // Collect generic params of object type
    final Set<PyGenericType> generics = new LinkedHashSet<>();
    final PyType qualifierType = receiver != null ? context.getType(receiver) : null;
    collectGenerics(qualifierType, context, generics, new HashSet<>());
    for (PyGenericType t : generics) {
      substitutions.put(t, t);
    }
    if (qualifierType != null) {
      for (PyClassType type : toPossibleClassTypes(qualifierType)) {
        for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
          final PyType genericType = provider.getGenericType(type.getPyClass(), context);
          final Set<PyGenericType> providedTypeGenerics = new LinkedHashSet<>();

          if (genericType != null) {
            match(genericType, type, context, substitutions);
            collectGenerics(genericType, context, providedTypeGenerics, new HashSet<>());
          }

          for (Map.Entry<PyType, PyType> entry : provider.getGenericSubstitutions(type.getPyClass(), context).entrySet()) {
            final PyGenericType genericKey = as(entry.getKey(), PyGenericType.class);
            final PyType value = entry.getValue();

            if (genericKey != null &&
                value != null &&
                !substitutions.containsKey(genericKey) &&
                !providedTypeGenerics.contains(genericKey)) {
              substitutions.put(genericKey, value);
            }
          }
        }
      }
    }

    replaceUnresolvedGenericsWithAny(substitutions);
    return substitutions;
  }

  @NotNull
  private static List<PyClassType> toPossibleClassTypes(@NotNull PyType type) {
    final PyClassType classType = as(type, PyClassType.class);
    if (classType != null) {
      return Collections.singletonList(classType);
    }
    final PyUnionType unionType = as(type, PyUnionType.class);
    if (unionType != null) {
      return StreamEx.of(unionType.getMembers()).nonNull().flatMap(t -> toPossibleClassTypes(t).stream()).toList();
    }
    return Collections.emptyList();
  }

  private static void replaceUnresolvedGenericsWithAny(@NotNull Map<PyGenericType, PyType> substitutions) {
    final List<PyType> unresolvedGenerics =
      ContainerUtil.filter(substitutions.values(), type -> type instanceof PyGenericType && !substitutions.containsKey(type));

    for (PyType unresolvedGeneric : unresolvedGenerics) {
      substitutions.put((PyGenericType)unresolvedGeneric, null);
    }
  }

  private static boolean matchClasses(@Nullable PyClass superClass, @Nullable PyClass subClass, @NotNull TypeEvalContext context) {
    if (superClass == null ||
        subClass == null ||
        subClass.isSubclass(superClass, context) ||
        PyABCUtil.isSubclass(subClass, superClass, context) ||
        isStrUnicodeMatch(subClass, superClass) ||
        isBytearrayBytesStringMatch(subClass, superClass) ||
        PyUtil.hasUnresolvedAncestors(subClass, context)) {
      return true;
    }
    else {
      final String superName = superClass.getName();
      return superName != null && superName.equals(subClass.getName());
    }
  }

  private static boolean isStrUnicodeMatch(@NotNull PyClass subClass, @NotNull PyClass superClass) {
    // TODO: Check for subclasses as well
    return PyNames.TYPE_STR.equals(subClass.getName()) && PyNames.TYPE_UNICODE.equals(superClass.getName());
  }

  private static boolean isBytearrayBytesStringMatch(@NotNull PyClass subClass, @NotNull PyClass superClass) {
    if (!PyNames.TYPE_BYTEARRAY.equals(subClass.getName())) return false;

    final PsiFile subClassFile = subClass.getContainingFile();

    final boolean isPy2 = subClassFile instanceof PyiFile
                          ? PyBuiltinCache.getInstance(subClass).getObjectType(PyNames.TYPE_UNICODE) != null
                          : LanguageLevel.forElement(subClass).isPython2();

    final String superClassName = superClass.getName();
    return isPy2 && PyNames.TYPE_STR.equals(superClassName) || !isPy2 && PyNames.TYPE_BYTES.equals(superClassName);
  }

  @Nullable
  public static Boolean isCallable(@Nullable PyType type) {
    if (type == null) {
      return null;
    }
    if (type instanceof PyUnionType) {
      return isUnionCallable((PyUnionType)type);
    }
    if (type instanceof PyCallableType) {
      return ((PyCallableType)type).isCallable();
    }
    if (type instanceof PyStructuralType && ((PyStructuralType)type).isInferredFromUsages()) {
      return true;
    }
    return false;
  }

  /**
   * If at least one is callable -- it is callable.
   * If at least one is unknown -- it is unknown.
   * It is false otherwise.
   */
  @Nullable
  private static Boolean isUnionCallable(@NotNull final PyUnionType type) {
    for (final PyType member : type.getMembers()) {
      final Boolean callable = isCallable(member);
      if (callable == null) {
        return null;
      }
      if (callable) {
        return true;
      }
    }
    return false;
  }

  public static boolean definesGetAttr(@NotNull PyFile file, @NotNull TypeEvalContext context) {
    if (file instanceof PyTypedElement) {
      final PyType type = context.getType((PyTypedElement)file);
      if (type != null) {
        return resolveTypeMember(type, PyNames.GETATTR, context) != null;
      }
    }

    return false;
  }

  public static boolean overridesGetAttr(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
    final PyType type = context.getType(cls);
    if (type != null) {
      if (resolveTypeMember(type, PyNames.GETATTR, context) != null) {
        return true;
      }
      final PsiElement method = resolveTypeMember(type, PyNames.GETATTRIBUTE, context);
      if (method != null && !PyBuiltinCache.getInstance(cls).isBuiltin(method)) {
        return true;
      }
    }
    return false;
  }

  @Nullable
  private static PsiElement resolveTypeMember(@NotNull PyType type, @NotNull String name, @NotNull TypeEvalContext context) {
    final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
    final List<? extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ, resolveContext);
    return !ContainerUtil.isEmpty(results) ? results.get(0).getElement() : null;
  }

  @Nullable
  public static PyType getTargetTypeFromTupleAssignment(@NotNull PyTargetExpression target,
                                                        @NotNull PyTupleExpression parentTuple,
                                                        @NotNull PyType assignedType,
                                                        @NotNull TypeEvalContext context) {
    if (assignedType instanceof PyTupleType) {
      return getTargetTypeFromTupleAssignment(target, parentTuple, (PyTupleType)assignedType);
    }
    else if (assignedType instanceof PyClassLikeType) {
      return StreamEx
        .of(((PyClassLikeType)assignedType).getAncestorTypes(context))
        .select(PyNamedTupleType.class)
        .findFirst()
        .map(t -> getTargetTypeFromTupleAssignment(target, parentTuple, t))
        .orElse(null);
    }

    return null;
  }

  @Nullable
  public static PyType getTargetTypeFromTupleAssignment(@NotNull PyTargetExpression target, @NotNull PyTupleExpression parentTuple,
                                                        @NotNull PyTupleType assignedTupleType) {
    final int count = assignedTupleType.getElementCount();
    final PyExpression[] elements = parentTuple.getElements();
    if (elements.length == count || assignedTupleType.isHomogeneous()) {
      final int index = ArrayUtil.indexOf(elements, target);
      if (index >= 0) {
        return assignedTupleType.getElementType(index);
      }
      for (int i = 0; i < count; i++) {
        PyExpression element = elements[i];
        while (element instanceof PyParenthesizedExpression) {
          element = ((PyParenthesizedExpression)element).getContainedExpression();
        }
        if (element instanceof PyTupleExpression) {
          final PyType elementType = assignedTupleType.getElementType(i);
          if (elementType instanceof PyTupleType) {
            final PyType result = getTargetTypeFromTupleAssignment(target, (PyTupleExpression)element, (PyTupleType)elementType);
            if (result != null) {
              return result;
            }
          }
        }
      }
    }
    return null;
  }

  private static class MatchContext {

    @NotNull
    private final TypeEvalContext context;

    @NotNull
    private final Map<PyGenericType, PyType> substitutions; // mutable

    private final boolean recursive;

    @NotNull
    private final Set<Pair<PyType, PyType>> matching; // mutable

    public MatchContext(@NotNull TypeEvalContext context,
                        @NotNull Map<PyGenericType, PyType> substitutions) {
      this(context, substitutions, true, new HashSet<>());
    }

    private MatchContext(@NotNull TypeEvalContext context,
                         @NotNull Map<PyGenericType, PyType> substitutions,
                         boolean recursive,
                         @NotNull Set<Pair<PyType, PyType>> matching) {
      this.context = context;
      this.substitutions = substitutions;
      this.recursive = recursive;
      this.matching = matching;
    }

    @NotNull
    public MatchContext notRecursive() {
      return new MatchContext(context, substitutions, false, matching);
    }
  }
}

redpajama_set_name: RedPajamaGithub


A cotton pique gilet with grandad collar and 4 button placket. Gilet features 3 front facing pockets, an internal pocket, an internal locker loop and straight hem. The gilet has a tailored fit and is designed to be worn short. The epitome of winter layering, this piece looks great with textured shirts and heavy knits. Made by famous brand name Afield.


text:
""" Import all RDKit chemistry modules

"""
from rdkit import rdBase
from rdkit import RDConfig
from rdkit import DataStructs
from rdkit.Geometry import rdGeometry
from rdkit.Chem import *
from rdkit.Chem.rdPartialCharges import *
from rdkit.Chem.rdDepictor import *
from rdkit.Chem.rdForceFieldHelpers import *
from rdkit.Chem.ChemicalFeatures import *
from rdkit.Chem.rdDistGeom import *
from rdkit.Chem.rdMolAlign import *
from rdkit.Chem.rdMolTransforms import *
from rdkit.Chem.rdShapeHelpers import *
from rdkit.Chem.rdChemReactions import *
try:
  from rdkit.Chem.rdSLNParse import *
except:
  pass
from rdkit.Chem.rdMolDescriptors import *
from rdkit import ForceField
Mol.Compute2DCoords = Compute2DCoords
Mol.ComputeGasteigerCharges = ComputeGasteigerCharges
import numpy

def TransformMol(mol,tform,confId=-1,keepConfs=False):
  """  Applies the transformation (usually a 4x4 double matrix) to a molecule
  if keepConfs is False then all but that conformer are removed

  """
  refConf = mol.GetConformer(confId)
  TransformConformer(refConf,tform)
  if not keepConfs:
    if confId==-1: confId=0
    allConfIds = [c.GetId() for c in mol.GetConformers()]
    for id in allConfIds:
      if not id==confId: mol.RemoveConformer(id)
    #reset the conf Id to zero since there is only one conformer left
    mol.GetConformer(confId).SetId(0)

def ComputeMolShape(mol,confId=-1,boxDim=(20,20,20),spacing=0.5,**kwargs):
  """ returns a grid representation of the molecule's shape
  """
  res = rdGeometry.UniformGrid3D(boxDim[0],boxDim[1],boxDim[2],spacing=spacing)
  EncodeShape(mol,res,confId,**kwargs)
  return res

def ComputeMolVolume(mol,confId=-1,gridSpacing=0.2,boxMargin=2.0):
  """ Calculates the volume of a particular conformer of a molecule
  based on a grid-encoding of the molecular shape.

  """
  mol = rdchem.Mol(mol.ToBinary())
  conf = mol.GetConformer(confId)
  CanonicalizeConformer(conf)
  box = ComputeConfBox(conf)
  sideLen = ( box[1].x-box[0].x + 2*boxMargin, \
              box[1].y-box[0].y + 2*boxMargin, \
              box[1].z-box[0].z + 2*boxMargin )
  shape = rdGeometry.UniformGrid3D(sideLen[0],sideLen[1],sideLen[2],
                                   spacing=gridSpacing)
  EncodeShape(mol,shape,confId,ignoreHs=False,vdwScale=1.0)
  voxelVol = gridSpacing**3
  occVect = shape.GetOccupancyVect()
  voxels = [1 for x in occVect if x==3]
  vol = voxelVol*len(voxels)
  return vol

def GenerateDepictionMatching2DStructure(mol,reference,confId=-1,
                                         referencePattern=None,
                                         acceptFailure=False,
                                         **kwargs):
  """ Generates a depiction for a molecule where a piece of the molecule
     is constrained to have the same coordinates as a reference.

     This is useful for, for example, generating depictions of SAR data
     sets so that the cores of the molecules are all oriented the same
     way.

  Arguments:
    - mol:          the molecule to be aligned, this will come back
                    with a single conformer.
    - reference:    a molecule with the reference atoms to align to;
                    this should have a depiction.
    - confId:       (optional) the id of the reference conformation to use
    - referencePattern:  (optional) an optional molecule to be used to
                         generate the atom mapping between the molecule
                         and the reference.
    - acceptFailure: (optional) if True, standard depictions will be generated
                     for molecules that don't have a substructure match to the
                     reference; if False, a ValueError will be raised

  """
  if reference and referencePattern:
    if not reference.GetNumAtoms(onlyExplicit=True)==referencePattern.GetNumAtoms(onlyExplicit=True):
      raise ValueError,'When a pattern is provided, it must have the same number of atoms as the reference'
    referenceMatch = reference.GetSubstructMatch(referencePattern)
    if not referenceMatch:
      raise ValueError,"Reference does not map to itself"
  else:
    referenceMatch = range(reference.GetNumAtoms(onlyExplicit=True))
  if referencePattern:
    match = mol.GetSubstructMatch(referencePattern)
  else:
    match = mol.GetSubstructMatch(reference)

  if not match:
    if not acceptFailure:
      raise ValueError,'Substructure match with reference not found.'
    else:
      coordMap={}
  else:
    conf = reference.GetConformer()
    coordMap={}
    for i,idx in enumerate(match):
      pt3 = conf.GetAtomPosition(referenceMatch[i])
      pt2 = rdGeometry.Point2D(pt3.x,pt3.y)
      coordMap[idx] = pt2
  Compute2DCoords(mol,clearConfs=True,coordMap=coordMap,canonOrient=False)

def GenerateDepictionMatching3DStructure(mol,reference,confId=-1,
                                         **kwargs):
  """ Generates a depiction for a molecule where a piece of the molecule
     is constrained to have coordinates similar to those of a 3D reference
     structure.

  Arguments:
    - mol:          the molecule to be aligned, this will come back
                    with a single conformer.
    - reference:    a molecule with the reference atoms to align to;
                    this should have a depiction.
    - confId:       (optional) the id of the reference conformation to use

  """
  nAts = mol.GetNumAtoms()
  dm = []
  conf = reference.GetConformer(confId)
  for i in range(nAts):
    pi = conf.GetAtomPosition(i)
    #npi.z=0
    for j in range(i+1,nAts):
      pj = conf.GetAtomPosition(j)
      #pj.z=0
      dm.append((pi-pj).Length())
  dm = numpy.array(dm)
  Compute2DCoordsMimicDistmat(mol,dm,**kwargs)

def GetBestRMS(ref,probe,refConfId=-1,probeConfId=-1,maps=None):
  """ Returns the optimal RMS for aligning two molecules, taking
  symmetry into account. As a side-effect, the probe molecule is
  left in the aligned state.

  Arguments:
    - ref: the reference molecule
    - probe: the molecule to be aligned to the reference
    - refConfId: (optional) reference conformation to use
    - probeConfId: (optional) probe conformation to use
    - maps: (optional) a list of lists of (probeAtomId,refAtomId)
      tuples with the atom-atom mappings of the two molecules.
      If not provided, these will be generated using a substructure
      search.

  """
  if not maps:
    query = RemoveHs(probe)
    matches = ref.GetSubstructMatches(query,uniquify=False)
    if not matches:
      raise ValueError,'mol %s does not match mol %s'%(ref.GetProp('_Name'),
                                                       probe.GetProp('_Name'))
    maps = [list(enumerate(match)) for match in matches]
  bestRMS=1000.
  for amap in maps:
    rms=AlignMol(probe,ref,probeConfId,refConfId,atomMap=amap)
    if rms<bestRMS:
      bestRMS=rms
      bestMap = amap

  # finally repeate the best alignment :
  if bestMap != amap:
    AlignMol(probe,ref,probeConfId,refConfId,atomMap=bestMap)
  return bestRMS

def EnumerateLibraryFromReaction(reaction,sidechainSets) :
  """ Returns a generator for the virtual library defined by
   a reaction and a sequence of sidechain sets

  >>> from rdkit import Chem
  >>> from rdkit.Chem import AllChem
  >>> s1=[Chem.MolFromSmiles(x) for x in ('NC','NCC')]
  >>> s2=[Chem.MolFromSmiles(x) for x in ('OC=O','OC(=O)C')]
  >>> rxn = AllChem.ReactionFromSmarts('[O:2]=[C:1][OH].[N:3]>>[O:2]=[C:1][N:3]')
  >>> r = AllChem.EnumerateLibraryFromReaction(rxn,[s2,s1])
  >>> [Chem.MolToSmiles(x[0]) for x in list(r)]
  ['CNC=O', 'CCNC=O', 'CNC(C)=O', 'CCNC(C)=O']

  Note that this is all done in a lazy manner, so "infinitely" large libraries can
  be done without worrying about running out of memory. Your patience will run out first:

  Define a set of 10000 amines:
  >>> amines = (Chem.MolFromSmiles('N'+'C'*x) for x in range(10000))

  ... a set of 10000 acids
  >>> acids = (Chem.MolFromSmiles('OC(=O)'+'C'*x) for x in range(10000))

  ... now the virtual library (1e8 compounds in principle):
  >>> r = AllChem.EnumerateLibraryFromReaction(rxn,[acids,amines])

  ... look at the first 4 compounds:
  >>> [Chem.MolToSmiles(r.next()[0]) for x in range(4)]
  ['NC=O', 'CNC=O', 'CCNC=O', 'CCCNC=O']

  """
  if len(sidechainSets) != reaction.GetNumReactantTemplates():
    raise ValueError,'%d sidechains provided, %d required'%(len(sidechainSets),reaction.getNumReactantTemplates())

  def _combiEnumerator(items,depth=0):
    for item in items[depth]:
      if depth+1 < len(items):
        v = _combiEnumerator(items,depth+1)
        for entry in v:
          l=[item]
          l.extend(entry)
          yield l
      else:
        yield [item]
  for chains in _combiEnumerator(sidechainSets):
    prodSets = reaction.RunReactants(chains)
    for prods in prodSets:
      yield prods

def ConstrainedEmbed(mol,core,useTethers=True,coreConfId=-1,
                     randomseed=2342):
  """ generates an embedding of a molecule where part of the molecule
  is constrained to have particular coordinates

  Arguments
    - mol: the molecule to embed
    - core: the molecule to use as a source of constraints
    - useTethers: (optional) if True, the final conformation will be
        optimized subject to a series of extra forces that pull the
        matching atoms to the positions of the core atoms. Otherwise
        simple distance constraints based on the core atoms will be
        used in the optimization.
    - coreConfId: (optional) id of the core conformation to use
    - randomSeed: (optional) seed for the random number generator

    An example, start by generating a template with a 3D structure:
    >>> from rdkit.Chem import AllChem
    >>> template = AllChem.MolFromSmiles("c1nn(Cc2ccccc2)cc1")
    >>> AllChem.EmbedMolecule(template)
    0
    >>> AllChem.UFFOptimizeMolecule(template)
    0

    Here's a molecule:
    >>> mol = AllChem.MolFromSmiles("c1nn(Cc2ccccc2)cc1-c3ccccc3")

    Now do the constrained embedding
    >>> newmol=AllChem.ConstrainedEmbed(mol, template)

    Demonstrate that the positions are the same:
    >>> newp=newmol.GetConformer().GetAtomPosition(0)
    >>> molp=mol.GetConformer().GetAtomPosition(0)
    >>> list(newp-molp)==[0.0,0.0,0.0]
    True
    >>> newp=newmol.GetConformer().GetAtomPosition(1)
    >>> molp=mol.GetConformer().GetAtomPosition(1)
    >>> list(newp-molp)==[0.0,0.0,0.0]
    True

  """
  match = mol.GetSubstructMatch(core)
  if not match:
    raise ValueError,"molecule doesn't match the core"
  coordMap={}
  coreConf = core.GetConformer(coreConfId)
  for i,idxI in enumerate(match):
    corePtI = coreConf.GetAtomPosition(i)
    coordMap[idxI]=corePtI

  ci = EmbedMolecule(mol,coordMap=coordMap,randomSeed=randomseed)
  if ci<0:
    raise ValueError,'Could not embed molecule.'

  algMap=[(j,i) for i,j in enumerate(match)]

  if not useTethers:
    # clean up the conformation
    ff = UFFGetMoleculeForceField(mol,confId=0)
    for i,idxI in enumerate(match):
      for j in range(i+1,len(match)):
        idxJ = match[j]
        d = coordMap[idxI].Distance(coordMap[idxJ])
        ff.AddDistanceConstraint(idxI,idxJ,d,d,100.)
    ff.Initialize()
    n=4
    more=ff.Minimize()
    while more and n:
      more=ff.Minimize()
      n-=1
    # rotate the embedded conformation onto the core:
    rms =AlignMol(mol,core,atomMap=algMap)
  else:
    # rotate the embedded conformation onto the core:
    rms = AlignMol(mol,core,atomMap=algMap)
    ff =  UFFGetMoleculeForceField(mol,confId=0)
    conf = core.GetConformer()
    for i in range(core.GetNumAtoms()):
      p =conf.GetAtomPosition(i)
      pIdx=ff.AddExtraPoint(p.x,p.y,p.z,fixed=True)-1
      ff.AddDistanceConstraint(pIdx,match[i],0,0,100.)
    ff.Initialize()
    n=4
    more=ff.Minimize(energyTol=1e-4,forceTol=1e-3)
    while more and n:
      more=ff.Minimize(energyTol=1e-4,forceTol=1e-3)
      n-=1
    # realign
    rms = AlignMol(mol,core,atomMap=algMap)
  mol.SetProp('EmbedRMS',str(rms))
  return mol

#------------------------------------
#
#  doctest boilerplate
#
def _test():
  import doctest,sys
  return doctest.testmod(sys.modules["__main__"])

if __name__ == '__main__':
  import sys
  failed,tried = _test()
  sys.exit(failed)


MIDDLETOWN, CT, February 5, 2015 – Applied PilotFish Healthcare Integration Inc. (APHI) announced today that the Utah Health Information Network (UHIN) has selected Applied PilotFish Healthcare Integration's eiPlatform and eiConsole for Healthcare products as integral components of its future-state architecture. UHIN serves as both a clearinghouse for healthcare claims data and a Health Information Exchange (HIE) for the coordination of clinical data. Phase 1 of UHIN's multi-year effort is focused on the movement, manipulation, and validation of electronic claims files and other administrative data. The scope of the effort includes the movement of X12 HIPAA transactions to and from thousands of providers around Utah and 4,000 payers nationwide.
UHIN is a broad-based coalition of Utah healthcare insurers, providers, and others, including local government entities. It provides a private and secure gateway for the exchange of electronic data. These exchanges include large integrated healthcare corporations as well as single-physician practices.
The Utah Health Information Network (UHIN) is a nonprofit coalition of healthcare providers, payers, state government and other stakeholders that have come together to reduce healthcare costs and improve quality and access for the community by enabling providers, payers, and patients to exchange information securely and electronically. UHIN focuses on creating electronic exchange solutions that work for the entire healthcare community, from single-provider practices to large integrated healthcare systems. For more information, visit http://www.uhin.org.
Applied PilotFish Healthcare Integration, Inc. (APHI) is a subsidiary of PilotFish Technology. Founded in 2001 and based in Middletown, CT, PilotFish Technology develops middleware to enable the integration of disparate systems. APHI distributes PilotFish products directly to healthcare industry end users and through select channel partners. For more information, visit Healthcare.PilotFishTechnology.com or contact Executive Vice President, Monika Vainius at 813 864 8662 .


Learn about decking materials and get helpful advice when developing your deck building plans. Deck Planning and Materials Guide. The ultimate in backyard decking. Part wood, part plastic, this wood-alternative board is easy to maintain, resists scratching, is impervious to termites and decay and will not warp or splinter.
You may even find that researching options for deck materials will lead to new decking ideas, resulting in a deck design that improves the appeal of your home's outdoor living areas and value. Choosing decking materials used to be easy, because there was one choice: wood.


text:
criticismism ii
art at two removes
Tag Archives: camp
Interview: Jasmine Surreal
November 19, 2014 paintingAurora, camp, cats, conceptual art, figurative, Jasmine Surreal, Jerry Lewis, Stuckism, surrealismMark Sheerin
Just minutes into our interview at a gallery in Bermondsey, 30-something Jasmine Surreal pulls a toy cat from her bag and begins ventriloquizing, in a cat voice, for my benefit.
"With my painting, I do nice, fantasy, imaginative things, because I'm so beautiful and glamorous like Zsa Zsa Gabor," says Surreal, lost for a moment in high-voiced character.
It is one of the stranger responses I've had from an artist and it is true. The painter has a pair of cats with whom she makes most of her work, holding the brushes like Sooty or Sweep. This takes a while to sink in, while it is impossible not to begin reassessing my interview subject's sanity.
Fortunately she seems fully aware of the eccentricity of her approach, with a ready sense of humour that saves our encounter from becoming a psychiatric case study.
Besides, Surreal is aligned with the Stuckist movement, the international support group for artists who make figurative work on canvas. They are not averse to being difficult, wayward and unconcerned with public image.
"I'm obsessed by cats," admits the artist. "I basically want to be reincarnated as one." And she says this in her real voice, a jaunty scouse accent. "I have funny cat crushes," she adds. "I get obsessed with a certain type and I download loads of pictures of them and I avidly stalk them on Twitter."
This is borne out as we walk round her show at Trispace Gallery in Bermondsey. Fur and whiskers are picked out in great detail. Their owners appear in a range of bizarre scenes. Surreal's love for these household pets might seem childish if it wasn't so amusing.
"I like kids because they're not affected by the way you should behave in society," the artist tells me. Indeed, it's a reason why she held her Private View on a family-friendly Saturday afternoon.
"In some ways I'm like that. I've never grown up and I never would because being grown up is painful." This could be at least part of the reason for an angry portrait of her mother, painted naturally by one of her cats.
"I do have a cute side," she adds, "and it's not going to be trampled out because society isn't cute." Instead of "grey" social comment, Surreal offers a camp alternative: "People say, 'you're a woman; how can you be camp?'". At which point she assumes an even more flamboyant persona: "It's very easy, darling, if you want to be."
The artist also does an amusing take-off of one of her more conceptual peers and pretends to swear on oath that she rarely attends contemporary art shows. It should come as no surprise that in a past life Surreal was an actress and a model. A career highlight came when playing a nude statue which comes to life in 2006 Brit flick Fated.
While still on Merseyside, she also worked as a journalist, writing for the comedy section of liistings magazine L-Scene. "I like a laugh me, you know. I'm a Northern bird," she points out. No one could accuse Surreal of taking herself too seriously. And yet she has plenty of conviction when it comes to her art. She certainly suffers for it.
"I find a lot of artists to be very conventional," she explains. "And they tend to find somebody like me, who's unconventional to be, like…they either laugh at me or they'll make fun of me or they'll make disparaging comments about me, whereas that incites me to do more and be more weird."
Surreal is clear about her antipathy to most modern art and even goes so far as to worry it might "poison my imagination". In the absence of a real pet cat or two, the artist works direct from her mind's eye.
"I'm very inspired by my own head. It's because I don't see things in reality or even in other paintings." Although she makes an exception here for the likes of Bosch and Magritte and, indeed, Dorothea Tanning and MC Escher. She dismissed Salvador Dalí on account of his alleged treatment of animals ("he experimented on them.")
But contrary to the suggestion of her assumed name (the artist was born Maddock), Jasmine Surreal insists: "I don't just paint surreal things." Her subjects are not wacky for the mere sake of it. "There's a meaning. There's symbolism. I don't like art that is meaningless. I like art to mean something, even if it only means something to me," she laughs.
So you might say this artist has well hidden depths, not unlike her all-time hero, Jerry Lewis. She says of the American comedian: "He's a surreal genius, but everybody laughs at him. They just think that he pulls funny faces and stuff, but he's much more than that."
And then as if in danger of sounding too serious or even pretentious, Surreal adds, "also, I fancy him rotten."
Jasmine Surreal was at Trispace Gallery, South London, between November 12 and 15 2014. Interview written for Culture24.
Get criticismism in your inbox
Asheq Akhtar
David Blandy
The Chapman Brothers
Stephen Cornford
Tamsin Dillon
Dominic from Luton
Karl England and Ben Street
Gerald Laing
Michael Landy
Meliisa Logan and Nadine Jessen
Daniel Pryde-Jarman
Asher Remy Toledo
Corinna Spencer
Jasmine Surreal
John Virtue
David Wightman
blogism
(fundamental) PAINTING
A Kick Up The Arts
AFTER THE END.
An Paenhuysen
Another Design Blog
Art Fag City
Art is Life
artcritical
Artwrit
Beyond the Stalking mode
Brian Dupont: Artist's Texts
C-Monster.net
Cathedral of Shit
Contemporary Monkey
Dead Hare Radio
Echostains Blog
Eyeteeth
greg.org
i like this art
in terms of
Intelligent Clashing
Jonathan Jones at the Guardian
kdoutsiderart
Modern Art Notes
non_official_sharing
Phases Mag
rachelelizaguthrie
Scrawls and Bawls
Tate Blog
The Aesthetic Trust
The Ben Street
This is Pipe
void()
archivism Select Month October 2020 (1) September 2020 (2) July 2020 (2) June 2020 (1) September 2019 (1) July 2019 (5) June 2019 (1) June 2018 (1) May 2018 (1) April 2018 (2) September 2017 (1) August 2017 (1) July 2017 (5) June 2017 (1) April 2017 (1) March 2017 (1) February 2017 (1) January 2017 (2) September 2016 (3) July 2016 (2) June 2016 (1) May 2016 (2) April 2016 (1) March 2016 (1) February 2016 (6) January 2016 (3) December 2015 (2) November 2015 (5) October 2015 (9) September 2015 (2) August 2015 (3) June 2015 (3) May 2015 (4) April 2015 (3) March 2015 (3) February 2015 (5) January 2015 (4) December 2014 (4) November 2014 (9) October 2014 (13) September 2014 (3) August 2014 (1) July 2014 (1) June 2014 (2) May 2014 (1) April 2014 (2) March 2014 (2) February 2014 (2) January 2014 (5) December 2013 (5) November 2013 (5) October 2013 (4) September 2013 (4) August 2013 (6) July 2013 (6) June 2013 (6) May 2013 (13) April 2013 (6) March 2013 (8) February 2013 (5) January 2013 (6) December 2012 (5) November 2012 (6) October 2012 (8) September 2012 (7) August 2012 (8) July 2012 (9) June 2012 (10) May 2012 (10) April 2012 (10) March 2012 (8) February 2012 (9) January 2012 (9) December 2011 (7) November 2011 (9) October 2011 (10) September 2011 (9) August 2011 (6) July 2011 (9) June 2011 (11) May 2011 (13) April 2011 (14) March 2011 (9) February 2011 (8) January 2011 (11) December 2010 (6) November 2010 (8) October 2010 (6) September 2010 (9) August 2010 (16) July 2010 (10) June 2010 (15) May 2010 (12) April 2010 (17) March 2010 (15) February 2010 (23) January 2010 (11) December 2009 (1) November 2009 (7) October 2009 (8) September 2009 (7) August 2009 (6) July 2009 (13)
19th century 20th century abstract expressionism abstract painting aggregation architecture collage conceptual conceptual art conceptual photography contemporary contemporary art contemporary installation contemporary painting contemporary sculpture craft curating design drawing fashion Figurative painting film film art film installation galleries illustration installation installation art intervention kinetic sculpture modernism music painting performance performance art philosophy photography public art sculpture sound sound art Uncategorized video video installation war art
criticismism in your inbox
*sign me up*
fb/twitter
archive Select Month October 2020 September 2020 July 2020 June 2020 September 2019 July 2019 June 2019 June 2018 May 2018 April 2018 September 2017 August 2017 July 2017 June 2017 April 2017 March 2017 February 2017 January 2017 September 2016 July 2016 June 2016 May 2016 April 2016 March 2016 February 2016 January 2016 December 2015 November 2015 October 2015 September 2015 August 2015 June 2015 May 2015 April 2015 March 2015 February 2015 January 2015 December 2014 November 2014 October 2014 September 2014 August 2014 July 2014 June 2014 May 2014 April 2014 March 2014 February 2014 January 2014 December 2013 November 2013 October 2013 September 2013 August 2013 July 2013 June 2013 May 2013 April 2013 March 2013 February 2013 January 2013 December 2012 November 2012 October 2012 September 2012 August 2012 July 2012 June 2012 May 2012 April 2012 March 2012 February 2012 January 2012 December 2011 November 2011 October 2011 September 2011 August 2011 July 2011 June 2011 May 2011 April 2011 March 2011 February 2011 January 2011 December 2010 November 2010 October 2010 September 2010 August 2010 July 2010 June 2010 May 2010 April 2010 March 2010 February 2010 January 2010 December 2009 November 2009 October 2009 September 2009 August 2009 July 2009

redpajama_set_name: RedPajamaCommonCrawl


text:
module CanTango
  module Macros
    sweet_scope :ns => {:CanTango => 'cantango/permits_ext'} do
      sweetload :Permit
    end
  end
end


text:
Travel technology (also called tourism technology, and hospitality automation) is the application of Information Technology (IT) or Information and Communications Technology (ICT) in the travel, tourism and hospitality industry.  Some forms of travel technology are flight tracking, pre-travel planning through online travel agencies, and systems that allow tourists to review their experiences.

Travel technology was originally associated with the computer reservations system (CRS) of the airlines industry, but is now used more inclusively, incorporating the broader tourism sector as well as its subset the hospitality industry.

Online travel agencies
Booking engines allow easy access for consumers and travel professionals; the systems enable individuals to make reservations and compare prices. Online travel agencies such as expedia.com, are a large contribution to how the travel and tourism industries have changed due to technology. These online agencies help users plan and book trips and provide comparisons of hotels, flights, vacation packages, prices and more, all in one place. The change from of-person to online travel agencies gives the customer more power in planning their trip.

Customer reviews
The increase in review websites has also had a huge impact on the tourism industry. Sites such as tripadvisor.com let users read, post, and interact with reviews of travel experiences and attractions others have had. eWOM, meaning electronic word of mouth, has become a big influence in consumer's attitudes and actions, resulting in different choices of products and planning aspects.

Social media and mobile technologies
The introduction of smartphones and mobile applications has also had a big effect on the tourism industry. Social media posts allow users to gather general information, free of marketing bias. GPS and social media apps allow users to tag and share their locations. People no longer need to print out directions and can use map apps to help them get around. Social media users can search for locations on social media platforms and gain more knowledge of the locations without using a review site.

Applications such as Uber and Lyft have also made travelling easier. Users no longer have to plan ahead for transportation to and from an airport or a different destination. Ubers and Lyfts may also be used in place of a rental car.

Mobile communication
Today the tour guide can be a GPS tour guide, and the guidebook could be an audioguide and trips could be planned completely online. The continuing evolution of information technology and the widespread public use of the Internet has created a number of conditions that have been both beneficial and detrimental to the modern travel agency. The internet is reshaping many business aspects. As a result, the travel and tourism industries will have to continue to adapt to new technologies in the future.

See also

 List of global distribution systems
 Online hotel reservations

Notes

References

External links

 International Federation for IT and Travel & Tourism (IFITT)

Tourism

redpajama_set_name: RedPajamaWikipedia


text:
Editorial Views (1)
Reviews of Educational Material (1)
Radiological and Other Imaging (4)
echocardiography (3)
doppler hemodynamics (2)
left ventricle (2)
transesophageal echocardiography (2)
balloon dilatation (1)
cardiac surgery procedures (1)
catheterization (1)
counterpulsation (1)
diastole (1)
Joseph S. Savino
Vasopressin: The Perioperative Gift that Keeps on Giving
John G. T. Augoustides, M.D., F.A.S.E., F.A.H.A., Joseph S. Savino, M.D.
Anesthesiology. November 2014: 121(5):914–915
DOI: https://doi.org/10.1097/ALN.0000000000000431
Fatal Thrombosis after Mitral Valve Replacement for Endocarditis: Aprotinin and Disseminated Intravascular Coagulation
John G. Augoustides, M.D., Todd Kilbaugh, M.D., Hilary Harris, B.A., John H. Glick, M.D., Michael Acker, M.D., Joseph S. Savino, M.D.
Anesthesiology. January 2006: 104(1):213
Beat-to-beat Augmentation of Left Ventricular Function by Intraaortic Counterpulsation
Albert T. Cheung, MD, Joseph S. Savino, MD, Stuart J. Weiss, MD, PhD
Anesthesiology. March 1996: 84(3):545–554
Detection of Acute Embolic Stroke during Mitral Valve Replacement Using Somatosensory Evoked Potential Monitoring
Albert T. Cheung, MD, Joseph S. Savino, MD, Stuart J. Weiss, MD, PhD, Terry Patterson, PhD, Rafael M. Richards, MS, Timothy J. Gardner, MD, Mark M. Stecker, MD, PhD
Anesthesiology. July 1995: 83(1):208–210.
Echocardiographic and Hemodynamic Indexes of Left Ventricular Preload in Patients with Normal and Abnormal Ventricular Function
Albert T. Cheung, M.D., Joseph S. Savino, M.D., Stuart J. Weiss, M.D., Ph.D., Stanley J. Aukburg, M.D., Jesse A. Berlin, Sc.D.
Pharmacology and Physiology in Anesthetic Practice
Carol A. Hirshman, M.D., JERRY M. GONZALES, M.D., JOSEPH S. SAVINO, M.D.
Anesthesiology. April 1992: 76(4):664
Protamine-induced Right-to-left Intracardiac Shunting
ALBERT T. CHEUNG, M.D., STUART J. WEISS, M.D., PH.D., JOSEPH S. SAVINO, M.D.
Measurement of Pulmonary Blood Flow with Transesophageal Two-dimensional and Doppler Echocardiography
Joseph S. Savino, M.D., Christopher A. Troianos, M.D., Stanley Aukburg, M.D., Richard Weiss, M.D., Nathaniel Reichek, M.D.
Transesophageal Echocardiographic Diagnosis of Aortic Dissection during Cardiac Surgery
Christopher A. Troianos, M.D., Joseph S. Savino, M.D., Richard L. Weiss, M.D.
Anesthesiology. July 1991: 75(1):149–152
Internal Jugular Vein Cannulation Guided by Echocardiography
Christopher A. Troianos, M.D., Joseph S. Savino, M.D.
Safety of Transesophageal Echocardiography Is Still Unclear
JOSEPH S. SAVINO, M.D., STUART WEISS, M.D., Ph.D.
Anesthesiology. August 1990: 73(2):366


Fall is here! With it comes hayrides, haunted houses, parades. apple picking, costumes and scarecrows! Westchester County has some of the best Halloween events in the area. Here is our list of upcoming fall festivals, events and Halloween happenings to fill your autumn with fun!
We have noted which events require advance reservations so please be sure to purchase your tickets now so you do not miss out. Check out our list of Fall Carnivals as well. Wishing you and your kids a safe and fun fall season!
UPDATE: Check out the latest events for the weekend of October 28 - 30th in our Weekend Blog.
Please consider sharing this with your friends and signing up for our email list. Find our what's happening this weekend, upcoming events and exclusive offers.
Explore nature, science, and books at Sheldrake's 60-acre sanctuary. Take a StoryWalk around the pond - reading about a magical woods while walking through Sheldrake's own beautiful woodland landscape. Then come back to the lawn to build a fairy house (or bug house!) to take home. Be a scientist and explore life in the pond with one of our naturalists. Or maybe you'll choose to play Animal Olympics, go on a guided nature walk, listen to live music, or participate in one of the other fun activities we have planned! Buy discounted tickets before 10/15 at www.sheldrakecenter.org. Tickets "day of" are $5/members and $10/non-members.


text:
By	Adrienne Franco | July 11, 2019
IRVING, Texas – United States Senators John Thune of South Dakota and John Kennedy of Louisiana join Connecticut Senator Richard Blumenthal as well as legislators from West Virginia, Ohio, South Dakota, Massachusetts, New York and Alabama in issuing letters urging direct broadcast satellite service provider DIRECTV and AT&T U-verse to immediately restore carriage of Nexstar-owned stations.
In his July 8, 2019 letter Senator Thune stated, "I strongly encourage AT&T/DIRECTV to provide carriage of KELO-TV and KCLO-TV through August 2, 2019, as requested by Nexstar, so that the parties can continue negotiations without impacting consumers' ability to view their local news coverage in the affected broadcast markets."
Similarly, in a letter directed to AT&T's CEO, Senator Kennedy cites the probable impact to consumers in Louisiana at the height of hurricane season, stating "I am concerned that your failure to reach an agreement is negatively impacting Louisiana families. I am especially concerned about customers losing access to up-to-date weather information in the event that the tropical depression currently forming in the Gulf of Mexico turns into a hurricane."
In closing, Senator Kennedy requests of AT&T, "I encourage you to accept Nexstar's offer of a short-term extension while you resolve your differences."
In New York, U.S. Congressman Anthony Brindisi issued a public statement calling on "…cable giant AT&T to negotiate in good faith with local broadcasters to continue to deliver local programming to their viewers. As thousands of Upstate New Yorkers lost access to their local television station this weekend, Brindisi went to bat for the local viewers. Local television provides critical programming for folks all across our district," Brindisi said. "These blackouts are a public safety issue. Many New Yorkers use local television to find out about breaking news, traffic accidents, and important weather events. These blackouts need to end."
Despite AT&T/DIRECTV having dropped the network and local community programming for Nexstar-owned stations 11:59 p.m. CT on July 3, Nexstar continues to negotiate in good faith with a goal of establishing a mutually agreeable contract with the cable company.
Consumers and viewers affected by AT&T/DIRECTV's blackout can contact AT&T/DIRECTV directly at 208 South Akard Street, Dallas, TX 75202 and by phone at 855-567-1569 or 210-821-4105. Viewers affected by the loss of service from DIRECTV have several alternatives to continue watching their favorite shows including local cable providers, DISH, over-the-air, certain subscription streaming television services, and services such as Verizon's FIOS.
A full copy of Senator Thune's letter is available here: Senator Thune Letter July 2019.
A full copy of Senator Kennedy's letter to AT&T's CEO is available here: Senator Kennedy Letter July 2019.
Congressman Brindisi's statement regarding the matter is available at: https://brindisi.house.gov/media/press-releases/brindisi-calls-cable-company-end-blackouts-behalf-local-consumers.
← The Brooklyn Nets Are Committing Nearly $350 Million To Kevin Durant, Kyrie Irving, And DeAndre Jordan


text:
HomeNewsKampala's top curry
Kampala's top curry
December 16, 2016 News 0
Curry meal. Creative Commons photo courtesy of avlxyz
Kampala is a two-curry town. Ask any long term resident of the city where to get the best curry and you will usually get one of two answers. However, I may even venture to say it is a three-curry town.
My friend Thomas insists that Khana Kazana has by far the best curry in Kampala. But ask Daniel and he will tell you that the competition is not even close: Handi's has the best curry in the city—probably in all of East Africa. Okay, I admit Daniel sometimes gets carried away, but he really likes spices!
If you ask me, that mutton rogan josh at Pavement Tandoori gives those two front-runners a run for their money.
Curry is a complicated dish to review. Unlike the simple ingredients that make a good hamburger (see "Best Hamburger in Kampala" June 2010), a curry can be made of many different ingredients and spices.
Considered a side dish by Indians, curry can be made vegetarian with an assortment of vegetables, cottage cheese or potatoes. It can also be made with every meat imaginable including chicken, fish, beef and goat. Cannot eat spicy foods? All curries can be ordered mild, medium or hot.
For the most part, people order their curry with rice, but it can also be eaten with naan (Indian flat bread). I suggest getting an order of both. Then follow your meal up with a tall glass of lasse (yogurt drink).
Khana Khazana is located on Acacia Avenue and boasts an open sitting area and waterfall in the dining room. It has an incredible menu complete with 103 different dishes you can order, of these an incredible 51 are curries. According to some unconfirmed reports, the eatery is one of the top Indian restaurants in the world—outside of India, of course.
On the advice of my waiter, I ordered the makhini chicken keseriya, which offers the meat in a thick gravy of tomatoes and other spices. It was exquisite. Served along with some steamed rice and butter naan, the curry was not overpowering and the spicing was rather complex. The meat could not have been more tender.
I ordered it medium spicy and I got medium spicy. Too often the only thing you can taste in a curry is hot. But the chef got the spicing perfect, making for a delightful lunch. I can only guess that the chef would also have gotten it perfect on any other the other 50 curry dishes. Thomas was right.
Handi's is located on the first floor of a building on Kampala Road. The setting is a stark contrast to Khana Khazana, but do not let that scare you away. We sat by a window overlooking all the chaos that is Kampala Road, but once we got our food, all the noises and distractions evaporated.
Following a similar pattern to the previous meal, I ordered my steamed rice and naan, garlic this time. For my curry I went with the Fish Goan Curry made with local tilapia. This curry is succulently made with coconut milk.
After no more than five minutes, the steaming dishes were delivered to our table. My tongue was sent on a whirlwind tour of the Indian countryside, tasting every spice in the smooth, subtle sauce. The fish was perfectly cooked and again a medium was a medium. Daniel was right.
Pavement Tandoori in the Kisimenti shopping area, is a much smaller more intimate setting than the other two restaurants I tried out and is definitely a more intimate dining experience. Wanting to try something different, I ordered the mutton rogan josh with steamed rice and chilli naan. Mutton can be a bit tricky to cook and I have often received some that was either so tender it fell apart or cooked too long that the meat is overly tough.
It was perfect. Leave it to the Indian chefs—they really know how to cook their meats. The stronger taste of the mutton was perfectly matched with their menagerie of spices. A medium was a medium and this time Ole was right.
So I guess there is no clear winner for the best curry in town. With three great curry restaurants, the curry fans of Kampala are the real winners.
By Ole Tangen Jr.
Best Curry in Kampala
Handi's
Pavement Tandoori
Persons with Albinism cry for safety
The Albinism Umbrella, an activist group for albinos' has called for policies to guarantee the ……READ MORE
Father kills eight-year-old son over pork
A father in Manafwa district is in police custody for allegedly killing his biological son ……READ MORE
Ssebaana's death a blow to Uganda's politics, economy – MPs
The death of veteran politician John Ssebaana Kizito has been described as a great loss ……READ MORE


text:
Home Info Enemy : Zionist Regime of Israel Israeli PM hopes to derail Russia-Syria S-300 deal
Israeli PM hopes to derail Russia-Syria S-300 deal
Israeli Prime Minister Benjamin Netanyahu will try to discourage Russia from providing Syria with an S-300 air-defense system during his upcoming visit to the U.S., according to Israeli media reports.
Netanyahu is scheduled to attend the 73rd session of the UN General Assembly, which is currently underway in New York.
On Monday, Israel's Channel 2 reported that Netanyahu would attempt to persuade U.S. President Donald Trump to offer Russian President Vladimir Putin a "diplomatic initiative" in exchange for the latter refraining from delivering the S-300 system to Syria.
Last week, several Israeli F-16s entered Syrian airspace before striking military targets in Syria's northwestern Latakia province.
When Syria's Russian-built S-200 air-defense system responded to the attack, a Russian Il-20 military plane was struck by anti-aircraft fire, killing all 15 servicemen on board.
Days later, Moscow — accusing Israel of using the Russian aircraft as a means of evading Syrian air defenses — announced its decision to provide Damascus with an advanced S-300 air-defense system.
Channel 2 did not provide details as to Netanyahu's proposed "diplomatic initiative", but said the prime minister hoped to return from New York "with a guarantee that the Israeli Air Force would have the freedom to operate in Syrian airspace".
Israel's Channel 10, meanwhile, quoted an unnamed Israeli official as saying that the situation with Russia constituted a "serious crisis".
The broadcaster went on to report that Israel's Security Cabinet had convened on Tuesday — with Netanyahu in attendance — to discuss the row with Moscow.
After the meeting, the cabinet reportedly instructed the Israeli army to continue conducting operations in Syria.
The meeting also reportedly tackled the implications of Russia's decision to provide Syria with the S-300 system, delivery of which is expected within two weeks.
In a statement, Russian Defense Minister Sergei Shoigu said the system would "significantly" strengthen the Syrian regime's air-defense capabilities.
According to Russian officials, the S-300 can strike targets up to 250 kilometers away and destroy multiple targets simultaneously. – Anadolu
Previous articleRouhani : Iran never requested meeting with Trump
Next articleMalaysia's Former First Lady Questioned For 13 Hours In 1MDB Graft Case
Settlers Storm Al-Aqsa with Israeli Minister of Agriculture
Iran rejects 'ridiculous' Israeli claim on downing Iranian drone
Israeli PM to Name Golan Settlement After Trump


text:
EXCLUSIVE: Swarovski Group signs jewellery licensing agreement with Karl Lagerfeld
Fashion icon Karl Lagerfeld has never shied away from wearing jewellery himself and now he's about to adorn the world with his very own fashion jewellery collection. And who has he chosen to embark on this adventure with him? The Swarovski Group.
While Swarovski are under strict instructions to keep the very essence of what the jewellery looks like under wraps, head of business development at Swarovski Professional, Myalee Sofield, wanted Professional Jeweller to be the first to know about the Group's sparkling new marriage with one of the most acclaimed fashion designers to ever exist.
The very first glimpse of the collection will be unveiled at Swarovski's striking Baselworld booth, but what we can reveal before the Switzerland trade-show is that the designer's namesake label has signed an exclusive multi-year licensing agreement with the Swarovski Group to produce a line of fashion jewellery featuring the company's signature crystals.
"Karl is the man of accessorisation and jewellery, it was therefore the next natural step for us to expand our product range with a fashion jewellery collection," shares chief executive of the Karl Lagerfeld namesake brand, Pier Paolo Righi. "Swarovski with their significant expertise make the perfect partner for us and we look forward to launching the first collection this fall."
As one of the most celebrated fashion designers, Karl Lagerfeld is globally renowned for his cutting-edge approach to style, with his namesake fashion house reflecting his signature aesthetic through creative, cool and accessible-luxe apparel and accessories.
Sofield shares: "The Karl Lagerfeld brand does not take itself too seriously which really sets it apart from so many other brands currently in the market. There is a sense of irony that runs through all of the collections and we made sure to reflect that in the fashion jewellery. We wanted to provide an opportunity for the consumer to really have fun with creating her look."
The new jewellery line, which is scheduled to launch into stores in September, will include necklaces, bracelets, rings and earrings, all meticulously crafted from high quality materials. Designs will feature iconic crystals from Swarovski throughout, adding a naturally brilliant and eye-catching appeal to each piece.
"Karl Lagerfeld has become a true authority on accessories, both in his work and personally," explains Sofield. "Throughout his career, Karl has been sure to make a statement with whatever he creates. While developing the jewellery line, we were not afraid to take risks with the designs which has really led to an amazing collection. We have taken the unique and iconic style that Karl has become so known for and translated that to include bold styling and recognisable features and details."
Sofield adds: "The collection is classically cool but with an ironic, edgy twist. It provides the consumer with easily wearable options that are fun, unique, and on trend."
As Lagerfeld connects with multiple generations and has a global appeal, the jewellery collection lends itself to be worn be a wide variety of people.
"The target consumer is style conscious and an early adopter of what's new in the fashion world. She loves to make a statement with the clothes and jewellery that she wears."
As part of the licensing agreement the Karl Lagerfeld fashion jewellery line will feature two main collections each year. Prices range from £45-£200 for the core collection, with some special styles ranging up to £500.
Launching the debut Karl Lagerfeld jewellery line at Baselworld, Sofield and the Swarovski Group team will meet with key buyers and retailers to introduce them to the range. This will be followed by an event in the spring where the Group will showcase the line solely to its customers in the UK and Ireland.
"We want to launch with a mixture of key jewellery retailers with a specific focus on fashion across the multiple, department store and independent market," shares Sofield. "We would like to see the brand well established with long term partners who love the brand as much as we do."
The Swarovski Group will be launching the line with key strategic initiatives in collaboration with Karl Lagerfeld's marketing activities.
Adding the Karl Lagerfeld jewellery line to its portfolio is part of the Swarovski Group's plan to build the global licensing arm of the company. Sofield joined the jewellery solutions and global licensing business of Swarovski Professional last year to help launch its new jewellery brand Adore and to work with Swarovski Professional's global vice president, Eric Russack, to build a portfolio of brands for the corporation. Joining brands such as Adore Jewellery, Karl Lagerfeld offers an edgier and even more fashion-focused selection of jewellery.
"We are thrilled to be working with such a legendary, inspirational and iconic leader as Karl Lagerfeld," says Swarovski Professional global vice president, Eric Russack. "We are proud to pair the Swarovski Group's 120 year legacy and excellence of product quality, innovation, & trend with the Karl Lagerfeld brand. We look forward to a successful and long lasting partnership."
Markus Langes-Swarovski, a member of Swarovski's executive board, adds: "We feel honoured to be partnering with an iconic fashion house such as Karl Lagerfeld. Reflective of the creative vision of Karl Lagerfeld, the collection was developed with cutting edge design elements and superior quality which perfectly complement the existing categories. We look forward to maximizing our licensing partnership together."
Myalee Sofield
Swarovski Swarovski Group
Previous articleH Samuel is the most searched for jewellery company on Google
Next articleNAJ launches regional drop-in sessions for industry professionals
COLLECTION: Karl Lagerfeld nods to fantasy fairytales for AW19
Iconic designer Karl Lagerfeld dead at 85
COLLECTIONS OF THE YEAR 2018: Pearl Jewellery


What metadata needs to be added? The change doesn't reference a bug number. We have our own system in place to ask for the required permissions so we don't need them all up front.
Hello, what does it mean exactly ? To disable the permission popup at the start and ask the permission later ?
Unity 5 asks for all required permissions up front. If you want to do a flow seperately (show nice screens explaining why you are going to ask for certain permissions for example), you'd want to disable this and do it manually.
We are using Unity 5.3.3p2, the meta-data should be added inside Application instead.
Hi! I know I'm late, but is this allowed by the Android guidelines? It's a pretty convenient trick, but I doubt it's allowed by Google's transparency policies.
Also, I tried adding this line to the manifest and didn't work.
FYI it works in 2017.3 by putting that line in the application section. This became an issue for us because Google now requires that we target Android 8.0 (API level 26) to submit apps to the play store, and for all updates as of November 1, 2018. So that means apps that target 5.1, before the new permission system went into effect, will now have to adapt.
@Stockx Not working. Help me please.
Here's an example using the Camera. Obviously, make sure you change the package to yours. I'm using Android Native Goodies Pro to do the runtime permission request when the user tries to use the camera.


80 Towd Point Rd is located in North Sea neighborhood in the city of Southampton, NY.
80 Towd Point Rd, Southampton, NY 11968 is easy to distinguish from the other listings on realtor.com®. even though you will find thousands of homes for rent across the nation listed right here, the rental listings you are looking at will help you learn why 80 Towd Point Rd is different. And since not everyone is right for every house, if 80 Towd Point Rd is not a match, keep browsing until you find your match.


text:
United Sisterhood Alliance
United Sisterhood Alliance comprises of four separate institutions; Workers Information Centre (WIC), Messenger Band, Women's Network for Unity (WNU), and Social Action for Community and Development.
WIC works directly with women garment workers to build networks through provision of drop-in centres which provide information, support services and a community space for garment workers.
Messenger Band is a grassroots advocacy group that composes and performs original songs that reflect the current problems and situation faced by the working class and impoverished people of Cambodia.
WNU's mission is to support sex workers to organise and form networks to advocate for greater access to social services, and freedom from violence and discrimination. WNU work towards change by promoting sex workers' participation in the development of programs, policies and laws related to sex work.
Social Action for Community and Development addresses and mitigates the impact of policies and practices contributing to systemic and structural injustice, using research, advocacy and mobilisation of community members including farmers, garment workers, sex workers, young people, and people living with HIV. Their current focus areas are access to social services; access to affordable medicines; and addressing the impact of trade policies on smallholder farmers.
United Sisterhood Alliance AND IWDA
United Sisterhood Alliance is an alliance of four social groups that evolved from an organisation established in 1999, the Womyn's Agenda for Change (WAC). In 2009 the NGO made a strategic decision to concentrate all resources and expertise into the continued strengthening and development of social and advocacy groups in order to be more effective in addressing the needs of the people in Cambodia as well as realising social development, change and justice. IWDA first partnered with WIC in 2011 – the partnership has now grown to encompass all members of United Sisterhood Alliance.
The immediate constituency of United Sisterhood are sex workers, garment workers, organised farmers, landless farmers and indigenous networks, Lesbian, Gay, Bi-sexual, Transgender (LGBT) and women's activists.
WIC's drop in centres provide a safe space for women workers to come together to build knowledge, confidence and power. The centres also provide access to critical services such as healthcare and training opportunities.
WNU's drop in centres provide a space for sex workers to organise and form networks advocating for greater access to social services.
A week in Phnom Penh with Dr Susan Carland and Cambodia's feminist community
Three ways garment factories violate women's rights – and how it happens


[ Offprint, inscribed by one of the authors. ] The perspective of Piero della Francesca's "Flagellation" | By R. Wittkower and B. A. R. Carter.
11pp., 4to. With three plates and five figures in text. Paginated 292-302. Stapled in card wraps. Inscribed on front cover: 'with best wishes | B.A.R.C.' The only copies on COPAC at the Warburg Institute and V & A.


There are 10-mile queues on the A1 southbound from Grantham this morning after a crash involving two vehicles near Colsterworth.
Traffic is queuing all the way from the junction with the A52 for Nottingham and Grantham town centre, right down to the junction for the B6403.
An eyewitness has told Lincolnshire Reporter that the road is partially blocked and that a number of vehicles were involved.
Motorists should avoid the area if at all possible.
Lincolnshire Police have said that the crash involved two vehicles, and that there were no injuries.


text:
Becket ist der Familienname folgender Personen:

 Fiona Becket (* 1962), Literaturhistorikerin
 Frederick Mark Becket (1875–1942), amerikanischer Metallurg
 Thomas Becket (1118–1170), englischer Lordkanzler und Erzbischof von Canterbury
 Welton Becket (1902–1969), US-amerikanischer Architekt

Orte in den Vereinigten Staaten:
 Becket (Massachusetts), im Berkshire County
 Becket (Montana), im Fergus County
 Becket (Ohio), im Belmont County – nicht mehr existent
 Becket Center, im Berkshire County, Massachusetts

Sonstiges:
 Becket oder die Ehre Gottes, Theaterstück von Jean Anouilh
 Becket (Film), britisches Filmdrama (1964)
 Becket Branch, Fließgewässer im Pike County, Kentucky
 Becket Run, Fließgewässer im Somerset County, Pennsylvania
 Becket Center Historic District, Park im Berkshire County, Massachusetts

Siehe auch:
 Beckett
 A'Becket


The straw is made of food grade PP material, 100 % safe to health. The straw comes in different colors, providing customers with many options. Wrapped in individual, the straws can enhance sanitation for user operation. To save the cost, wrapping several straws in one sleeve is also available. The straw has three different diameters: 6mm, 8mm, and 12mm.
Copyright 2017 © Yi Shen Plastic Corp. All rights reserved.


text:
CBD & e-cigarette
CBD forms
E-liquid CBD and THC: what are the differences?
The CBD e-liquid and the THC e-liquid have one thing in common, both are derived from the hemp plant. Both substances belong to the family of cannabinoids. Their molecules act on the receptors located in the nervous system, organs, immune system, brain, etc.. But they have different effects. Find out more about them below.
What are the differences between CBD and THC?
For smokers, it is important to know the differences between CBD and THC. Then you should know that cannabis is a product containing several hundred molecules. Tetrahydrocannabinol or THC is the most abundant cannabinoid in the cannabis plant. This molecule is known for its psychotropic effects. THC changes the smoker's state of consciousness, making him or her "high". It makes him feel high.
Cannabidiol, or CBD, is another cannabis chemical, but it does not have the same effects as THC. On the contrary, it is known for its calming effect. And, it works the opposite of THC by calming the nervous system. The psychotropic effects are therefore not related to CBD.
CBD: its positive effects
THC and CBD each have health effects. In most countries, even though it is mild, THC is considered a drug. This is because of its psychoactive effects and especially its risks to the body. Moreover, its use often leads to dependence.
As for CBD, it is almost the opposite, it has major therapeutic virtues. CBD acts as analgesics and painkillers. It helps prevent depression and anxiety. It can also relieve the symptoms of multiple sclerosis and epilepsy and combat certain psychotic disorders such as schizophrenia, etc. Some studies even show that, at high levels, CBD acts as an inhibitor in the multiplication of tumour cells caused by certain cancers.
CBD AND THC, what does the law say?
Studies have proven that CBD does not create any risk of addiction and is not dangerous to health, unlike THC. For this reason, cannabidiol is classified as a controlled substance and its marketing is authorised in France. Moreover, the WHO has already given a favourable opinion on this legal aspect of CBD, stating that it cannot be classified as a drug. As such, the sale of cannabidiol products with a THC concentration of less than 0.2% is authorized. It is sold as a liquid for use in electronic cigarettes to allow the vaporizer to be supplemented with a food. But it can also be applied directly to the skin.
What are the benefits of CBD e-liquid?
How to use the e-liquid in the CBD?
CBD LEGAL
CBD has been classified by the WHO as harmless and safe. Its sale has become legal in many countries, but the THC content must be less than 0.2%.
Medical Benefits of Cannabidiol
Cannabis medical analgesic
Use of CBD in self-medication
Therapeutic potentials of CBD
CBD TREND
Over-the-counter CBD products
E-cig and nicotine substitutes
CBD for cannabic weaning
CBD feed supplements