@Override
  public void run(IOperationProgressMonitor pm)
      throws InvocationTargetException, InterruptedException {
    IEntity selfEntity =
        EntityUtils.mapEntity(selfModel, EntityUtils.clone(EntityUtils.getCompoundRoot(selfModel)));

    Set<String> initialNames = bm.wNames();

    pm.beginTask("Executing sample...", IOperationProgressMonitor.TOTAL_WORK);

    behaviorModel =
        BehaviorUtils.apply(
            "whole:org.whole.lang.ui.views:SamplePerspectiveSemantics#SampleViewBehavior",
            behaviorModel,
            bm);

    IEntity derivedModel = null;
    try {
      IEntityIterator<?> iterator = BehaviorUtils.lazyEvaluate(behaviorModel, 0, bm);
      iterator.setBindings(selfBindings);
      iterator.reset(selfEntity);

      if (iterator.getClass().equals(ConstantIterator.class)) {
        IEntity result = iterator.next();
        if (result == null || !EntityUtils.isData(result)) derivedModel = result;
        else {
          Object resultValue = result.wGetValue();
          derivedModel =
              IVisitor.class.isInstance(resultValue)
                  ? BindingManagerFactory.instance.createValue(
                      Matcher.match((IVisitor) resultValue, selfEntity))
                  : result;
        }
      } else if (iterator.hasNext()) {
        derivedModel = MiscEntityFactory.instance.createMisc(0);

        ITransactionScope transactionScope =
            BindingManagerFactory.instance.createTransactionScope();
        bm.wEnterScope(transactionScope);
        try {
          for (IEntity result : iterator) {
            transactionScope.commit();
            derivedModel.wAdd(
                GenericEntityFactory.instance.create(
                    CommonsEntityDescriptorEnum.SameStageFragment,
                    // CommonsEntityFactory.instance.createSameStageFragment(
                    EntityUtils.clone(result))); // TODO substitute with a no containment fragment
          }
        } finally {
          transactionScope.rollback();
          bm.wExitScope();
        }
      }
    } catch (MissingVariableException e) {
      addMissingVariables(contextModel, e);
    } catch (OperationCanceledException e) {
      // gracefully terminate execution
    } catch (Exception e) {
      if (e.getCause() instanceof MissingVariableException)
        addMissingVariables(contextModel, (MissingVariableException) e.getCause());
    } finally {
      pm.endTask();
    }

    IEntity variablesModel = null;
    if (derivedModel != null) {
      EnvironmentEntityFactory ef = EnvironmentEntityFactory.instance;
      variablesModel = ef.createBindings(0);
      for (String name : new TreeSet<String>(bm.wLocalNames()))
        if (!initialNames.contains(name))
          variablesModel.wAdd(
              ef.createBinding(ef.createName(name), ef.createValue(BindingUtils.wGet(bm, name))));

      final IEntity contents = derivedModel;
      final IEntity variables = variablesModel;
      context
          .get(UISynchronize.class)
          .asyncExec(
              new Runnable() {
                public void run() {
                  context.get(IEntityPartViewer.class).setContents(null, contents);
                  context
                      .get(IEventBroker.class)
                      .post(IUIConstants.TOPIC_UPDATE_VARIABLES, variables);
                }
              });
    }
  }
  @Override
  public void visit(TestSuite entity) {
    if (isLearning()) {
      Map<IEntity, List<IEntity>> learntMap = getLearntMap();

      IEntity result = null;
      for (int cycle = 1; cycle <= learnCycles(); cycle++) {
        printWriter().printf("*** Learning cycle %d ***\n\n", cycle);
        ITransactionScope resettableScope = BindingManagerFactory.instance.createTransactionScope();
        getBindings().wEnterScope(resettableScope);
        try {
          getBindings().wDefValue("learnCycle", cycle);
          super.visit(entity);
          result = getBindings().getResult();
        } finally {
          resettableScope.rollback();
          getBindings().wExitScope();
        }
      }
      getBindings().setResult(result);

      FilterFamily filterFamily = getFilterFamily(entity);
      FilterRules filterRules = filterFamily.getFilterRules();
      FreshNameGenerator fnGen = new FreshNameGenerator();
      for (IEntity name :
          BehaviorUtils.compileAndLazyEvaluate(createFindAllFilterRuleNamesQuery(), filterFamily))
        fnGen.addBoundName(name.wStringValue());

      for (IEntity adapter : learntMap.keySet()) {
        List<IEntity> learntEntities = learntMap.get(adapter);

        IEntity value = learntEntities.get(0);
        if (learntEntities.size() > 1 && EntityUtils.isData(value)) {
          for (IEntity learntEntity : learntEntities) if (!learntEntity.wEquals(value)) continue;
        } else if (learntEntities.size() > 1) {
          for (IEntity learntEntity2 : learntEntities)
            if (EntityUtils.isData(learntEntity2)) continue;

          // generate filter rule
          FilterRule filterRule = TestsHelpers.createFilterRule(learntEntities);
          if (EntityUtils.isNotResolver(filterRule)) {
            String filterName;
            IEntity filterBody;
            if ((filterBody = Matcher.find(filterRule.getBody(), filterRules, false)) != null) {
              // try to reuse a generated filter
              filterName = ((FilterRule) filterBody.wGetParent()).getName().getValue();
            } else {
              // add the filter rule to the filter family
              filterName = fnGen.nextFreshName(GENERATED_FILTER_NAME);
              ITransactionScope resettableScope =
                  BindingManagerFactory.instance.createTransactionScope();
              getBindings().wEnterScope(resettableScope);
              try {
                getBindings().wDefValue("filterName", filterName);
                Matcher.substitute(filterRule, getBindings(), false);
                filterRules.wAdd(filterRule);
              } finally {
                resettableScope.rollback();
                getBindings().wExitScope();
              }
            }

            // wrap SubjectStatement with a UsingFilter
            ITransactionScope resettableScope =
                BindingManagerFactory.instance.createTransactionScope();
            getBindings().wEnterScope(resettableScope);
            try {
              SubjectStatement statement =
                  BehaviorUtils.evaluateFirstResult(
                      createFindAncestorSubjectStatement(), adapter, getBindings());
              UsingFilter usingFilter = createUsingFilter(filterName);
              statement.wGetParent().wSet(statement, usingFilter);
              usingFilter.setSubjectStatement(statement);
            } finally {
              resettableScope.rollback();
              getBindings().wExitScope();
            }
          }
        }

        TestsHelpers.replace(adapter, value);
      }
      // add the newly generated family
      if (!EntityUtils.hasParent(filterFamily) && !filterRules.wIsEmpty())
        entity.getFilterFamilies().wAdd(filterFamily);
    } else super.visit(entity);
  }