text:
// Copyright 2006 The Bazel Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.syntax;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.skylarkinterface.StarlarkBuiltin;
import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for MethodLibrary. */
@RunWith(JUnit4.class)
public final class MethodLibraryTest extends EvaluationTestCase {

  private static final String LINE_SEPARATOR = System.lineSeparator();

  @Before
  public final void setFailFast() throws Exception {
    setFailFast(true);
  }

  @Test
  public void testStackTraceLocation() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "Traceback (most recent call last):"
                + LINE_SEPARATOR
                + "\tFile \"\", line 8"
                + LINE_SEPARATOR
                + "\t\tfoo()"
                + LINE_SEPARATOR
                + "\tFile \"\", line 2, in foo"
                + LINE_SEPARATOR
                + "\t\tbar(1)"
                + LINE_SEPARATOR
                + "\tFile \"\", line 7, in bar"
                + LINE_SEPARATOR
                + "\t\t\"test\".index(x)",
            "def foo():",
            "  bar(1)",
            "def bar(x):",
            "  if x == 1:",
            "    a = x",
            "    b = 2",
            "    'test'.index(x)",
            "foo()");
  }

  @Test
  public void testStackTraceWithIf() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "File \"\", line 5"
                + LINE_SEPARATOR
                + "\t\tfoo()"
                + LINE_SEPARATOR
                + "\tFile \"\", line 3, in foo"
                + LINE_SEPARATOR
                + "\t\ts[0]",
            "def foo():",
            "  s = []",
            "  if s[0] == 1:",
            "    x = 1",
            "foo()");
  }

  @Test
  public void testStackTraceWithAugmentedAssignment() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "File \"\", line 4"
                + LINE_SEPARATOR
                + "\t\tfoo()"
                + LINE_SEPARATOR
                + "\tFile \"\", line 3, in foo"
                + LINE_SEPARATOR
                + "\t\ts += \"2\""
                + LINE_SEPARATOR
                + "unsupported binary operation: int + string",
            "def foo():",
            "  s = 1",
            "  s += '2'",
            "foo()");
  }

  @Test
  public void testStackTraceSkipBuiltInOnly() throws Exception {
    // The error message should not include the stack trace when there is
    // only one built-in function.
    new Scenario()
        .testIfExactError(
            "in call to index(), parameter 'sub' got value of type 'int', want 'string'",
            "'test'.index(1)");
  }

  @Test
  public void testStackTrace() throws Exception {
    // Unlike SkylarintegrationTests#testStackTraceErrorInFunction(), this test
    // has neither a BUILD nor a bzl file.
    new Scenario()
        .testIfExactError(
            "Traceback (most recent call last):"
                + LINE_SEPARATOR
                + "\tFile \"\", line 6"
                + LINE_SEPARATOR
                + "\t\tfoo()"
                + LINE_SEPARATOR
                + "\tFile \"\", line 2, in foo"
                + LINE_SEPARATOR
                + "\t\tbar(1)"
                + LINE_SEPARATOR
                + "\tFile \"\", line 5, in bar"
                + LINE_SEPARATOR
                + "\t\t\"test\".index(x)"
                + LINE_SEPARATOR
                + "in call to index(), parameter 'sub' got value of type 'int', want 'string'",
            "def foo():",
            "  bar(1)",
            "def bar(x):",
            "  if 1 == 1:",
            "    'test'.index(x)",
            "foo()");
  }

  @Test
  public void testBuiltinFunctionErrorMessage() throws Exception {
    new Scenario()
        .testIfErrorContains("substring \"z\" not found in \"abc\"", "'abc'.index('z')")
        .testIfErrorContains(
            "in call to startswith(), parameter 'sub' got value of type 'int', want 'string or"
                + " tuple'",
            "'test'.startswith(1)")
        .testIfErrorContains("in dict, got string, want iterable", "dict('a')");
  }

  @Test
  public void testHasAttr() throws Exception {
    new Scenario()
        .testExpression("hasattr(depset(), 'to_list')", Boolean.TRUE)
        .testExpression("hasattr('test', 'count')", Boolean.TRUE)
        .testExpression("hasattr(dict(a = 1, b = 2), 'items')", Boolean.TRUE)
        .testExpression("hasattr({}, 'items')", Boolean.TRUE);
  }

  @Test
  public void testGetAttrMissingField() throws Exception {
    new Scenario()
        .testIfExactError(
            "'string' value has no field or method 'not_there'", "getattr('a string', 'not_there')")
        .testExpression("getattr('a string', 'not_there', 'use this')", "use this")
        .testExpression("getattr('a string', 'not there', None)", Starlark.NONE);
  }

  @StarlarkBuiltin(name = "AStruct", documented = false, doc = "")
  static final class AStruct implements ClassObject, StarlarkValue {
    @Override
    public Object getValue(String name) {
      switch (name) {
        case "field":
          return "a";
        default:
          return null;
      }
    }

    @Override
    public ImmutableCollection<String> getFieldNames() {
      return ImmutableList.of("field");
    }

    @Override
    public String getErrorMessageForUnknownField(String name) {
      return null;
    }
  }

  @Test
  public void testGetAttrMissingField_typoDetection() throws Exception {
    new Scenario()
        .update("s", new AStruct())
        .testIfExactError(
            "'AStruct' value has no field or method 'feild' (did you mean 'field'?)",
            "getattr(s, 'feild')");
  }

  @Test
  public void testGetAttrWithMethods() throws Exception {
    String msg = "'string' value has no field or method 'cnt'";
    new Scenario()
        .testIfExactError(msg, "getattr('a string', 'cnt')")
        .testExpression("getattr('a string', 'cnt', 'default')", "default");
  }

  @Test
  public void testDir() throws Exception {
    new Scenario()
        .testExpression(
            "str(dir({}))",
            "[\"clear\", \"get\", \"items\", \"keys\","
                + " \"pop\", \"popitem\", \"setdefault\", \"update\", \"values\"]");
  }

  @Test
  public void testBoolean() throws Exception {
    new Scenario().testExpression("False", Boolean.FALSE).testExpression("True", Boolean.TRUE);
  }

  @Test
  public void testBooleanUnsupportedOperationFails() throws Exception {
    new Scenario().testIfErrorContains("unsupported binary operation: bool + bool", "True + True");
  }

  @Test
  public void testListSort() throws Exception {
    new Scenario()
        .testEval("sorted([0,1,2,3])", "[0, 1, 2, 3]")
        .testEval("sorted([])", "[]")
        .testEval("sorted([3, 2, 1, 0])", "[0, 1, 2, 3]")
        .testEval("sorted([[1], [], [2], [1, 2]])", "[[], [1], [1, 2], [2]]")
        .testEval("sorted([True, False, True])", "[False, True, True]")
        .testEval("sorted(['a','x','b','z'])", "[\"a\", \"b\", \"x\", \"z\"]")
        .testEval("sorted({1: True, 5: True, 4: False})", "[1, 4, 5]")
        .testEval("sorted([3, 2, 1, 0], reverse=True)", "[3, 2, 1, 0]")
        .testEval("sorted([[1], [], [1, 2]], key=len, reverse=True)", "[[1, 2], [1], []]")
        .testEval("sorted([[0, 5], [4, 1], [1, 7]], key=max)", "[[4, 1], [0, 5], [1, 7]]")
        .testIfExactError("Cannot compare function with function", "sorted([sorted, sorted])");
  }

  @Test
  public void testDictionaryCopy() throws Exception {
    new Scenario().setUp("x = {1 : 2}", "y = dict(x)").testEval("x[1] == 2 and y[1] == 2", "True");
  }

  @Test
  public void testDictionaryCopyKeyCollision() throws Exception {
    new Scenario().setUp("x = {'test' : 2}", "y = dict(x, test = 3)").testEval("y['test']", "3");
  }

  @Test
  public void testDictionaryKeyNotFound() throws Exception {
    new Scenario()
        .testIfErrorContains("key \"0\" not found in dictionary", "{}['0']")
        .testIfErrorContains("key 0 not found in dictionary", "{'0': 1, 2: 3, 4: 5}[0]");
  }

  @Test
  public void testDictionaryAccess() throws Exception {
    new Scenario()
        .testEval("{1: ['foo']}[1]", "['foo']")
        .testExpression("{'4': 8}['4']", 8)
        .testExpression("{'a': 'aa', 'b': 'bb', 'c': 'cc'}['b']", "bb");
  }

  @Test
  public void testDictionaryVariableAccess() throws Exception {
    new Scenario().setUp("d = {'a' : 1}", "a = d['a']").testLookup("a", 1);
  }

  @Test
  public void testDictionaryCreation() throws Exception {
    String expected = "{'a': 1, 'b': 2, 'c': 3}";

    new Scenario()
        .testEval("dict([('a', 1), ('b', 2), ('c', 3)])", expected)
        .testEval("dict(a = 1, b = 2, c = 3)", expected)
        .testEval("dict([('a', 1)], b = 2, c = 3)", expected);
  }

  @Test
  public void testDictionaryCreationInnerLists() throws Exception {
    new Scenario().testEval("dict([[1, 2], [3, 4]], a = 5)", "{1: 2, 3: 4, 'a': 5}");
  }

  @Test
  public void testDictionaryCreationEmpty() throws Exception {
    new Scenario().testEval("dict()", "{}").testEval("dict([])", "{}");
  }

  @Test
  public void testDictionaryCreationDifferentKeyTypes() throws Exception {
    String expected = "{'a': 1, 2: 3}";

    new Scenario()
        .testEval("dict([('a', 1), (2, 3)])", expected)
        .testEval("dict([(2, 3)], a = 1)", expected);
  }

  @Test
  public void testDictionaryCreationKeyCollision() throws Exception {
    String expected = "{'a': 1, 'b': 2, 'c': 3}";

    new Scenario()
        .testEval("dict([('a', 42), ('b', 2), ('a', 1), ('c', 3)])", expected)
        .testEval("dict([('a', 42)], a = 1, b = 2, c = 3)", expected);
    new Scenario().testEval("dict([('a', 42)], **{'a': 1, 'b': 2, 'c': 3})", expected);
  }

  @Test
  public void testDictionaryCreationInvalidPositional() throws Exception {
    new Scenario()
        .testIfErrorContains("in dict, got string, want iterable", "dict('a')")
        .testIfErrorContains(
            "in dict, dictionary update sequence element #0 is not iterable (string)",
            "dict([('a')])")
        .testIfErrorContains(
            "in dict, dictionary update sequence element #0 is not iterable (string)",
            "dict([('a')])")
        .testIfErrorContains(
            "dict() accepts no more than 1 positional argument but got 3",
            "dict((3,4), (3,2), (1,2))")
        .testIfErrorContains(
            "item #0 has length 3, but exactly two elements are required",
            "dict([('a', 'b', 'c')])");
  }

  @Test
  public void testDictionaryValues() throws Exception {
    new Scenario()
        .testEval("{1: 'foo'}.values()", "['foo']")
        .testEval("{}.values()", "[]")
        .testEval("{True: 3, False: 5}.values()", "[3, 5]")
        .testEval("{'a': 5, 'c': 2, 'b': 4, 'd': 3}.values()", "[5, 2, 4, 3]");
    // sorted by keys
  }

  @Test
  public void testDictionaryKeys() throws Exception {
    new Scenario()
        .testEval("{1: 'foo'}.keys()", "[1]")
        .testEval("{}.keys()", "[]")
        .testEval("{True: 3, False: 5}.keys()", "[True, False]")
        .testEval(
            "{1:'a', 2:'b', 6:'c', 0:'d', 5:'e', 4:'f', 3:'g'}.keys()", "[1, 2, 6, 0, 5, 4, 3]");
  }

  @Test
  public void testDictionaryGet() throws Exception {
    new Scenario()
        .testExpression("{1: 'foo'}.get(1)", "foo")
        .testExpression("{1: 'foo'}.get(2)", Starlark.NONE)
        .testExpression("{1: 'foo'}.get(2, 'a')", "a")
        .testExpression("{1: 'foo'}.get(2, default='a')", "a")
        .testExpression("{1: 'foo'}.get(2, default=None)", Starlark.NONE);
  }

  @Test
  public void testDictionaryItems() throws Exception {
    new Scenario()
        .testEval("{'a': 'foo'}.items()", "[('a', 'foo')]")
        .testEval("{}.items()", "[]")
        .testEval("{1: 3, 2: 5}.items()", "[(1, 3), (2, 5)]")
        .testEval("{'a': 5, 'c': 2, 'b': 4}.items()", "[('a', 5), ('c', 2), ('b', 4)]");
  }

  @Test
  public void testDictionaryClear() throws Exception {
    new Scenario()
        .setUp(
            "d = {1: 'foo', 2: 'bar', 3: 'baz'}",
            "len(d) == 3 or fail('clear 1')",
            "d.clear() == None or fail('clear 2')")
        .testEval("d", "{}");
  }

  @Test
  public void testDictionaryPop() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "KeyError: 1",
            "d = {1: 'foo', 2: 'bar', 3: 'baz'}\n"
                + "len(d) == 3 or fail('pop 1')\n"
                + "d.pop(2) == 'bar' or fail('pop 2')\n"
                + "d.pop(3, 'quux') == 'baz' or fail('pop 3a')\n"
                + "d.pop(3, 'quux') == 'quux' or fail('pop 3b')\n"
                + "d.pop(1) == 'foo' or fail('pop 1')\n"
                + "d == {} or fail('pop 0')\n"
                + "d.pop(1)");
  }

  @Test
  public void testDictionaryPopItem() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "popitem(): dictionary is empty",
            "d = {2: 'bar', 3: 'baz', 1: 'foo'}\n"
                + "len(d) == 3 or fail('popitem 0')\n"
                + "d.popitem() == (2, 'bar') or fail('popitem 2')\n"
                + "d.popitem() == (3, 'baz') or fail('popitem 3')\n"
                + "d.popitem() == (1, 'foo') or fail('popitem 1')\n"
                + "d == {} or fail('popitem 4')\n"
                + "d.popitem()");
  }

  @Test
  public void testDictionaryUpdate() throws Exception {
    new Scenario()
        .setUp("foo = {'a': 2}", "foo.update({'b': 4})")
        .testEval("foo", "{'a': 2, 'b': 4}");
    new Scenario()
        .setUp("foo = {'a': 2}", "foo.update({'a': 3, 'b': 4})")
        .testEval("foo", "{'a': 3, 'b': 4}");
  }

  @Test
  public void testDictionarySetDefault() throws Exception {
    new Scenario()
        .setUp(
            "d = {2: 'bar', 1: 'foo'}",
            "len(d) == 2 or fail('setdefault 0')",
            "d.setdefault(1, 'a') == 'foo' or fail('setdefault 1')",
            "d.setdefault(2) == 'bar' or fail('setdefault 2')",
            "d.setdefault(3) == None or fail('setdefault 3')",
            "d.setdefault(4, 'b') == 'b' or fail('setdefault 4')")
        .testEval("d", "{1: 'foo', 2: 'bar', 3: None, 4: 'b'}");
  }

  @Test
  public void testListIndexMethod() throws Exception {
    new Scenario()
        .testExpression("['a', 'b', 'c'].index('a')", 0)
        .testExpression("['a', 'b', 'c'].index('b')", 1)
        .testExpression("['a', 'b', 'c'].index('c')", 2)
        .testExpression("[2, 4, 6].index(4)", 1)
        .testExpression("[2, 4, 6].index(4)", 1)
        .testExpression("[0, 1, [1]].index([1])", 2)
        .testIfErrorContains("item \"a\" not found in list", "[1, 2].index('a')")
        .testIfErrorContains("item 0 not found in list", "[].index(0)");
  }

  @Test
  public void testHash() throws Exception {
    // We specify the same string hashing algorithm as String.hashCode().
    new Scenario()
        .testExpression("hash('skylark')", "skylark".hashCode())
        .testExpression("hash('google')", "google".hashCode())
        .testIfErrorContains(
            "in call to hash(), parameter 'value' got value of type 'NoneType', want 'string'",
            "hash(None)");
  }

  @Test
  public void testRangeType() throws Exception {
    new Scenario()
        .setUp("a = range(3)")
        .testExpression("len(a)", 3)
        .testExpression("str(a)", "range(0, 3)")
        .testExpression("str(range(1,2,3))", "range(1, 2, 3)")
        .testExpression("repr(a)", "range(0, 3)")
        .testExpression("repr(range(1,2,3))", "range(1, 2, 3)")
        .testExpression("type(a)", "range")
        .testIfErrorContains("unsupported binary operation: range + range", "a + a")
        .testIfErrorContains("'range' value has no field or method 'append'", "a.append(3)")
        .testExpression("str(list(range(5)))", "[0, 1, 2, 3, 4]")
        .testExpression("str(list(range(0)))", "[]")
        .testExpression("str(list(range(1)))", "[0]")
        .testExpression("str(list(range(-2)))", "[]")
        .testExpression("str(list(range(-3, 2)))", "[-3, -2, -1, 0, 1]")
        .testExpression("str(list(range(3, 2)))", "[]")
        .testExpression("str(list(range(3, 3)))", "[]")
        .testExpression("str(list(range(3, 4)))", "[3]")
        .testExpression("str(list(range(3, 5)))", "[3, 4]")
        .testExpression("str(list(range(-3, 5, 2)))", "[-3, -1, 1, 3]")
        .testExpression("str(list(range(-3, 6, 2)))", "[-3, -1, 1, 3, 5]")
        .testExpression("str(list(range(5, 0, -1)))", "[5, 4, 3, 2, 1]")
        .testExpression("str(list(range(5, 0, -10)))", "[5]")
        .testExpression("str(list(range(0, -3, -2)))", "[0, -2]")
        .testExpression("range(3)[-1]", 2)
        .testIfErrorContains(
            "index out of range (index is 3, but sequence has 3 elements)", "range(3)[3]")
        .testExpression("str(range(5)[1:])", "range(1, 5)")
        .testExpression("len(range(5)[1:])", 4)
        .testExpression("str(range(5)[:2])", "range(0, 2)")
        .testExpression("str(range(10)[1:9:2])", "range(1, 9, 2)")
        .testExpression("str(list(range(10)[1:9:2]))", "[1, 3, 5, 7]")
        .testExpression("str(range(10)[1:10:2])", "range(1, 10, 2)")
        .testExpression("str(range(10)[1:11:2])", "range(1, 10, 2)")
        .testExpression("str(range(0, 10, 2)[::2])", "range(0, 10, 4)")
        .testExpression("str(range(0, 10, 2)[::-2])", "range(8, -2, -4)")
        .testExpression("str(range(5)[1::-1])", "range(1, -1, -1)")
        .testIfErrorContains("step cannot be 0", "range(2, 3, 0)")
        .testIfErrorContains("unsupported binary operation: range * int", "range(3) * 3")
        .testIfErrorContains("Cannot compare range objects", "range(3) < range(5)")
        .testIfErrorContains("Cannot compare range objects", "range(4) > [1]")
        .testExpression("4 in range(1, 10)", true)
        .testExpression("4 in range(1, 3)", false)
        .testExpression("4 in range(0, 8, 2)", true)
        .testExpression("4 in range(1, 8, 2)", false)
        .testExpression("range(0, 5, 10) == range(0, 5, 11)", true)
        .testExpression("range(0, 5, 2) == [0, 2, 4]", false)
        .testExpression("str(list(range(1, 10, 2)))", "[1, 3, 5, 7, 9]")
        .testExpression("str(range(1, 10, 2)[:99])", "range(1, 11, 2)")
        .testExpression("range(1, 10, 2) == range(1, 11, 2)", true)
        .testExpression("range(1, 10, 2) == range(1, 12, 2)", false)
        // x in range(...), +ve step
        .testExpression("2          in range(3, 0x7ffffffd, 2)", false) // too low
        .testExpression("3          in range(3, 0x7ffffffd, 2)", true) // in range
        .testExpression("4          in range(3, 0x7ffffffd, 2)", false) // even
        .testExpression("5          in range(3, 0x7ffffffd, 2)", true) // in range
        .testExpression("0x7ffffffb in range(3, 0x7ffffffd, 2)", true) // in range
        .testExpression("0x7ffffffc in range(3, 0x7ffffffd, 2)", false) // even
        .testExpression("0x7ffffffd in range(3, 0x7ffffffd, 2)", false) // too high
        // x in range(...), -ve step
        .testExpression("0x7ffffffe in range(0x7ffffffd, 3, -2)", false) // too high
        .testExpression("0x7ffffffd in range(0x7ffffffd, 3, -2)", true) // in range
        .testExpression("0x7ffffffc in range(0x7ffffffd, 3, -2)", false) // even
        .testExpression("0x7ffffffb in range(0x7ffffffd, 3, -2)", true) // in range
        .testExpression("5          in range(0x7ffffffd, 3, -2)", true) // in range
        .testExpression("4          in range(0x7ffffffd, 3, -2)", false) // even
        .testExpression("3          in range(0x7ffffffd, 3, -2)", false); // too low
  }

  @Test
  public void testEnumerate() throws Exception {
    new Scenario()
        .testExpression("str(enumerate([]))", "[]")
        .testExpression("str(enumerate([5]))", "[(0, 5)]")
        .testExpression("str(enumerate([5, 3]))", "[(0, 5), (1, 3)]")
        .testExpression("str(enumerate(['a', 'b', 'c']))", "[(0, \"a\"), (1, \"b\"), (2, \"c\")]")
        .testExpression("str(enumerate(['a']) + [(1, 'b')])", "[(0, \"a\"), (1, \"b\")]");
  }

  @Test
  public void testEnumerateBadArg() throws Exception {
    new Scenario().testIfErrorContains("type 'string' is not iterable", "enumerate('a')");
  }

  @Test
  public void testReassignmentOfPrimitivesNotForbiddenByCoreLanguage() throws Exception {
    new Scenario()
        .setUp("cc_binary = (['hello.cc'])")
        .testIfErrorContains(
            "'list' object is not callable",
            "cc_binary(name = 'hello', srcs=['hello.cc'], malloc = '//base:system_malloc')");
  }

  @Test
  public void testLenOnString() throws Exception {
    new Scenario().testExpression("len('abc')", 3);
  }

  @Test
  public void testLenOnList() throws Exception {
    new Scenario().testExpression("len([1,2,3])", 3);
  }

  @Test
  public void testLenOnDict() throws Exception {
    new Scenario().testExpression("len({'a' : 1, 'b' : 2})", 2);
  }

  @Test
  public void testLenOnBadType() throws Exception {
    new Scenario().testIfErrorContains("int is not iterable", "len(1)");
  }

  @Test
  public void testIndexOnFunction() throws Exception {
    new Scenario()
        .testIfErrorContains("type 'function' has no operator [](int)", "len[1]")
        .testIfErrorContains("invalid slice operand: function", "len[1:4]");
  }

  @Test
  public void testBool() throws Exception {
    new Scenario()
        .testExpression("bool(1)", Boolean.TRUE)
        .testExpression("bool(0)", Boolean.FALSE)
        .testExpression("bool([1, 2])", Boolean.TRUE)
        .testExpression("bool([])", Boolean.FALSE)
        .testExpression("bool(None)", Boolean.FALSE);
  }

  @Test
  public void testStr() throws Exception {
    new Scenario()
        .testExpression("str(1)", "1")
        .testExpression("str(-2)", "-2")
        .testExpression("str([1, 2])", "[1, 2]")
        .testExpression("str(True)", "True")
        .testExpression("str(False)", "False")
        .testExpression("str(None)", "None")
        .testExpression("str(str)", "<built-in function str>");
  }

  @Test
  public void testStrFunction() throws Exception {
    new Scenario().setUp("def foo(x): pass").testExpression("str(foo)", "<function foo>");
  }

  @Test
  public void testType() throws Exception {
    new Scenario()
        .testExpression("type(1)", "int")
        .testExpression("type('a')", "string")
        .testExpression("type([1, 2])", "list")
        .testExpression("type((1, 2))", "tuple")
        .testExpression("type(True)", "bool")
        .testExpression("type(None)", "NoneType")
        .testExpression("type(str)", "function");
  }

  @Test
  public void testZipFunction() throws Exception {
    new Scenario()
        .testExpression("str(zip())", "[]")
        .testExpression("str(zip([1, 2]))", "[(1,), (2,)]")
        .testExpression("str(zip([1, 2], ['a', 'b']))", "[(1, \"a\"), (2, \"b\")]")
        .testExpression("str(zip([1, 2, 3], ['a', 'b']))", "[(1, \"a\"), (2, \"b\")]")
        .testExpression("str(zip([1], [2], [3]))", "[(1, 2, 3)]")
        .testExpression("str(zip([1], {2: 'a'}))", "[(1, 2)]")
        .testExpression("str(zip([1], []))", "[]")
        .testIfErrorContains("type 'int' is not iterable", "zip(123)")
        .testIfErrorContains("type 'int' is not iterable", "zip([1], 1)");
  }

  /**
   * Assert that lstrip(), rstrip(), and strip() produce the expected result for a given input
   * string and chars argument. If chars is null no argument is passed.
   */
  private void checkStrip(
      String input, Object chars,
      String expLeft, String expRight, String expBoth) throws Exception {
    if (chars == null) {
      new Scenario()
          .update("s", input)
          .testExpression("s.lstrip()", expLeft)
          .testExpression("s.rstrip()", expRight)
          .testExpression("s.strip()", expBoth);
    } else {
      new Scenario()
          .update("s", input)
          .update("chars", chars)
          .testExpression("s.lstrip(chars)", expLeft)
          .testExpression("s.rstrip(chars)", expRight)
          .testExpression("s.strip(chars)", expBoth);
    }
  }

  @Test
  public void testStrip() throws Exception {
    // Strip nothing.
    checkStrip("a b c", "", "a b c", "a b c", "a b c");
    checkStrip(" a b c ", "", " a b c ", " a b c ", " a b c ");
    // Normal case, found and not found.
    checkStrip("abcba", "ba", "cba", "abc", "c");
    checkStrip("abc", "xyz", "abc", "abc", "abc");
    // Default whitespace.
    checkStrip(" a b c ", null, "a b c ", " a b c", "a b c");
    checkStrip(" a b c ", Starlark.NONE, "a b c ", " a b c", "a b c");
    // Default whitespace with full range of Latin-1 whitespace chars.
    String whitespace = "\u0009\n\u000B\u000C\r\u001C\u001D\u001E\u001F\u0020\u0085\u00A0";
    checkStrip(
        whitespace + "a" + whitespace, null,
        "a" + whitespace, whitespace + "a", "a");
    checkStrip(
        whitespace + "a" + whitespace, Starlark.NONE, "a" + whitespace, whitespace + "a", "a");
    // Empty cases.
    checkStrip("", "", "", "", "");
    checkStrip("abc", "abc", "", "", "");
    checkStrip("", "xyz", "", "", "");
    checkStrip("", null, "", "", "");
  }

  @Test
  public void testFail() throws Exception {
    new Scenario().testIfErrorContains("abc", "fail('abc')").testIfErrorContains("18", "fail(18)");
  }

  @Test
  public void testTupleCoercion() throws Exception {
    new Scenario()
        .testExpression("tuple([1, 2]) == (1, 2)", true)
        // Depends on current implementation of dict
        .testExpression("tuple({1: 'foo', 2: 'bar'}) == (1, 2)", true);
  }

  @Test
  public void testPositionalOnlyArgument() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "join() got named argument for positional-only parameter 'elements'",
            "','.join(elements=['foo', 'bar'])");
  }

  @Test
  public void testStringJoinRequiresStrings() throws Exception {
    new Scenario()
        .testIfErrorContains(
            "expected string for sequence element 1, got 'int'", "', '.join(['foo', 2])");
  }
}


text:
import express from 'express';
import passport from 'passport';
import compression from 'compression';
import cors from 'cors';
import bodyParser from 'body-parser';
import multipart from 'connect-multiparty';
import parseQuery from './utils/parse-query';
import parseError from './utils/parse-error';
import { throwIfInvalid } from '../utils/is-core';
import * as queries from './queries';
import * as models from './database';
import authenticate from './auth';

const { env: { NODE_ENV } } = process;

const api = express();

api.use(compression());
api.use(cors());
api.use(bodyParser.json());
api.use(multipart());

api.use(passport.initialize());

api.use(async (req, res, next) => {
  try {
    const { path, method, body } = req;
    const query = parseQuery(queries, path, method);
    const { secured, validate } = query;

    const user = secured && authenticate(req);

    if (validate) {
      throwIfInvalid(validate(body));
    }

    const response = await query({ req, res, next, models, user });

    if (response) {
      res.send(response);
    }
  } catch (error) {
    const { status, data } = parseError(error, 'Not found');

    res.status(status).send(data);
  }
});

export function listen(apiPort) {
  return new Promise((resolve, reject) => {
    try {
      const server = api.listen(apiPort, () => {
        console.info(`API server is listen on ${apiPort} port in ${NODE_ENV} mode.`);

        resolve(() => {
          server.close();
        });
      });
    } catch (error) {
      reject(error);
    }
  });
}

export default api;

// https://www.npmjs.com/package/http-errors

redpajama_set_name: RedPajamaGithub


text:
package org.onosproject.driver.pipeline;

import static java.util.concurrent.Executors.newScheduledThreadPool;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;

import com.google.common.collect.ImmutableList;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.NextGroup;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.Criterion.Type;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.MplsBosCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveStore;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupEvent;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupListener;
import org.onosproject.net.group.GroupService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Driver for SPRING-OPEN pipeline.
 */
public class SpringOpenTTP extends AbstractHandlerBehaviour
        implements Pipeliner {

    /**
     * GroupCheck delay.
     */
    private static final int CHECK_DELAY = 500;

    // Default table ID - compatible with CpqD switch
    private static final int TABLE_VLAN = 0;
    private static final int TABLE_TMAC = 1;
    private static final int TABLE_IPV4_UNICAST = 2;
    private static final int TABLE_MPLS = 3;
    private static final int TABLE_DMAC = 4;
    private static final int TABLE_ACL = 5;
    private static final int TABLE_SMAC = 6;

    /**
     * Set the default values. These variables will get overwritten based on the
     * switch vendor type
     */
    protected int vlanTableId = TABLE_VLAN;
    protected int tmacTableId = TABLE_TMAC;
    protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
    protected int mplsTableId = TABLE_MPLS;
    protected int dstMacTableId = TABLE_DMAC;
    protected int aclTableId = TABLE_ACL;
    protected int srcMacTableId = TABLE_SMAC;

    private static final Logger log = getLogger(SpringOpenTTP.class);

    private ServiceDirectory serviceDirectory;
    private FlowRuleService flowRuleService;
    private CoreService coreService;
    protected GroupService groupService;
    protected FlowObjectiveStore flowObjectiveStore;
    protected DeviceId deviceId;
    private ApplicationId appId;

    private Cache<GroupKey, NextObjective> pendingGroups;

    private static final ScheduledExecutorService GROUP_CHECKER
        = newScheduledThreadPool(2,
                                 groupedThreads("onos/pipeliner",
                                                "spring-open-%d", log));
    static {
        // ONOS-3579 workaround, let core threads die out on idle
        if (GROUP_CHECKER instanceof ScheduledThreadPoolExecutor) {
            ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) GROUP_CHECKER;
            executor.setKeepAliveTime(CHECK_DELAY * 2L, TimeUnit.MILLISECONDS);
            executor.allowCoreThreadTimeOut(true);
        }
    }

    protected KryoNamespace appKryo = new KryoNamespace.Builder()
            .register(KryoNamespaces.API)
            .register(GroupKey.class)
            .register(DefaultGroupKey.class)
            .register(TrafficTreatment.class)
            .register(SpringOpenGroup.class)
            .build("SpringOpenTTP");

    @Override
    public void init(DeviceId deviceId, PipelinerContext context) {
        this.serviceDirectory = context.directory();
        this.deviceId = deviceId;

        pendingGroups = CacheBuilder
                .newBuilder()
                .expireAfterWrite(20, TimeUnit.SECONDS)
                .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
                                     if (notification.getCause() == RemovalCause.EXPIRED) {
                                         fail(notification.getValue(),
                                              ObjectiveError.GROUPINSTALLATIONFAILED);
                                     }
                                 }).build();

        coreService = serviceDirectory.get(CoreService.class);
        flowRuleService = serviceDirectory.get(FlowRuleService.class);
        groupService = serviceDirectory.get(GroupService.class);
        flowObjectiveStore = context.store();

        groupService.addListener(new InnerGroupListener());

        appId = coreService
                .registerApplication("org.onosproject.driver.SpringOpenTTP");

        setTableMissEntries();
        log.info("Spring Open TTP driver initialized");
    }

    @Override
    public void filter(FilteringObjective filteringObjective) {
        if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
            log.debug("processing PERMIT filter objective");
            processFilter(filteringObjective,
                          filteringObjective.op() == Objective.Operation.ADD,
                          filteringObjective.appId());
        } else {
            log.debug("filter objective other than PERMIT not supported");
            fail(filteringObjective, ObjectiveError.UNSUPPORTED);
        }
    }

    @Override
    public void forward(ForwardingObjective fwd) {
        Collection<FlowRule> rules;
        FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();

        rules = processForward(fwd);
        switch (fwd.op()) {
        case ADD:
            rules.stream().filter(Objects::nonNull)
                    .forEach(flowBuilder::add);
            break;
        case REMOVE:
            rules.stream().filter(Objects::nonNull)
                    .forEach(flowBuilder::remove);
            break;
        default:
            fail(fwd, ObjectiveError.UNKNOWN);
            log.warn("Unknown forwarding type {}", fwd.op());
        }

        flowRuleService.apply(flowBuilder
                .build(new FlowRuleOperationsContext() {
                    @Override
                    public void onSuccess(FlowRuleOperations ops) {
                        pass(fwd);
                        log.debug("Provisioned tables in {} successfully with "
                                + "forwarding rules", deviceId);
                    }

                    @Override
                    public void onError(FlowRuleOperations ops) {
                        fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
                        log.warn("Failed to provision tables in {} with "
                                + "forwarding rules", deviceId);
                    }
                }));

    }

    @Override
    public void next(NextObjective nextObjective) {
        NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
        switch (nextObjective.op()) {
        case ADD:
            if (nextGroup != null) {
                log.warn("Cannot add next {} that already exists in device {}",
                         nextObjective.id(), deviceId);
                return;
            }
            log.debug("Processing NextObjective id{} in dev{} - add group",
                      nextObjective.id(), deviceId);
            addGroup(nextObjective);
            break;
        case ADD_TO_EXISTING:
            if (nextGroup != null) {
                log.debug("Processing NextObjective id{} in dev{} - add bucket",
                          nextObjective.id(), deviceId);
                addBucketToGroup(nextObjective);
            } else {
                log.warn("Cannot add to group that does not exist");
            }
            break;
        case REMOVE:
            if (nextGroup == null) {
                log.warn("Cannot remove next {} that does not exist in device {}",
                         nextObjective.id(), deviceId);
                return;
            }
            log.debug("Processing NextObjective id{}  in dev{} - remove group",
                      nextObjective.id(), deviceId);
            removeGroup(nextObjective);
            break;
        case REMOVE_FROM_EXISTING:
            if (nextGroup == null) {
                log.warn("Cannot remove from next {} that does not exist in device {}",
                         nextObjective.id(), deviceId);
                return;
            }
            log.debug("Processing NextObjective id{} in dev{} - remove bucket",
                      nextObjective.id(), deviceId);
            removeBucketFromGroup(nextObjective);
            break;
        default:
            log.warn("Unsupported operation {}", nextObjective.op());
        }
    }

    @Override
    public void purgeAll(ApplicationId appId) {
        flowRuleService.purgeFlowRules(deviceId, appId);
        groupService.purgeGroupEntries(deviceId, appId);
    }

    private void removeGroup(NextObjective nextObjective) {
        log.debug("removeGroup in {}: for next objective id {}",
                  deviceId, nextObjective.id());
        final GroupKey key = new DefaultGroupKey(
                appKryo.serialize(nextObjective.id()));
        groupService.removeGroup(deviceId, key, appId);
    }

    private void addGroup(NextObjective nextObjective) {
        log.debug("addGroup with type{} for nextObjective id {}",
                  nextObjective.type(), nextObjective.id());
        List<GroupBucket> buckets;
        switch (nextObjective.type()) {
            case SIMPLE:
                Collection<TrafficTreatment> treatments = nextObjective.next();
                if (treatments.size() == 1) {
                    // Spring Open TTP converts simple nextObjective to flow-actions
                    // in a dummy group
                    TrafficTreatment treatment = nextObjective.next().iterator().next();
                    log.debug("Converting SIMPLE group for next objective id {} " +
                            "to {} flow-actions in device:{}", nextObjective.id(),
                            treatment.allInstructions().size(), deviceId);
                    flowObjectiveStore.putNextGroup(nextObjective.id(),
                                                    new SpringOpenGroup(null, treatment));
                }
                break;
            case HASHED:
                // we convert MPLS ECMP groups to flow-actions for a single
                // bucket(output port).
                boolean mplsEcmp = false;
                if (nextObjective.meta() != null) {
                    for (Criterion c : nextObjective.meta().criteria()) {
                        if (c.type() == Type.MPLS_LABEL) {
                            mplsEcmp = true;
                        }
                    }
                }
                if (mplsEcmp) {
                    // covert to flow-actions in a dummy group by choosing the first bucket
                    log.debug("Converting HASHED group for next objective id {} " +
                              "to flow-actions in device:{}", nextObjective.id(),
                              deviceId);
                    TrafficTreatment treatment = nextObjective.next().iterator().next();
                    flowObjectiveStore.putNextGroup(nextObjective.id(),
                                                    new SpringOpenGroup(null, treatment));
                } else {
                    // process as ECMP group
                    buckets = nextObjective
                            .next()
                            .stream()
                            .map(DefaultGroupBucket::createSelectGroupBucket)
                            .collect(Collectors.toList());
                    if (!buckets.isEmpty()) {
                        final GroupKey key = new DefaultGroupKey(
                                                     appKryo.serialize(nextObjective.id()));
                        GroupDescription groupDescription = new DefaultGroupDescription(
                                                  deviceId,
                                                  GroupDescription.Type.SELECT,
                                                  new GroupBuckets(buckets),
                                                  key,
                                                  null,
                                                  nextObjective.appId());
                        log.debug("Creating HASHED group for next objective id {}"
                                + " in dev:{}", nextObjective.id(), deviceId);
                        pendingGroups.put(key, nextObjective);
                        groupService.addGroup(groupDescription);
                        verifyPendingGroupLater();
                    }
                }
                break;
            case BROADCAST:
                buckets = nextObjective
                        .next()
                        .stream()
                        .map(DefaultGroupBucket::createAllGroupBucket)
                        .collect(Collectors.toList());
                if (!buckets.isEmpty()) {
                    final GroupKey key = new DefaultGroupKey(
                            appKryo.serialize(nextObjective
                                                      .id()));
                    GroupDescription groupDescription = new DefaultGroupDescription(
                            deviceId,
                            GroupDescription.Type.ALL,
                            new GroupBuckets(buckets),
                            key,
                            null,
                            nextObjective.appId());
                    log.debug("Creating BROADCAST group for next objective id {} "
                            + "in device {}", nextObjective.id(), deviceId);
                    pendingGroups.put(key, nextObjective);
                    groupService.addGroup(groupDescription);
                    verifyPendingGroupLater();
                }
                break;
            case FAILOVER:
                log.debug("FAILOVER next objectives not supported");
                fail(nextObjective, ObjectiveError.UNSUPPORTED);
                log.warn("Unsupported next objective type {}", nextObjective.type());
                break;
            default:
                fail(nextObjective, ObjectiveError.UNKNOWN);
                log.warn("Unknown next objective type {}", nextObjective.type());
        }
    }

    private void addBucketToGroup(NextObjective nextObjective) {
        log.debug("addBucketToGroup in {}: for next objective id {}",
                  deviceId, nextObjective.id());
        Collection<TrafficTreatment> treatments = nextObjective.next();
        TrafficTreatment treatment = treatments.iterator().next();
        final GroupKey key = new DefaultGroupKey(
                appKryo.serialize(nextObjective
                        .id()));
        Group group = groupService.getGroup(deviceId, key);
        if (group == null) {
            log.warn("Group is not found in {} for {}", deviceId, key);
            return;
        }
        GroupBucket bucket;
        if (group.type() == GroupDescription.Type.INDIRECT) {
            bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
        } else if (group.type() == GroupDescription.Type.SELECT) {
            bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
        } else if (group.type() == GroupDescription.Type.ALL) {
            bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
        } else {
            log.warn("Unsupported Group type {}", group.type());
            return;
        }
        GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
        log.debug("Adding buckets to group id {} of next objective id {} in device {}",
                  group.id(), nextObjective.id(), deviceId);
        groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
    }

    private void removeBucketFromGroup(NextObjective nextObjective) {
        log.debug("removeBucketFromGroup in {}: for next objective id {}",
                  deviceId, nextObjective.id());
        NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
        if (nextGroup != null) {
            Collection<TrafficTreatment> treatments = nextObjective.next();
            TrafficTreatment treatment = treatments.iterator().next();
            final GroupKey key = new DefaultGroupKey(
                    appKryo.serialize(nextObjective
                            .id()));
            Group group = groupService.getGroup(deviceId, key);
            if (group == null) {
                log.warn("Group is not found in {} for {}", deviceId, key);
                return;
            }
            GroupBucket bucket;
            if (group.type() == GroupDescription.Type.INDIRECT) {
                bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
            } else if (group.type() == GroupDescription.Type.SELECT) {
                bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
            } else if (group.type() == GroupDescription.Type.ALL) {
                bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
            } else {
                log.warn("Unsupported Group type {}", group.type());
                return;
            }
            GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
            log.debug("Removing buckets from group id {} of next objective id {} in device {}",
                      group.id(), nextObjective.id(), deviceId);
            groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
        }
    }

    private Collection<FlowRule> processForward(ForwardingObjective fwd) {
        switch (fwd.flag()) {
        case SPECIFIC:
            return processSpecific(fwd);
        case VERSATILE:
            return processVersatile(fwd);
        default:
            fail(fwd, ObjectiveError.UNKNOWN);
            log.warn("Unknown forwarding flag {}", fwd.flag());
        }
        return Collections.emptySet();
    }

    private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
        log.debug("Processing versatile forwarding objective in dev:{}", deviceId);
        TrafficSelector selector = fwd.selector();
        EthTypeCriterion ethType =
                (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
        if (ethType == null) {
            log.error("Versatile forwarding objective must include ethType");
            fail(fwd, ObjectiveError.UNKNOWN);
            return Collections.emptySet();
        }

        if (fwd.treatment() == null && fwd.nextId() == null) {
            log.error("VERSATILE forwarding objective needs next objective ID "
                    + "or treatment.");
            return Collections.emptySet();
        }
        // emulation of ACL table (for versatile fwd objective) requires
        // overriding any previous instructions
        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
                .builder();
        treatmentBuilder.wipeDeferred();

        if (fwd.nextId() != null) {
            NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
            if (next != null) {
                SpringOpenGroup soGroup = appKryo.deserialize(next.data());
                if (soGroup.dummy) {
                    // need to convert to flow-actions
                    for (Instruction ins : soGroup.treatment.allInstructions()) {
                        treatmentBuilder.add(ins);
                    }
                } else {
                    GroupKey key = soGroup.key;
                    Group group = groupService.getGroup(deviceId, key);
                    if (group == null) {
                        log.warn("The group left!");
                        fail(fwd, ObjectiveError.GROUPMISSING);
                        return Collections.emptySet();
                    }
                    treatmentBuilder.deferred().group(group.id());
                    log.debug("Adding OUTGROUP action");
                }
            }
        }

        if (fwd.treatment() != null) {
            if (fwd.treatment().allInstructions().size() == 1 &&
                    fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
                OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
                if (o.port() == PortNumber.CONTROLLER) {
                    treatmentBuilder.popVlan();
                    treatmentBuilder.punt();
                } else {
                    treatmentBuilder.add(o);
                }
            } else {
                for (Instruction ins : fwd.treatment().allInstructions()) {
                    treatmentBuilder.add(ins);
                }
            }
        }

        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                .fromApp(fwd.appId()).withPriority(fwd.priority())
                .forDevice(deviceId).withSelector(fwd.selector())
                .withTreatment(treatmentBuilder.build());

        if (fwd.permanent()) {
            ruleBuilder.makePermanent();
        } else {
            ruleBuilder.makeTemporary(fwd.timeout());
        }

        ruleBuilder.forTable(aclTableId);
        return Collections.singletonList(ruleBuilder.build());
    }

    private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
        TrafficSelector selector = fwd.selector();
        EthTypeCriterion ethType = (EthTypeCriterion) selector
                .getCriterion(Criterion.Type.ETH_TYPE);
        if ((ethType == null) ||
                ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
                        (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) {
            return false;
        }
        return true;
    }

    private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
        TrafficSelector selector = fwd.selector();
        EthCriterion ethDst = (EthCriterion) selector
                .getCriterion(Criterion.Type.ETH_DST);
        VlanIdCriterion vlanId = (VlanIdCriterion) selector
                .getCriterion(Criterion.Type.VLAN_VID);
        if (ethDst == null && vlanId == null) {
            return false;
        }
        return true;
    }

    protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
        log.debug("Processing specific fwd objective:{} in dev:{} with next:{}",
                  fwd.id(), deviceId, fwd.nextId());
        boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
        boolean isEthDstObj = isSupportedEthDstObjective(fwd);

        if (isEthTypeObj) {
            return processEthTypeSpecificObjective(fwd);
        } else if (isEthDstObj) {
            return processEthDstSpecificObjective(fwd);
        } else {
            log.warn("processSpecific: Unsupported "
                    + "forwarding objective criteria");
            fail(fwd, ObjectiveError.UNSUPPORTED);
            return Collections.emptySet();
        }
    }

    protected Collection<FlowRule>
    processEthTypeSpecificObjective(ForwardingObjective fwd) {
        TrafficSelector selector = fwd.selector();
        EthTypeCriterion ethType = (EthTypeCriterion) selector
                .getCriterion(Criterion.Type.ETH_TYPE);

        TrafficSelector.Builder filteredSelectorBuilder =
                DefaultTrafficSelector.builder();
        int forTableId = -1;
        if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
            filteredSelectorBuilder = filteredSelectorBuilder
                .matchEthType(Ethernet.TYPE_IPV4)
                .matchIPDst(((IPCriterion) selector
                        .getCriterion(Criterion.Type.IPV4_DST))
                        .ip());
            forTableId = ipv4UnicastTableId;
            log.debug("processing IPv4 specific forwarding objective:{} in dev:{}",
                      fwd.id(), deviceId);
        } else {
            filteredSelectorBuilder = filteredSelectorBuilder
                .matchEthType(Ethernet.MPLS_UNICAST)
                .matchMplsLabel(((MplsCriterion)
                   selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
            if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
                filteredSelectorBuilder.matchMplsBos(((MplsBosCriterion)
                        selector.getCriterion(Type.MPLS_BOS)).mplsBos());
            }
            forTableId = mplsTableId;
            log.debug("processing MPLS specific forwarding objective:{} in dev:{}",
                    fwd.id(), deviceId);
        }

        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
                .builder();
        if (fwd.treatment() != null) {
            for (Instruction i : fwd.treatment().allInstructions()) {
                treatmentBuilder.add(i);
            }
        }

        if (fwd.nextId() != null) {
            NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
            if (next != null) {
                SpringOpenGroup soGroup = appKryo.deserialize(next.data());
                if (soGroup.dummy) {
                    log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} "
                            + "in dev: {}", soGroup.treatment.allInstructions().size(),
                            fwd.id(), fwd.nextId(), deviceId);
                    for (Instruction ins : soGroup.treatment.allInstructions()) {
                        treatmentBuilder.add(ins);
                    }
                } else {
                    GroupKey key = soGroup.key;
                    Group group = groupService.getGroup(deviceId, key);
                    if (group == null) {
                        log.warn("The group left!");
                        fail(fwd, ObjectiveError.GROUPMISSING);
                        return Collections.emptySet();
                    }
                    treatmentBuilder.deferred().group(group.id());
                    log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
                            + "for next:{} in dev: {}", group.id(), fwd.id(),
                            fwd.nextId(), deviceId);
                }
            } else {
                log.warn("processSpecific: No associated next objective object");
                fail(fwd, ObjectiveError.GROUPMISSING);
                return Collections.emptySet();
            }
        }

        TrafficSelector filteredSelector = filteredSelectorBuilder.build();
        TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
                .build();

        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                .fromApp(fwd.appId()).withPriority(fwd.priority())
                .forDevice(deviceId).withSelector(filteredSelector)
                .withTreatment(treatment);

        if (fwd.permanent()) {
            ruleBuilder.makePermanent();
        } else {
            ruleBuilder.makeTemporary(fwd.timeout());
        }

        ruleBuilder.forTable(forTableId);
        return Collections.singletonList(ruleBuilder.build());

    }

    protected Collection<FlowRule>
    processEthDstSpecificObjective(ForwardingObjective fwd) {
        List<FlowRule> rules = new ArrayList<>();

        // Build filtered selector
        TrafficSelector selector = fwd.selector();
        EthCriterion ethCriterion = (EthCriterion) selector
                .getCriterion(Criterion.Type.ETH_DST);
        VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
                .getCriterion(Criterion.Type.VLAN_VID);
        TrafficSelector.Builder filteredSelectorBuilder =
                DefaultTrafficSelector.builder();
        // Do not match MacAddress for subnet broadcast entry
        if (!ethCriterion.mac().equals(MacAddress.NONE)) {
            filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
            log.debug("processing L2 forwarding objective:{} in dev:{}",
                      fwd.id(), deviceId);
        } else {
            log.debug("processing L2 Broadcast forwarding objective:{} "
                    + "in dev:{} for vlan:{}",
                      fwd.id(), deviceId, vlanIdCriterion.vlanId());
        }
        filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
        TrafficSelector filteredSelector = filteredSelectorBuilder.build();

        // Build filtered treatment
        TrafficTreatment.Builder treatmentBuilder =
                DefaultTrafficTreatment.builder();
        if (fwd.treatment() != null) {
            treatmentBuilder.deferred();
            fwd.treatment().allInstructions().forEach(treatmentBuilder::add);
        }
        if (fwd.nextId() != null) {
            NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
            if (next != null) {
                SpringOpenGroup soGrp = appKryo.deserialize(next.data());
                if (soGrp.dummy) {
                    log.debug("Adding {} flow-actions for fwd. obj. {} "
                            + "in dev: {}", soGrp.treatment.allInstructions().size(),
                            fwd.id(), deviceId);
                    for (Instruction ins : soGrp.treatment.allInstructions()) {
                        treatmentBuilder.deferred().add(ins);
                    }
                } else {
                    GroupKey key = soGrp.key;
                    Group group = groupService.getGroup(deviceId, key);
                    if (group == null) {
                        log.warn("The group left!");
                        fail(fwd, ObjectiveError.GROUPMISSING);
                        return Collections.emptySet();
                    }
                    treatmentBuilder.deferred().group(group.id());
                    log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
                            + "in dev: {}", group.id(), fwd.id(), deviceId);
                }
            }
        }
        treatmentBuilder.immediate().transition(aclTableId);
        TrafficTreatment filteredTreatment = treatmentBuilder.build();

        // Build bridging table entries
        FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
        flowRuleBuilder.fromApp(fwd.appId())
                .withPriority(fwd.priority())
                .forDevice(deviceId)
                .withSelector(filteredSelector)
                .withTreatment(filteredTreatment)
                .forTable(dstMacTableId);
        if (fwd.permanent()) {
            flowRuleBuilder.makePermanent();
        } else {
            flowRuleBuilder.makeTemporary(fwd.timeout());
        }
        rules.add(flowRuleBuilder.build());

        /*
        // TODO Emulate source MAC table behavior
        // Do not install source MAC table entry for subnet broadcast
        if (!ethCriterion.mac().equals(MacAddress.NONE)) {
            // Build filtered selector
            selector = fwd.selector();
            ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST);
            filteredSelectorBuilder = DefaultTrafficSelector.builder();
            filteredSelectorBuilder.matchEthSrc(ethCriterion.mac());
            filteredSelector = filteredSelectorBuilder.build();

            // Build empty treatment. Apply existing instruction if match.
            treatmentBuilder = DefaultTrafficTreatment.builder();
            filteredTreatment = treatmentBuilder.build();

            // Build bridging table entries
            flowRuleBuilder = DefaultFlowRule.builder();
            flowRuleBuilder.fromApp(fwd.appId())
                    .withPriority(fwd.priority())
                    .forDevice(deviceId)
                    .withSelector(filteredSelector)
                    .withTreatment(filteredTreatment)
                    .forTable(srcMacTableId)
                    .makePermanent();
            rules.add(flowRuleBuilder.build());
        }
        */

        return rules;
    }

    /*
     * Note: CpqD switches do not handle MPLS-related operation properly
     * for a packet with VLAN tag. We pop VLAN here as a workaround.
     * Side effect: HostService learns redundant hosts with same MAC but
     * different VLAN. No known side effect on the network reachability.
     */
    protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
                                       VlanIdCriterion vlanIdCriterion,
                                       FilteringObjective filt,
                                       VlanId assignedVlan,
                                       ApplicationId applicationId) {
        if (vlanIdCriterion == null) {
            return processEthDstOnlyFilter(ethCriterion, applicationId, filt.priority());
        }

        //handling untagged packets via assigned VLAN
        if (vlanIdCriterion.vlanId() == VlanId.NONE) {
            vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
        }

        List<FlowRule> rules = new ArrayList<>();
        TrafficSelector.Builder selectorIp = DefaultTrafficSelector
                .builder();
        TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
                .builder();
        selectorIp.matchEthDst(ethCriterion.mac());
        selectorIp.matchEthType(Ethernet.TYPE_IPV4);
        selectorIp.matchVlanId(vlanIdCriterion.vlanId());
        treatmentIp.popVlan();
        treatmentIp.transition(ipv4UnicastTableId);
        FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
                .withSelector(selectorIp.build())
                .withTreatment(treatmentIp.build())
                .withPriority(filt.priority()).fromApp(applicationId)
                .makePermanent().forTable(tmacTableId).build();
        log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac());
        rules.add(ruleIp);

        TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
                .builder();
        TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
                .builder();
        selectorMpls.matchEthDst(ethCriterion.mac());
        selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
        selectorMpls.matchVlanId(vlanIdCriterion.vlanId());
        treatmentMpls.popVlan();
        treatmentMpls.transition(mplsTableId);
        FlowRule ruleMpls = DefaultFlowRule.builder()
                .forDevice(deviceId).withSelector(selectorMpls.build())
                .withTreatment(treatmentMpls.build())
                .withPriority(filt.priority()).fromApp(applicationId)
                .makePermanent().forTable(tmacTableId).build();
        log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac());
        rules.add(ruleMpls);

        return rules;
    }

    protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
            ApplicationId applicationId, int priority) {
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
        selector.matchEthType(Ethernet.TYPE_IPV4);
        selector.matchEthDst(ethCriterion.mac());
        treatment.transition(TABLE_IPV4_UNICAST);
        FlowRule rule = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(priority)
                .fromApp(applicationId)
                .makePermanent()
                .forTable(TABLE_TMAC).build();
        return ImmutableList.<FlowRule>builder().add(rule).build();
    }

    protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
                                                 FilteringObjective filt,
                                                 VlanId assignedVlan, VlanId explicitlyAssignedVlan, VlanId pushedVlan,
                                                 boolean pushVlan, boolean popVlan,
                                                 ApplicationId applicationId) {
        List<FlowRule> rules = new ArrayList<>();
        log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId());
        TrafficSelector.Builder selector = DefaultTrafficSelector
                .builder();
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment
                .builder();
        PortCriterion p = (PortCriterion) filt.key();
        if (vlanIdCriterion.vlanId() != VlanId.NONE) {
            selector.matchVlanId(vlanIdCriterion.vlanId());
            selector.matchInPort(p.port());
            if (popVlan) {
                // Pop outer tag
                treatment.immediate().popVlan();
            }
            if (explicitlyAssignedVlan != null && (!popVlan || !vlanIdCriterion.vlanId().equals(assignedVlan))) {
                // Modify VLAN ID on single tagged packet or modify remaining tag after popping
                // In the first case, do not set VLAN ID again to the already existing value
                treatment.immediate().setVlanId(explicitlyAssignedVlan);
            }
            if (pushVlan) {
                // Push new tag
                treatment.immediate().pushVlan().setVlanId(pushedVlan);
            }
        } else {
            selector.matchInPort(p.port());
            treatment.immediate().pushVlan().setVlanId(assignedVlan);
        }
        treatment.transition(tmacTableId);
        FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(filt.priority()).fromApp(applicationId)
                .makePermanent().forTable(vlanTableId).build();
        rules.add(rule);

        return rules;
    }

    private void processFilter(FilteringObjective filt, boolean install,
                               ApplicationId applicationId) {
        // This driver only processes filtering criteria defined with switch
        // ports as the key
        if (filt.key().equals(Criteria.dummy())
                || filt.key().type() != Criterion.Type.IN_PORT) {
            log.warn("No key defined in filtering objective from app: {}. Not"
                    + "processing filtering objective", applicationId);
            fail(filt, ObjectiveError.UNKNOWN);
            return;
        }

        EthCriterion ethCriterion = null;
        VlanIdCriterion vlanIdCriterion = null;

        // convert filtering conditions for switch-intfs into flowrules
        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();

        for (Criterion criterion : filt.conditions()) {
            if (criterion.type() == Criterion.Type.ETH_DST) {
                ethCriterion = (EthCriterion) criterion;
            } else if (criterion.type() == Criterion.Type.VLAN_VID) {
                vlanIdCriterion = (VlanIdCriterion) criterion;
            } else if (criterion.type() == Criterion.Type.IPV4_DST) {
                log.debug("driver does not process IP filtering rules as it " +
                        "sends all misses in the IP table to the controller");
            } else {
                log.warn("Driver does not currently process filtering condition"
                                 + " of type: {}", criterion.type());
                fail(filt, ObjectiveError.UNSUPPORTED);
            }
        }

        VlanId assignedVlan = null;
        VlanId modifiedVlan = null;
        VlanId pushedVlan = null;
        boolean pushVlan = false;
        boolean popVlan = false;
        if (vlanIdCriterion != null) {
            if (filt.meta() != null) {
                for (Instruction i : filt.meta().allInstructions()) {
                    if (i instanceof L2ModificationInstruction) {
                        if (((L2ModificationInstruction) i).subtype()
                                .equals(L2ModificationInstruction.L2SubType.VLAN_PUSH)) {
                            pushVlan = true;
                        } else if (((L2ModificationInstruction) i).subtype()
                                .equals(L2ModificationInstruction.L2SubType.VLAN_POP)) {
                            if (modifiedVlan != null) {
                                log.error("Pop tag is not allowed after modify VLAN operation " +
                                        "in filtering objective", deviceId);
                                fail(filt, ObjectiveError.BADPARAMS);
                                return;
                            }
                            popVlan = true;
                        }
                    }
                    if (i instanceof ModVlanIdInstruction) {
                        if (pushVlan && vlanIdCriterion.vlanId() != VlanId.NONE) {
                            // Modify VLAN should not appear after pushing a new tag
                            if (pushedVlan != null) {
                                log.error("Modify VLAN not allowed after push tag operation " +
                                        "in filtering objective", deviceId);
                                fail(filt, ObjectiveError.BADPARAMS);
                                return;
                            }
                            pushedVlan = ((ModVlanIdInstruction) i).vlanId();
                        } else if (vlanIdCriterion.vlanId() == VlanId.NONE) {
                            // For untagged packets the pushed VLAN ID will be saved in assignedVlan
                            // just to ensure the driver works as designed for the fabric use case
                            assignedVlan = ((ModVlanIdInstruction) i).vlanId();
                        } else {
                            // For tagged packets modifiedVlan will contain the modified value of existing tag
                            if (modifiedVlan != null) {
                                log.error("Driver does not allow multiple modify VLAN operations " +
                                        "in the same filtering objective", deviceId);
                                fail(filt, ObjectiveError.BADPARAMS);
                                return;
                            }
                            modifiedVlan = ((ModVlanIdInstruction) i).vlanId();
                        }
                    }
                }
            }

            // For VLAN cross-connect packets, use the configured VLAN unless there is an explicitly provided VLAN ID
            if (vlanIdCriterion.vlanId() != VlanId.NONE) {
                if (assignedVlan == null) {
                    assignedVlan = vlanIdCriterion.vlanId();
                }
            // For untagged packets, assign a VLAN ID
            } else {
                if (filt.meta() == null) {
                    log.error("Missing metadata in filtering objective required " +
                            "for vlan assignment in dev {}", deviceId);
                    fail(filt, ObjectiveError.BADPARAMS);
                    return;
                }
                if (assignedVlan == null) {
                    log.error("Driver requires an assigned vlan-id to tag incoming "
                            + "untagged packets. Not processing vlan filters on "
                            + "device {}", deviceId);
                    fail(filt, ObjectiveError.BADPARAMS);
                    return;
                }
            }
            if (pushVlan && popVlan) {
                log.error("Cannot push and pop vlan in the same filtering objective");
                fail(filt, ObjectiveError.BADPARAMS);
                return;
            }
            if (popVlan && vlanIdCriterion.vlanId() == VlanId.NONE) {
                log.error("Cannot pop vlan for untagged packets");
                fail(filt, ObjectiveError.BADPARAMS);
                return;
            }
            if ((pushVlan && pushedVlan == null) && vlanIdCriterion.vlanId() != VlanId.NONE) {
                log.error("No VLAN ID provided for push tag operation");
                fail(filt, ObjectiveError.BADPARAMS);
                return;
            }
        }

        if (ethCriterion == null) {
            log.debug("filtering objective missing dstMac, cannot program TMAC table");
        } else {
            for (FlowRule tmacRule : processEthDstFilter(ethCriterion,
                                                         vlanIdCriterion,
                                                         filt,
                                                         assignedVlan,
                                                         applicationId)) {
                log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
                          tmacRule, deviceId);
                ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
            }
        }

        if (vlanIdCriterion == null) {
            log.debug("filtering objective missing VLAN ID criterion, "
                    + "cannot program VLAN Table");
        } else {
            for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion,
                                                         filt,
                                                         assignedVlan, modifiedVlan, pushedVlan,
                                                         pushVlan, popVlan,
                                                         applicationId)) {
                log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
                          vlanRule, deviceId);
                ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
            }
        }

        // apply filtering flow rules
        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
            @Override
            public void onSuccess(FlowRuleOperations ops) {
                pass(filt);
                log.debug("Provisioned tables in {} with fitering "
                        + "rules", deviceId);
            }

            @Override
            public void onError(FlowRuleOperations ops) {
                fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
                log.warn("Failed to provision tables in {} with "
                        + "fitering rules", deviceId);
            }
        }));
    }

    protected void setTableMissEntries() {
        // set all table-miss-entries
        populateTableMissEntry(vlanTableId, true, false, false, -1);
        populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId);
        populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId);
        populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
        populateTableMissEntry(dstMacTableId, false, false, true, aclTableId);
        populateTableMissEntry(aclTableId, false, false, false, -1);
    }

    protected void populateTableMissEntry(int tableToAdd,
                                          boolean toControllerNow,
                                          boolean toControllerWrite,
                                          boolean toTable, int tableToSend) {
        TrafficSelector selector = DefaultTrafficSelector.builder().build();
        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();

        if (toControllerNow) {
            tBuilder.setOutput(PortNumber.CONTROLLER);
        }

        if (toControllerWrite) {
            tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
        }

        if (toTable) {
            tBuilder.transition(tableToSend);
        }

        FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
                .withSelector(selector).withTreatment(tBuilder.build())
                .withPriority(0).fromApp(appId).makePermanent()
                .forTable(tableToAdd).build();

        flowRuleService.applyFlowRules(flow);
    }

    private void pass(Objective obj) {
        obj.context().ifPresent(context -> context.onSuccess(obj));
    }

    protected void fail(Objective obj, ObjectiveError error) {
        obj.context().ifPresent(context -> context.onError(obj, error));
    }

    private class InnerGroupListener implements GroupListener {
        @Override
        public void event(GroupEvent event) {
            if (event.type() == GroupEvent.Type.GROUP_ADDED) {
                log.trace("InnerGroupListener: Group ADDED "
                        + "event received in device {}", deviceId);
                GroupKey key = event.subject().appCookie();

                NextObjective obj = pendingGroups.getIfPresent(key);
                if (obj != null) {
                    log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
                              deviceId, event.subject().id(), obj.id());
                    flowObjectiveStore
                            .putNextGroup(obj.id(),
                                          new SpringOpenGroup(key, null));
                    pass(obj);
                    pendingGroups.invalidate(key);
                }
            } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
                log.warn("InnerGroupListener: Group ADD "
                        + "failed event received in device {}", deviceId);
            }
        }
    }

    private void verifyPendingGroupLater() {
        GROUP_CHECKER.schedule(new GroupChecker(), CHECK_DELAY, TimeUnit.MILLISECONDS);
    }

    private class GroupChecker implements Runnable {

        @Override
        public void run() {
            Set<GroupKey> keys = pendingGroups
                    .asMap()
                    .keySet()
                    .stream()
                    .filter(key -> groupService.getGroup(deviceId, key) != null)
                    .collect(Collectors.toSet());

            keys.forEach(key -> {
                NextObjective obj = pendingGroups
                        .getIfPresent(key);
                if (obj == null) {
                    return;
                }
                log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
                        deviceId,
                        groupService.getGroup(deviceId, key).id(),
                        obj.id());
                pass(obj);
                pendingGroups.invalidate(key);
                flowObjectiveStore.putNextGroup(
                        obj.id(),
                        new SpringOpenGroup(key, null));
            });

            if (!pendingGroups.asMap().isEmpty()) {
                // Periodically execute only if entry remains in pendingGroups.
                // Iterating pendingGroups trigger cleanUp and expiration,
                // which will eventually empty the pendingGroups.
                verifyPendingGroupLater();
            }
        }
    }

    /**
     * SpringOpenGroup can either serve as storage for a GroupKey which can be
     * used to fetch the group from the Group Service, or it can be serve as storage
     * for Traffic Treatments which can be used as flow actions. In the latter
     * case, we refer to this as a dummy group.
     *
     */
    protected class SpringOpenGroup implements NextGroup {
        private final boolean dummy;
        private final GroupKey key;
        private final TrafficTreatment treatment;

        /**
         * Storage for a GroupKey or a TrafficTreatment. One of the params
         * to this constructor must be null.
         * @param key represents a GroupKey
         * @param treatment represents flow actions in a dummy group
         */
        public SpringOpenGroup(GroupKey key, TrafficTreatment treatment) {
            if (key == null) {
                this.key = new DefaultGroupKey(new byte[]{0});
                this.treatment = treatment;
                this.dummy = true;
            } else {
                this.key = key;
                this.treatment = DefaultTrafficTreatment.builder().build();
                this.dummy = false;
            }
        }

        public GroupKey key() {
            return key;
        }

        public boolean dummy() {
            return dummy;
        }

        public TrafficTreatment treatment() {
            return treatment;
        }

        @Override
        public byte[] data() {
            return appKryo.serialize(this);
        }

    }

    @Override
    public List<String> getNextMappings(NextGroup nextGroup) {
        // TODO Implementation deferred to vendor
        return null;
    }
}


text:
.. Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied.  See the License for the
   specific language governing permissions and limitations
   under the License.

dropDatabase
============

The sub task for dropping the target database. Note that this is only supported on some database
platforms. See :doc:`here <database-support>` for details on which platforms support this.

This sub task does not require schema files. Therefore the ``fileset`` subelement and
the ``schemaFile`` attributes can be omitted.

Attributes
----------

``failOnError``
    :Required: no
    :Allowed: ``true``, ``false``
    :Default: ``true``
    :Meaning: Specifies whether the execution shall stop if an error has occurred while the task runs.


text:
if(IN.to_number && IN.sms_param) {
	service_shared.sms(CONFIG.app_key, CONFIG.sms_free_sign_name, IN.sms_param, IN.to_number, CONFIG.sms_template_code, CONFIG.secret, CONFIG.proxy, function(err, response) {
		if(err) {
			sendERR(err);
		} else {
			sendOUT({"out": {
				status:true,
				detail:response.body
			}});
		}
	});
}


text:
package com.mcb;

import com.ning.http.client.AsyncHttpClient;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest
    extends TestCase
{
    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest( String testName )
    {
        super( testName );
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite()
    {
        return new TestSuite( AppTest.class );
    }

    /**
     * Rigourous Test :-)
     */
    public void testApp()
    {
//        GuiceMain.main(null);
        AsyncHttpClient client = new AsyncHttpClient();

        assertTrue( true );
    }
}


text:
<!doctype html>

		<meta charset="utf-8">
		<title>Bluemix Guide</title>
		<link rel="stylesheet" href="stylesheets/base.css">
		<link rel="icon" href="images/bluemix-icon.png">

To-Do App

                        <input id="new-todo" placeholder="Loading..." autofocus>

            <input id="toggle-all" type="checkbox">
            Mark all as complete

Guide Part 1
To-Do's are saved to browser memory

Guide Part 2
To-Do's are saved to Cloudant Database

Guide Part 3
To-Do's are saved to Cloudant Database + Watson Services are added to enhance the app


text:
import React, {Component} from 'react'
import PropTypes from 'prop-types'

import Icon from 'react-fa'

import e from 'gEngine/engine'

import './members.css'
import {MemberAddForm} from '../shared/MemberAddForm/index.js'

export class MembersTab extends Component {
  state = {
    indexTabOpen: this.props.startOnIndexTab
  }

  render() {
    const {members, memberships, invitations, admin_id, onRemove, addUser, httpRequests, meIsAdmin, organizationId} = this.props
    const unjoinedInvitees = invitations.filter(i => !_.some(memberships, m => m.invitation_id === i.id))
    const onChangeSubTab = () => {this.setState({indexTabOpen: !this.state.indexTabOpen})}
    return (

        {this.state.indexTabOpen &&
          <MembersIndexSubTab {...{members, invitations: unjoinedInvitees, admin_id, onRemove, onChangeSubTab, meIsAdmin}}/>
        }
        {!this.state.indexTabOpen &&
          <MembersAddSubTab {...{organizationId, onChangeSubTab}}/>
        }

    )
  }
}

const MembersIndexSubTab = ({members, invitations, admin_id, onChangeSubTab, onRemove, meIsAdmin}) => (

      {meIsAdmin &&

          Add Members

      }

          {_.map(members, m => (
              <Member
                key={m.id}
                user={m}
                isAdmin={admin_id === m.id}
                onRemove={() => {onRemove(m)}}
                meIsAdmin={meIsAdmin}
              />
            )
          )}
          {meIsAdmin && _.map(invitations, i => <Invitee key={i.id} email={i.email} /> )}

)

const Invitee = ({email}) => (

<Icon name='envelope'/>

{email}

invited

)

const Member = ({user, isAdmin, onRemove, meIsAdmin}) => (

    {meIsAdmin &&

          {user.name}

          {isAdmin ? 'Admin' : 'Editor'}

joined

          {user.membershipId && !isAdmin &&
            <button className='ui circular button small remove' onClick={onRemove}>

            </button>
          }

    }
    {!meIsAdmin &&

          {user.name}

    }

)

const MembersAddSubTab = ({organizationId, onChangeSubTab}) => (

        <Icon name='chevron-left'/> Member List

 Invite New Members

 Members have viewing & editing access to all organization models.
 If you are on a plan, your pricing will be adjusted within 24 hours.

      <MemberAddForm organizationId={organizationId}/>

)


text:
package eu.ydp.empiria.player.client.controller.extensions.types;

import com.google.gwt.core.client.JavaScriptObject;

public interface PlayerJsObjectModifierExtension {

    public void setPlayerJsObject(JavaScriptObject playerJsObject);
}