using System;
using enum_thorough_typesafeNamespace;

public class runme {
  static void Main() {
    {
      // Anonymous enums
      int i = enum_thorough_typesafe.AnonEnum1;
      if (enum_thorough_typesafe.ReallyAnInteger != 200) throw new Exception("Test Anon 1 failed");
      i += enum_thorough_typesafe.AnonSpaceEnum1;
      i += AnonStruct.AnonStructEnum1;
    }
    {
      colour red = colour.red;
      enum_thorough_typesafe.colourTest1(red);
      enum_thorough_typesafe.colourTest2(red);
      enum_thorough_typesafe.colourTest3(red);
      enum_thorough_typesafe.colourTest4(red);
      enum_thorough_typesafe.myColour = red;
    }
    {
      SpeedClass s = new SpeedClass();
      SpeedClass.speed speed = SpeedClass.speed.slow;
      if (s.speedTest1(speed) != speed) throw new Exception("speedTest 1 failed");
      if (s.speedTest2(speed) != speed) throw new Exception("speedTest 2 failed");
      if (s.speedTest3(speed) != speed) throw new Exception("speedTest 3 failed");
      if (s.speedTest4(speed) != speed) throw new Exception("speedTest 4 failed");
      if (s.speedTest5(speed) != speed) throw new Exception("speedTest 5 failed");
      if (s.speedTest6(speed) != speed) throw new Exception("speedTest 6 failed");
      if (s.speedTest7(speed) != speed) throw new Exception("speedTest 7 failed");
      if (s.speedTest8(speed) != speed) throw new Exception("speedTest 8 failed");

      if (enum_thorough_typesafe.speedTest1(speed) != speed) throw new Exception("speedTest Global 1 failed");
      if (enum_thorough_typesafe.speedTest2(speed) != speed) throw new Exception("speedTest Global 2 failed");
      if (enum_thorough_typesafe.speedTest3(speed) != speed) throw new Exception("speedTest Global 3 failed");
      if (enum_thorough_typesafe.speedTest4(speed) != speed) throw new Exception("speedTest Global 4 failed");
      if (enum_thorough_typesafe.speedTest5(speed) != speed) throw new Exception("speedTest Global 5 failed");
    }
    {
      SpeedClass s = new SpeedClass();
      SpeedClass.speed slow = SpeedClass.speed.slow;
      SpeedClass.speed lightning = SpeedClass.speed.lightning;

      if (s.mySpeedtd1 != slow) throw new Exception("mySpeedtd1 1 failed");
      if (s.mySpeedtd1.swigValue != 10) throw new Exception("mySpeedtd1 2 failed");

      s.mySpeedtd1 = lightning;
      if (s.mySpeedtd1 != lightning) throw new Exception("mySpeedtd1 3 failed");
      if (s.mySpeedtd1.swigValue != 31) throw new Exception("mySpeedtd1 4 failed");
    }
    {
      if (enum_thorough_typesafe.namedanonTest1(namedanon.NamedAnon2) != namedanon.NamedAnon2) throw new Exception("namedanonTest 1 failed");
    }
    {
      twonames val = twonames.TwoNames2;
      if (enum_thorough_typesafe.twonamesTest1(val) != val) throw new Exception("twonamesTest 1 failed");
      if (enum_thorough_typesafe.twonamesTest2(val) != val) throw new Exception("twonamesTest 2 failed");
      if (enum_thorough_typesafe.twonamesTest3(val) != val) throw new Exception("twonamesTest 3 failed");
    }
    {
      TwoNamesStruct t = new TwoNamesStruct();
      TwoNamesStruct.twonames val = TwoNamesStruct.twonames.TwoNamesStruct1;
      if (t.twonamesTest1(val) != val) throw new Exception("twonamesTest 1 failed");
      if (t.twonamesTest2(val) != val) throw new Exception("twonamesTest 2 failed");
      if (t.twonamesTest3(val) != val) throw new Exception("twonamesTest 3 failed");
    }
    {
      namedanonspace val = namedanonspace.NamedAnonSpace2;
      if (enum_thorough_typesafe.namedanonspaceTest1(val) != val) throw new Exception("namedanonspaceTest 1 failed");
      if (enum_thorough_typesafe.namedanonspaceTest2(val) != val) throw new Exception("namedanonspaceTest 2 failed");
      if (enum_thorough_typesafe.namedanonspaceTest3(val) != val) throw new Exception("namedanonspaceTest 3 failed");
      if (enum_thorough_typesafe.namedanonspaceTest4(val) != val) throw new Exception("namedanonspaceTest 4 failed");
    }
    {
      TemplateClassInt t = new TemplateClassInt();
      TemplateClassInt.scientists galileo = TemplateClassInt.scientists.galileo;

      if (t.scientistsTest1(galileo) != galileo) throw new Exception("scientistsTest 1 failed");
      if (t.scientistsTest2(galileo) != galileo) throw new Exception("scientistsTest 2 failed");
      if (t.scientistsTest3(galileo) != galileo) throw new Exception("scientistsTest 3 failed");
      if (t.scientistsTest4(galileo) != galileo) throw new Exception("scientistsTest 4 failed");
      if (t.scientistsTest5(galileo) != galileo) throw new Exception("scientistsTest 5 failed");
      if (t.scientistsTest6(galileo) != galileo) throw new Exception("scientistsTest 6 failed");
      if (t.scientistsTest7(galileo) != galileo) throw new Exception("scientistsTest 7 failed");
      if (t.scientistsTest8(galileo) != galileo) throw new Exception("scientistsTest 8 failed");
      if (t.scientistsTest9(galileo) != galileo) throw new Exception("scientistsTest 9 failed");
//      if (t.scientistsTestA(galileo) != galileo) throw new Exception("scientistsTest A failed");
      if (t.scientistsTestB(galileo) != galileo) throw new Exception("scientistsTest B failed");
//      if (t.scientistsTestC(galileo) != galileo) throw new Exception("scientistsTest C failed");
      if (t.scientistsTestD(galileo) != galileo) throw new Exception("scientistsTest D failed");
      if (t.scientistsTestE(galileo) != galileo) throw new Exception("scientistsTest E failed");
      if (t.scientistsTestF(galileo) != galileo) throw new Exception("scientistsTest F failed");
      if (t.scientistsTestG(galileo) != galileo) throw new Exception("scientistsTest G failed");
      if (t.scientistsTestH(galileo) != galileo) throw new Exception("scientistsTest H failed");
      if (t.scientistsTestI(galileo) != galileo) throw new Exception("scientistsTest I failed");
      if (t.scientistsTestJ(galileo) != galileo) throw new Exception("scientistsTest J failed");

      if (enum_thorough_typesafe.scientistsTest1(galileo) != galileo) throw new Exception("scientistsTest Global 1 failed");
      if (enum_thorough_typesafe.scientistsTest2(galileo) != galileo) throw new Exception("scientistsTest Global 2 failed");
      if (enum_thorough_typesafe.scientistsTest3(galileo) != galileo) throw new Exception("scientistsTest Global 3 failed");
      if (enum_thorough_typesafe.scientistsTest4(galileo) != galileo) throw new Exception("scientistsTest Global 4 failed");
      if (enum_thorough_typesafe.scientistsTest5(galileo) != galileo) throw new Exception("scientistsTest Global 5 failed");
      if (enum_thorough_typesafe.scientistsTest6(galileo) != galileo) throw new Exception("scientistsTest Global 6 failed");
      if (enum_thorough_typesafe.scientistsTest7(galileo) != galileo) throw new Exception("scientistsTest Global 7 failed");
      if (enum_thorough_typesafe.scientistsTest8(galileo) != galileo) throw new Exception("scientistsTest Global 8 failed");
    }
    {
      TClassInt t = new TClassInt();
      TClassInt.scientists bell = TClassInt.scientists.bell;
      TemplateClassInt.scientists galileo = TemplateClassInt.scientists.galileo;
      if (t.scientistsNameTest1(bell) != bell) throw new Exception("scientistsNameTest 1 failed");
      if (t.scientistsNameTest2(bell) != bell) throw new Exception("scientistsNameTest 2 failed");
      if (t.scientistsNameTest3(bell) != bell) throw new Exception("scientistsNameTest 3 failed");
      if (t.scientistsNameTest4(bell) != bell) throw new Exception("scientistsNameTest 4 failed");
      if (t.scientistsNameTest5(bell) != bell) throw new Exception("scientistsNameTest 5 failed");
      if (t.scientistsNameTest6(bell) != bell) throw new Exception("scientistsNameTest 6 failed");
      if (t.scientistsNameTest7(bell) != bell) throw new Exception("scientistsNameTest 7 failed");
      if (t.scientistsNameTest8(bell) != bell) throw new Exception("scientistsNameTest 8 failed");
      if (t.scientistsNameTest9(bell) != bell) throw new Exception("scientistsNameTest 9 failed");
//      if (t.scientistsNameTestA(bell) != bell) throw new Exception("scientistsNameTest A failed");
      if (t.scientistsNameTestB(bell) != bell) throw new Exception("scientistsNameTest B failed");
//      if (t.scientistsNameTestC(bell) != bell) throw new Exception("scientistsNameTest C failed");
      if (t.scientistsNameTestD(bell) != bell) throw new Exception("scientistsNameTest D failed");
      if (t.scientistsNameTestE(bell) != bell) throw new Exception("scientistsNameTest E failed");
      if (t.scientistsNameTestF(bell) != bell) throw new Exception("scientistsNameTest F failed");
      if (t.scientistsNameTestG(bell) != bell) throw new Exception("scientistsNameTest G failed");
      if (t.scientistsNameTestH(bell) != bell) throw new Exception("scientistsNameTest H failed");
      if (t.scientistsNameTestI(bell) != bell) throw new Exception("scientistsNameTest I failed");

      if (t.scientistsNameSpaceTest1(bell) != bell) throw new Exception("scientistsNameSpaceTest 1 failed");
      if (t.scientistsNameSpaceTest2(bell) != bell) throw new Exception("scientistsNameSpaceTest 2 failed");
      if (t.scientistsNameSpaceTest3(bell) != bell) throw new Exception("scientistsNameSpaceTest 3 failed");
      if (t.scientistsNameSpaceTest4(bell) != bell) throw new Exception("scientistsNameSpaceTest 4 failed");
      if (t.scientistsNameSpaceTest5(bell) != bell) throw new Exception("scientistsNameSpaceTest 5 failed");
      if (t.scientistsNameSpaceTest6(bell) != bell) throw new Exception("scientistsNameSpaceTest 6 failed");
      if (t.scientistsNameSpaceTest7(bell) != bell) throw new Exception("scientistsNameSpaceTest 7 failed");

      if (t.scientistsOtherTest1(galileo) != galileo) throw new Exception("scientistsOtherTest 1 failed");
      if (t.scientistsOtherTest2(galileo) != galileo) throw new Exception("scientistsOtherTest 2 failed");
      if (t.scientistsOtherTest3(galileo) != galileo) throw new Exception("scientistsOtherTest 3 failed");
      if (t.scientistsOtherTest4(galileo) != galileo) throw new Exception("scientistsOtherTest 4 failed");
      if (t.scientistsOtherTest5(galileo) != galileo) throw new Exception("scientistsOtherTest 5 failed");
      if (t.scientistsOtherTest6(galileo) != galileo) throw new Exception("scientistsOtherTest 6 failed");
      if (t.scientistsOtherTest7(galileo) != galileo) throw new Exception("scientistsOtherTest 7 failed");

      if (enum_thorough_typesafe.scientistsNameTest1(bell) != bell) throw new Exception("scientistsNameTest Global 1 failed");
      if (enum_thorough_typesafe.scientistsNameTest2(bell) != bell) throw new Exception("scientistsNameTest Global 2 failed");
      if (enum_thorough_typesafe.scientistsNameTest3(bell) != bell) throw new Exception("scientistsNameTest Global 3 failed");
      if (enum_thorough_typesafe.scientistsNameTest4(bell) != bell) throw new Exception("scientistsNameTest Global 4 failed");
      if (enum_thorough_typesafe.scientistsNameTest5(bell) != bell) throw new Exception("scientistsNameTest Global 5 failed");
      if (enum_thorough_typesafe.scientistsNameTest6(bell) != bell) throw new Exception("scientistsNameTest Global 6 failed");
      if (enum_thorough_typesafe.scientistsNameTest7(bell) != bell) throw new Exception("scientistsNameTest Global 7 failed");

      if (enum_thorough_typesafe.scientistsNameSpaceTest1(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 1 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest2(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 2 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest3(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 3 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest4(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 4 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest5(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 5 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest6(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 6 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest7(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 7 failed");

      if (enum_thorough_typesafe.scientistsNameSpaceTest8(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 8 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTest9(bell) != bell) throw new Exception("scientistsNameSpaceTest Global 9 failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestA(bell) != bell) throw new Exception("scientistsNameSpaceTest Global A failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestB(bell) != bell) throw new Exception("scientistsNameSpaceTest Global B failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestC(bell) != bell) throw new Exception("scientistsNameSpaceTest Global C failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestD(bell) != bell) throw new Exception("scientistsNameSpaceTest Global D failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestE(bell) != bell) throw new Exception("scientistsNameSpaceTest Global E failed");

      if (enum_thorough_typesafe.scientistsNameSpaceTestF(bell) != bell) throw new Exception("scientistsNameSpaceTest Global F failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestG(bell) != bell) throw new Exception("scientistsNameSpaceTest Global G failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestH(bell) != bell) throw new Exception("scientistsNameSpaceTest Global H failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestI(bell) != bell) throw new Exception("scientistsNameSpaceTest Global I failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestJ(bell) != bell) throw new Exception("scientistsNameSpaceTest Global J failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestK(bell) != bell) throw new Exception("scientistsNameSpaceTest Global K failed");
      if (enum_thorough_typesafe.scientistsNameSpaceTestL(bell) != bell) throw new Exception("scientistsNameSpaceTest Global L failed");
    }
    {
      newname val = newname.argh;
      if (enum_thorough_typesafe.renameTest1(val) != val) throw new Exception("renameTest Global 1 failed");
      if (enum_thorough_typesafe.renameTest2(val) != val) throw new Exception("renameTest Global 2 failed");
    }
    {
      NewNameStruct n = new NewNameStruct();
      if (n.renameTest1(NewNameStruct.enumeration.bang) != NewNameStruct.enumeration.bang) throw new Exception("renameTest 1 failed");
      if (n.renameTest2(NewNameStruct.enumeration.bang) != NewNameStruct.enumeration.bang) throw new Exception("renameTest 2 failed");
      if (n.renameTest3(NewNameStruct.simplerenamed.simple1) != NewNameStruct.simplerenamed.simple1) throw new Exception("renameTest 3 failed");
      if (n.renameTest4(NewNameStruct.doublenamerenamed.doublename1) != NewNameStruct.doublenamerenamed.doublename1) throw new Exception("renameTest 4 failed");
      if (n.renameTest5(NewNameStruct.doublenamerenamed.doublename1) != NewNameStruct.doublenamerenamed.doublename1) throw new Exception("renameTest 5 failed");
      if (n.renameTest6(NewNameStruct.singlenamerenamed.singlename1) != NewNameStruct.singlenamerenamed.singlename1) throw new Exception("renameTest 6 failed");
    }
    {
      if (enum_thorough_typesafe.renameTest3(NewNameStruct.enumeration.bang) != NewNameStruct.enumeration.bang) throw new Exception("renameTest Global 3 failed");
      if (enum_thorough_typesafe.renameTest4(NewNameStruct.simplerenamed.simple1) != NewNameStruct.simplerenamed.simple1) throw new Exception("renameTest Global 4 failed");
      if (enum_thorough_typesafe.renameTest5(NewNameStruct.doublenamerenamed.doublename1) != NewNameStruct.doublenamerenamed.doublename1) throw new Exception("renameTest Global 5 failed");
      if (enum_thorough_typesafe.renameTest6(NewNameStruct.doublenamerenamed.doublename1) != NewNameStruct.doublenamerenamed.doublename1) throw new Exception("renameTest Global 6 failed");
      if (enum_thorough_typesafe.renameTest7(NewNameStruct.singlenamerenamed.singlename1) != NewNameStruct.singlenamerenamed.singlename1) throw new Exception("renameTest Global 7 failed");
    }
    {
      TreesClass t = new TreesClass();
      TreesClass.trees pine = TreesClass.trees.pine;

      if (t.treesTest1(pine) != pine) throw new Exception("treesTest 1 failed");
      if (t.treesTest2(pine) != pine) throw new Exception("treesTest 2 failed");
      if (t.treesTest3(pine) != pine) throw new Exception("treesTest 3 failed");
      if (t.treesTest4(pine) != pine) throw new Exception("treesTest 4 failed");
      if (t.treesTest5(pine) != pine) throw new Exception("treesTest 5 failed");
      if (t.treesTest6(pine) != pine) throw new Exception("treesTest 6 failed");
      if (t.treesTest7(pine) != pine) throw new Exception("treesTest 7 failed");
      if (t.treesTest8(pine) != pine) throw new Exception("treesTest 8 failed");
      if (t.treesTest9(pine) != pine) throw new Exception("treesTest 9 failed");
      if (t.treesTestA(pine) != pine) throw new Exception("treesTest A failed");
      if (t.treesTestB(pine) != pine) throw new Exception("treesTest B failed");
      if (t.treesTestC(pine) != pine) throw new Exception("treesTest C failed");
      if (t.treesTestD(pine) != pine) throw new Exception("treesTest D failed");
      if (t.treesTestE(pine) != pine) throw new Exception("treesTest E failed");
      if (t.treesTestF(pine) != pine) throw new Exception("treesTest F failed");
      if (t.treesTestG(pine) != pine) throw new Exception("treesTest G failed");
      if (t.treesTestH(pine) != pine) throw new Exception("treesTest H failed");
      if (t.treesTestI(pine) != pine) throw new Exception("treesTest I failed");
      if (t.treesTestJ(pine) != pine) throw new Exception("treesTest J failed");
      if (t.treesTestK(pine) != pine) throw new Exception("treesTest K failed");
      if (t.treesTestL(pine) != pine) throw new Exception("treesTest L failed");
      if (t.treesTestM(pine) != pine) throw new Exception("treesTest M failed");
      if (t.treesTestN(pine) != pine) throw new Exception("treesTest N failed");
      if (t.treesTestO(pine) != pine) throw new Exception("treesTest O failed");

      if (enum_thorough_typesafe.treesTest1(pine) != pine) throw new Exception("treesTest Global 1 failed");
      if (enum_thorough_typesafe.treesTest2(pine) != pine) throw new Exception("treesTest Global 2 failed");
      if (enum_thorough_typesafe.treesTest3(pine) != pine) throw new Exception("treesTest Global 3 failed");
      if (enum_thorough_typesafe.treesTest4(pine) != pine) throw new Exception("treesTest Global 4 failed");
      if (enum_thorough_typesafe.treesTest5(pine) != pine) throw new Exception("treesTest Global 5 failed");
      if (enum_thorough_typesafe.treesTest6(pine) != pine) throw new Exception("treesTest Global 6 failed");
      if (enum_thorough_typesafe.treesTest7(pine) != pine) throw new Exception("treesTest Global 7 failed");
      if (enum_thorough_typesafe.treesTest8(pine) != pine) throw new Exception("treesTest Global 8 failed");
      if (enum_thorough_typesafe.treesTest9(pine) != pine) throw new Exception("treesTest Global 9 failed");
      if (enum_thorough_typesafe.treesTestA(pine) != pine) throw new Exception("treesTest Global A failed");
      if (enum_thorough_typesafe.treesTestB(pine) != pine) throw new Exception("treesTest Global B failed");
      if (enum_thorough_typesafe.treesTestC(pine) != pine) throw new Exception("treesTest Global C failed");
      if (enum_thorough_typesafe.treesTestD(pine) != pine) throw new Exception("treesTest Global D failed");
      if (enum_thorough_typesafe.treesTestE(pine) != pine) throw new Exception("treesTest Global E failed");
      if (enum_thorough_typesafe.treesTestF(pine) != pine) throw new Exception("treesTest Global F failed");
      if (enum_thorough_typesafe.treesTestG(pine) != pine) throw new Exception("treesTest Global G failed");
      if (enum_thorough_typesafe.treesTestH(pine) != pine) throw new Exception("treesTest Global H failed");
      if (enum_thorough_typesafe.treesTestI(pine) != pine) throw new Exception("treesTest Global I failed");
      if (enum_thorough_typesafe.treesTestJ(pine) != pine) throw new Exception("treesTest Global J failed");
      if (enum_thorough_typesafe.treesTestK(pine) != pine) throw new Exception("treesTest Global K failed");
      if (enum_thorough_typesafe.treesTestL(pine) != pine) throw new Exception("treesTest Global L failed");
      if (enum_thorough_typesafe.treesTestM(pine) != pine) throw new Exception("treesTest Global M failed");
//      if (enum_thorough_typesafe.treesTestN(pine) != pine) throw new Exception("treesTest Global N failed");
      if (enum_thorough_typesafe.treesTestO(pine) != pine) throw new Exception("treesTest Global O failed");
      if (enum_thorough_typesafe.treesTestP(pine) != pine) throw new Exception("treesTest Global P failed");
      if (enum_thorough_typesafe.treesTestQ(pine) != pine) throw new Exception("treesTest Global Q failed");
      if (enum_thorough_typesafe.treesTestR(pine) != pine) throw new Exception("treesTest Global R failed");
    }
    {
      HairStruct h = new HairStruct();
      HairStruct.hair ginger = HairStruct.hair.ginger;

      if (h.hairTest1(ginger) != ginger) throw new Exception("hairTest 1 failed");
      if (h.hairTest2(ginger) != ginger) throw new Exception("hairTest 2 failed");
      if (h.hairTest3(ginger) != ginger) throw new Exception("hairTest 3 failed");
      if (h.hairTest4(ginger) != ginger) throw new Exception("hairTest 4 failed");
      if (h.hairTest5(ginger) != ginger) throw new Exception("hairTest 5 failed");
      if (h.hairTest6(ginger) != ginger) throw new Exception("hairTest 6 failed");
      if (h.hairTest7(ginger) != ginger) throw new Exception("hairTest 7 failed");
      if (h.hairTest8(ginger) != ginger) throw new Exception("hairTest 8 failed");
      if (h.hairTest9(ginger) != ginger) throw new Exception("hairTest 9 failed");
      if (h.hairTestA(ginger) != ginger) throw new Exception("hairTest A failed");
      if (h.hairTestB(ginger) != ginger) throw new Exception("hairTest B failed");

      colour red = colour.red;
      if (h.colourTest1(red) != red) throw new Exception("colourTest HairStruct 1 failed");
      if (h.colourTest2(red) != red) throw new Exception("colourTest HairStruct 2 failed");
      if (h.namedanonTest1(namedanon.NamedAnon2) != namedanon.NamedAnon2) throw new Exception("namedanonTest HairStruct 1 failed");
      if (h.namedanonspaceTest1(namedanonspace.NamedAnonSpace2) != namedanonspace.NamedAnonSpace2) throw new Exception("namedanonspaceTest HairStruct 1 failed");

      TreesClass.trees fir = TreesClass.trees.fir;
      if (h.treesGlobalTest1(fir) != fir) throw new Exception("treesGlobalTest1 HairStruct 1 failed");
      if (h.treesGlobalTest2(fir) != fir) throw new Exception("treesGlobalTest1 HairStruct 2 failed");
      if (h.treesGlobalTest3(fir) != fir) throw new Exception("treesGlobalTest1 HairStruct 3 failed");
      if (h.treesGlobalTest4(fir) != fir) throw new Exception("treesGlobalTest1 HairStruct 4 failed");
    }
    {
      HairStruct.hair blonde = HairStruct.hair.blonde;
      if (enum_thorough_typesafe.hairTest1(blonde) != blonde) throw new Exception("hairTest Global 1 failed");
      if (enum_thorough_typesafe.hairTest2(blonde) != blonde) throw new Exception("hairTest Global 2 failed");
      if (enum_thorough_typesafe.hairTest3(blonde) != blonde) throw new Exception("hairTest Global 3 failed");
      if (enum_thorough_typesafe.hairTest4(blonde) != blonde) throw new Exception("hairTest Global 4 failed");
      if (enum_thorough_typesafe.hairTest5(blonde) != blonde) throw new Exception("hairTest Global 5 failed");
      if (enum_thorough_typesafe.hairTest6(blonde) != blonde) throw new Exception("hairTest Global 6 failed");
      if (enum_thorough_typesafe.hairTest7(blonde) != blonde) throw new Exception("hairTest Global 7 failed");
      if (enum_thorough_typesafe.hairTest8(blonde) != blonde) throw new Exception("hairTest Global 8 failed");
      if (enum_thorough_typesafe.hairTest9(blonde) != blonde) throw new Exception("hairTest Global 9 failed");
      if (enum_thorough_typesafe.hairTestA(blonde) != blonde) throw new Exception("hairTest Global A failed");
      if (enum_thorough_typesafe.hairTestB(blonde) != blonde) throw new Exception("hairTest Global B failed");
      if (enum_thorough_typesafe.hairTestC(blonde) != blonde) throw new Exception("hairTest Global C failed");

      if (enum_thorough_typesafe.hairTestA1(blonde) != blonde) throw new Exception("hairTest Global A1 failed");
      if (enum_thorough_typesafe.hairTestA2(blonde) != blonde) throw new Exception("hairTest Global A2 failed");
      if (enum_thorough_typesafe.hairTestA3(blonde) != blonde) throw new Exception("hairTest Global A3 failed");
      if (enum_thorough_typesafe.hairTestA4(blonde) != blonde) throw new Exception("hairTest Global A4 failed");
      if (enum_thorough_typesafe.hairTestA5(blonde) != blonde) throw new Exception("hairTest Global A5 failed");
      if (enum_thorough_typesafe.hairTestA6(blonde) != blonde) throw new Exception("hairTest Global A6 failed");
      if (enum_thorough_typesafe.hairTestA7(blonde) != blonde) throw new Exception("hairTest Global A7 failed");
      if (enum_thorough_typesafe.hairTestA8(blonde) != blonde) throw new Exception("hairTest Global A8 failed");
      if (enum_thorough_typesafe.hairTestA9(blonde) != blonde) throw new Exception("hairTest Global A9 failed");
      if (enum_thorough_typesafe.hairTestAA(blonde) != blonde) throw new Exception("hairTest Global AA failed");
      if (enum_thorough_typesafe.hairTestAB(blonde) != blonde) throw new Exception("hairTest Global AB failed");
      if (enum_thorough_typesafe.hairTestAC(blonde) != blonde) throw new Exception("hairTest Global AC failed");

      if (enum_thorough_typesafe.hairTestB1(blonde) != blonde) throw new Exception("hairTest Global B1 failed");
      if (enum_thorough_typesafe.hairTestB2(blonde) != blonde) throw new Exception("hairTest Global B2 failed");
      if (enum_thorough_typesafe.hairTestB3(blonde) != blonde) throw new Exception("hairTest Global B3 failed");
      if (enum_thorough_typesafe.hairTestB4(blonde) != blonde) throw new Exception("hairTest Global B4 failed");
      if (enum_thorough_typesafe.hairTestB5(blonde) != blonde) throw new Exception("hairTest Global B5 failed");
      if (enum_thorough_typesafe.hairTestB6(blonde) != blonde) throw new Exception("hairTest Global B6 failed");
      if (enum_thorough_typesafe.hairTestB7(blonde) != blonde) throw new Exception("hairTest Global B7 failed");
      if (enum_thorough_typesafe.hairTestB8(blonde) != blonde) throw new Exception("hairTest Global B8 failed");
      if (enum_thorough_typesafe.hairTestB9(blonde) != blonde) throw new Exception("hairTest Global B9 failed");
      if (enum_thorough_typesafe.hairTestBA(blonde) != blonde) throw new Exception("hairTest Global BA failed");
      if (enum_thorough_typesafe.hairTestBB(blonde) != blonde) throw new Exception("hairTest Global BB failed");
      if (enum_thorough_typesafe.hairTestBC(blonde) != blonde) throw new Exception("hairTest Global BC failed");

      if (enum_thorough_typesafe.hairTestC1(blonde) != blonde) throw new Exception("hairTest Global C1 failed");
      if (enum_thorough_typesafe.hairTestC2(blonde) != blonde) throw new Exception("hairTest Global C2 failed");
      if (enum_thorough_typesafe.hairTestC3(blonde) != blonde) throw new Exception("hairTest Global C3 failed");
      if (enum_thorough_typesafe.hairTestC4(blonde) != blonde) throw new Exception("hairTest Global C4 failed");
      if (enum_thorough_typesafe.hairTestC5(blonde) != blonde) throw new Exception("hairTest Global C5 failed");
      if (enum_thorough_typesafe.hairTestC6(blonde) != blonde) throw new Exception("hairTest Global C6 failed");
      if (enum_thorough_typesafe.hairTestC7(blonde) != blonde) throw new Exception("hairTest Global C7 failed");
      if (enum_thorough_typesafe.hairTestC8(blonde) != blonde) throw new Exception("hairTest Global C8 failed");
      if (enum_thorough_typesafe.hairTestC9(blonde) != blonde) throw new Exception("hairTest Global C9 failed");
      if (enum_thorough_typesafe.hairTestCA(blonde) != blonde) throw new Exception("hairTest Global CA failed");
      if (enum_thorough_typesafe.hairTestCB(blonde) != blonde) throw new Exception("hairTest Global CB failed");
      if (enum_thorough_typesafe.hairTestCC(blonde) != blonde) throw new Exception("hairTest Global CC failed");
    }
    {
      FirStruct f = new FirStruct();
      HairStruct.hair blonde = HairStruct.hair.blonde;

      if (f.hairTestFir1(blonde) != blonde) throw new Exception("hairTestFir 1 failed");
      if (f.hairTestFir2(blonde) != blonde) throw new Exception("hairTestFir 2 failed");
      if (f.hairTestFir3(blonde) != blonde) throw new Exception("hairTestFir 3 failed");
      if (f.hairTestFir4(blonde) != blonde) throw new Exception("hairTestFir 4 failed");
      if (f.hairTestFir5(blonde) != blonde) throw new Exception("hairTestFir 5 failed");
      if (f.hairTestFir6(blonde) != blonde) throw new Exception("hairTestFir 6 failed");
      if (f.hairTestFir7(blonde) != blonde) throw new Exception("hairTestFir 7 failed");
      if (f.hairTestFir8(blonde) != blonde) throw new Exception("hairTestFir 8 failed");
      if (f.hairTestFir9(blonde) != blonde) throw new Exception("hairTestFir 9 failed");
      if (f.hairTestFirA(blonde) != blonde) throw new Exception("hairTestFir A failed");
    }
    {
      enum_thorough_typesafe.GlobalInstance = enum_thorough_typesafe.globalinstance2;
      if (enum_thorough_typesafe.GlobalInstance != enum_thorough_typesafe.globalinstance2) throw new Exception("GlobalInstance 1 failed");

      Instances i = new Instances();
      i.MemberInstance = Instances.memberinstance3;
      if (i.MemberInstance != Instances.memberinstance3) throw new Exception("MemberInstance 1 failed");
    }
    // ignore enum item tests start
    {
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_zero).swigValue != 0) throw new Exception("ignoreATest 0 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_three).swigValue != 3) throw new Exception("ignoreATest 3 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_ten).swigValue != 10) throw new Exception("ignoreATest 10 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_eleven).swigValue != 11) throw new Exception("ignoreATest 11 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_thirteen).swigValue != 13) throw new Exception("ignoreATest 13 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_fourteen).swigValue != 14) throw new Exception("ignoreATest 14 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_twenty).swigValue != 20) throw new Exception("ignoreATest 20 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_thirty).swigValue != 30) throw new Exception("ignoreATest 30 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_thirty_two).swigValue != 32) throw new Exception("ignoreATest 32 failed");
      if (enum_thorough_typesafe.ignoreATest(IgnoreTest.IgnoreA.ignoreA_thirty_three).swigValue != 33) throw new Exception("ignoreATest 33 failed");
    }
    {
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_eleven).swigValue != 11) throw new Exception("ignoreBTest 11 failed");
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_twelve).swigValue != 12) throw new Exception("ignoreBTest 12 failed");
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_thirty_one).swigValue != 31) throw new Exception("ignoreBTest 31 failed");
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_thirty_two).swigValue != 32) throw new Exception("ignoreBTest 32 failed");
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_forty_one).swigValue != 41) throw new Exception("ignoreBTest 41 failed");
      if (enum_thorough_typesafe.ignoreBTest(IgnoreTest.IgnoreB.ignoreB_forty_two).swigValue != 42) throw new Exception("ignoreBTest 42 failed");
    }
    {
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_ten).swigValue != 10) throw new Exception("ignoreCTest 10 failed");
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_twelve).swigValue != 12) throw new Exception("ignoreCTest 12 failed");
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_thirty).swigValue != 30) throw new Exception("ignoreCTest 30 failed");
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_thirty_two).swigValue != 32) throw new Exception("ignoreCTest 32 failed");
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_forty).swigValue != 40) throw new Exception("ignoreCTest 40 failed");
      if (enum_thorough_typesafe.ignoreCTest(IgnoreTest.IgnoreC.ignoreC_forty_two).swigValue != 42) throw new Exception("ignoreCTest 42 failed");
    }
    {
      if (enum_thorough_typesafe.ignoreDTest(IgnoreTest.IgnoreD.ignoreD_twenty_one).swigValue != 21) throw new Exception("ignoreDTest 21 failed");
      if (enum_thorough_typesafe.ignoreDTest(IgnoreTest.IgnoreD.ignoreD_twenty_two).swigValue != 22) throw new Exception("ignoreDTest 22 failed");
    }
    {
      if (enum_thorough_typesafe.ignoreETest(IgnoreTest.IgnoreE.ignoreE_zero).swigValue != 0) throw new Exception("ignoreETest 0 failed");
      if (enum_thorough_typesafe.ignoreETest(IgnoreTest.IgnoreE.ignoreE_twenty_one).swigValue != 21) throw new Exception("ignoreETest 21 failed");
      if (enum_thorough_typesafe.ignoreETest(IgnoreTest.IgnoreE.ignoreE_twenty_two).swigValue != 22) throw new Exception("ignoreETest 22 failed");
    }
    // ignore enum item tests end
    {
      if (enum_thorough_typesafe.repeatTest(repeat.one).swigValue != 1) throw new Exception("repeatTest 1 failed");
      if (enum_thorough_typesafe.repeatTest(repeat.initial).swigValue != 1) throw new Exception("repeatTest 2 failed");
      if (enum_thorough_typesafe.repeatTest(repeat.two).swigValue != 2) throw new Exception("repeatTest 3 failed");
      if (enum_thorough_typesafe.repeatTest(repeat.three).swigValue != 3) throw new Exception("repeatTest 4 failed");
      if (enum_thorough_typesafe.repeatTest(repeat.llast).swigValue != 3) throw new Exception("repeatTest 5 failed");
      if (enum_thorough_typesafe.repeatTest(repeat.end).swigValue != 3) throw new Exception("repeatTest 6 failed");
    }
    {
      if (enum_thorough_typesafe.enumWithMacroTest(enumWithMacro.ABCD).swigValue != (('A' << 24) | ('B' << 16) | ('C' << 8) | 'D')) throw new Exception("enumWithMacroTest 1 failed");
      if (enum_thorough_typesafe.enumWithMacroTest(enumWithMacro.ABCD2).swigValue != enum_thorough_typesafe.enumWithMacroTest(enumWithMacro.ABCD).swigValue) throw new Exception("enumWithMacroTest 2 failed");
    }
    // different types
    {
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typeint).swigValue != 10) throw new Exception("differentTypes 1 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typebooltrue).swigValue != 1) throw new Exception("differentTypes 2 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typebooltwo).swigValue != 2) throw new Exception("differentTypes 3 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typeboolfalse).swigValue != 0) throw new Exception("differentTypes 4 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typechar).swigValue != (int)'C') throw new Exception("differentTypes 5 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typedefaultint).swigValue != (int)'D') throw new Exception("differentTypes 6 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typecharcompound).swigValue != (int)'A' + 1) throw new Exception("differentTypes 7 failed");
      if (enum_thorough_typesafe.differentTypesTest(DifferentTypes.typecharcompound2).swigValue != (int)'B' << 2) throw new Exception("differentTypes 8 failed");

      int global_enum = enum_thorough_typesafe.global_typeint;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 10) throw new Exception("global differentTypes 1 failed");
      global_enum = enum_thorough_typesafe.global_typeboolfalse;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 0) throw new Exception("global differentTypes 2 failed");
      global_enum = enum_thorough_typesafe.global_typebooltrue;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 1) throw new Exception("global differentTypes 3 failed");
      global_enum = enum_thorough_typesafe.global_typebooltwo;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 2) throw new Exception("global differentTypes 4 failed");
      global_enum = enum_thorough_typesafe.global_typechar;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 'C') throw new Exception("global differentTypes 5 failed");
      global_enum = enum_thorough_typesafe.global_typedefaultint;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != 'D') throw new Exception("global differentTypes 6 failed");
      global_enum = enum_thorough_typesafe.global_typecharcompound;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != (int)'A' + 1) throw new Exception("global differentTypes 7 failed");
      global_enum = enum_thorough_typesafe.global_typecharcompound2;
      if (enum_thorough_typesafe.globalDifferentTypesTest(global_enum) != (int)'B' << 2) throw new Exception("global differentTypes 8 failed");
    }
  }
}


// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: Render model of associated tracked object
//
//=============================================================================

using Microsoft.MixedReality.Toolkit.OpenVR.Headers;
using Microsoft.MixedReality.Toolkit.Utilities;
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;

namespace Microsoft.MixedReality.Toolkit.OpenVR.Input
{
    /// <summary>
    /// Represents and loads models from the OpenVR APIs. This class is based on the SteamVR_RenderModel class.
    /// </summary>
    [AddComponentMenu("Scripts/MRTK/Providers/OpenVRRenderModel")]
    public class OpenVRRenderModel : MonoBehaviour
    {
        private class RenderModel
        {
            public RenderModel(Mesh mesh, Material material)
            {
                Mesh = mesh;
                Material = material;
            }
            public Mesh Mesh { get; private set; }
            public Material Material { get; private set; }
        }

        private static readonly Hashtable models = new Hashtable();
        private static readonly Hashtable materials = new Hashtable();

        private string renderModelName = string.Empty;

        internal Shader shader = null;

        /// <summary>
        /// Attempts to load or reload a controller model based on the passed in handedness.
        /// </summary>
        /// <param name="handedness">The handedness of the controller model to load.</param>
        /// <returns>True if the controller model was found and loaded. False otherwise.</returns>
        public bool LoadModel(Handedness handedness)
        {
            var system = Headers.OpenVR.System;
            if (system == null)
            {
                return false;
            }

            var error = ETrackedPropertyError.TrackedProp_Success;
            uint index = system.GetTrackedDeviceIndexForControllerRole(handedness == Handedness.Left ? ETrackedControllerRole.LeftHand : ETrackedControllerRole.RightHand);
            var capacity = system.GetStringTrackedDeviceProperty(index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0, ref error);
            if (capacity <= 1)
            {
                Debug.LogError("Failed to get render model name for tracked object " + index);
                return false;
            }

            var buffer = new System.Text.StringBuilder((int)capacity);
            system.GetStringTrackedDeviceProperty(index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);

            var s = buffer.ToString();
            if (renderModelName != s)
            {
                StartCoroutine(SetModelAsync(s));
            }

            return true;
        }

        private IEnumerator SetModelAsync(string newRenderModelName)
        {
            if (string.IsNullOrEmpty(newRenderModelName))
            {
                yield break;
            }

            // Pre-load all render models before asking for the data to create meshes.
            CVRRenderModels renderModels = Headers.OpenVR.RenderModels;
            if (renderModels == null)
            {
                yield break;
            }

            // Gather names of render models to pre-load.
            string[] renderModelNames;

            uint count = renderModels.GetComponentCount(newRenderModelName);
            if (count > 0)
            {
                renderModelNames = new string[count];

                for (int componentIndex = 0; componentIndex < count; componentIndex++)
                {
                    uint capacity = renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, null, 0);
                    if (capacity == 0)
                    {
                        continue;
                    }

                    var componentNameStringBuilder = new System.Text.StringBuilder((int)capacity);
                    if (renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, componentNameStringBuilder, capacity) == 0)
                    {
                        continue;
                    }

                    string componentName = componentNameStringBuilder.ToString();

                    capacity = renderModels.GetComponentRenderModelName(newRenderModelName, componentName, null, 0);
                    if (capacity == 0)
                    {
                        continue;
                    }

                    var nameStringBuilder = new System.Text.StringBuilder((int)capacity);
                    if (renderModels.GetComponentRenderModelName(newRenderModelName, componentName, nameStringBuilder, capacity) == 0)
                    {
                        continue;
                    }

                    var s = nameStringBuilder.ToString();

                    // Only need to pre-load if not already cached.
                    if (!(models[s] is RenderModel model) || model.Mesh == null)
                    {
                        renderModelNames[componentIndex] = s;
                    }
                }
            }
            else
            {
                // Only need to pre-load if not already cached.
                if (!(models[newRenderModelName] is RenderModel model) || model.Mesh == null)
                {
                    renderModelNames = new string[] { newRenderModelName };
                }
                else
                {
                    renderModelNames = System.Array.Empty<string>();
                }
            }

            // Keep trying every 100ms until all components finish loading.
            while (true)
            {
                var loading = false;
                for (int renderModelNameIndex = 0; renderModelNameIndex < renderModelNames.Length; renderModelNameIndex++)
                {
                    if (string.IsNullOrEmpty(renderModelNames[renderModelNameIndex]))
                    {
                        continue;
                    }

                    var pRenderModel = System.IntPtr.Zero;

                    var error = renderModels.LoadRenderModel_Async(renderModelNames[renderModelNameIndex], ref pRenderModel);

                    if (error == EVRRenderModelError.Loading)
                    {
                        loading = true;
                    }
                    else if (error == EVRRenderModelError.None)
                    {
                        // Pre-load textures as well.
                        var renderModel = MarshalRenderModel(pRenderModel);

                        // Check the cache first.
                        var material = materials[renderModel.diffuseTextureId] as Material;
                        if (material == null || material.mainTexture == null)
                        {
                            var pDiffuseTexture = System.IntPtr.Zero;

                            error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);

                            if (error == EVRRenderModelError.Loading)
                            {
                                loading = true;
                            }
                        }
                    }
                }

                if (loading)
                {
                    yield return new WaitForSecondsRealtime(0.1f);
                }
                else
                {
                    break;
                }
            }

            SetModel(newRenderModelName);
            renderModelName = newRenderModelName;
        }

        private bool SetModel(string renderModelName)
        {
            StripMesh(gameObject);

            if (!string.IsNullOrEmpty(renderModelName))
            {
                var model = models[renderModelName] as RenderModel;
                if (model == null || model.Mesh == null)
                {
                    var renderModels = Headers.OpenVR.RenderModels;
                    if (renderModels == null)
                    {
                        return false;
                    }

                    model = LoadRenderModel(renderModels, renderModelName, renderModelName);
                    if (model == null)
                    {
                        return false;
                    }

                    models[renderModelName] = model;
                }

                gameObject.AddComponent<MeshFilter>().mesh = model.Mesh;
                MeshRenderer newRenderer = gameObject.AddComponent<MeshRenderer>();
                newRenderer.sharedMaterial = model.Material;
                return true;
            }

            return false;
        }

        private RenderModel LoadRenderModel(CVRRenderModels renderModels, string renderModelName, string baseName)
        {
            var pRenderModel = System.IntPtr.Zero;

            EVRRenderModelError error;
            while (true)
            {
                error = renderModels.LoadRenderModel_Async(renderModelName, ref pRenderModel);
                if (error != EVRRenderModelError.Loading)
                    break;

                Sleep();
            }

            if (error != EVRRenderModelError.None)
            {
                Debug.LogError(string.Format("Failed to load render model {0} - {1}", renderModelName, error.ToString()));
                return null;
            }

            var renderModel = MarshalRenderModel(pRenderModel);

            var vertices = new Vector3[renderModel.unVertexCount];
            var normals = new Vector3[renderModel.unVertexCount];
            var uv = new Vector2[renderModel.unVertexCount];

            var type = typeof(RenderModel_Vertex_t);
            for (int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
            {
                var ptr = new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
                var vert = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, type);

                vertices[iVert] = new Vector3(vert.vPosition.v0, vert.vPosition.v1, -vert.vPosition.v2);
                normals[iVert] = new Vector3(vert.vNormal.v0, vert.vNormal.v1, -vert.vNormal.v2);
                uv[iVert] = new Vector2(vert.rfTextureCoord0, vert.rfTextureCoord1);
            }

            int indexCount = (int)renderModel.unTriangleCount * 3;
            var indices = new short[indexCount];
            Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);

            var triangles = new int[indexCount];
            for (int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
            {
                triangles[iTri * 3 + 0] = (int)indices[iTri * 3 + 2];
                triangles[iTri * 3 + 1] = (int)indices[iTri * 3 + 1];
                triangles[iTri * 3 + 2] = (int)indices[iTri * 3 + 0];
            }

            var mesh = new Mesh
            {
                vertices = vertices,
                normals = normals,
                uv = uv,
                triangles = triangles
            };

            // Check cache before loading texture.
            var material = materials[renderModel.diffuseTextureId] as Material;
            if (material == null || material.mainTexture == null)
            {
                var pDiffuseTexture = System.IntPtr.Zero;

                while (true)
                {
                    error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
                    if (error != EVRRenderModelError.Loading)
                    {
                        break;
                    }

                    Sleep();
                }

                if (error == EVRRenderModelError.None)
                {
                    var diffuseTexture = MarshalRenderModel_TextureMap(pDiffuseTexture);
                    var texture = new Texture2D(diffuseTexture.unWidth, diffuseTexture.unHeight, TextureFormat.RGBA32, false);
                    if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11)
                    {
                        texture.Apply();
                        System.IntPtr texturePointer = texture.GetNativeTexturePtr();
                        while (true)
                        {
                            error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texturePointer);
                            if (error != EVRRenderModelError.Loading)
                            {
                                break;
                            }

                            Sleep();
                        }
                    }
                    else
                    {
                        var textureMapData = new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4]; // RGBA
                        Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);

                        var colors = new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
                        int iColor = 0;
                        for (int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
                        {
                            for (int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
                            {
                                var r = textureMapData[iColor++];
                                var g = textureMapData[iColor++];
                                var b = textureMapData[iColor++];
                                var a = textureMapData[iColor++];
                                colors[iHeight * diffuseTexture.unWidth + iWidth] = new Color32(r, g, b, a);
                            }
                        }

                        texture.SetPixels32(colors);
                        texture.Apply();
                    }

                    material = new Material(shader != null ? shader : Shader.Find("Mixed Reality Toolkit/Standard"))
                    {
                        mainTexture = texture
                    };

                    materials[renderModel.diffuseTextureId] = material;

                    renderModels.FreeTexture(pDiffuseTexture);
                }
                else
                {
                    Debug.Log("Failed to load render model texture for render model " + renderModelName + ". Error: " + error.ToString());
                }
            }

            // Delay freeing when we can since we'll often get multiple requests for the same model right
            // after another (e.g. two controllers or two base stations).
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                renderModels.FreeRenderModel(pRenderModel);
            }
            else
#endif
            {
                StartCoroutine(FreeRenderModel(pRenderModel));
            }

            return new RenderModel(mesh, material);
        }

        private IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
        {
            yield return new WaitForSeconds(1.0f);
            Headers.OpenVR.RenderModels.FreeRenderModel(pRenderModel);
        }

        private void StripMesh(GameObject go)
        {
            var meshRenderer = go.GetComponent<MeshRenderer>();
            if (meshRenderer != null)
            {
                DestroyImmediate(meshRenderer);
            }

            var meshFilter = go.GetComponent<MeshFilter>();
            if (meshFilter != null)
            {
                DestroyImmediate(meshFilter);
            }
        }

        private static void Sleep()
        {
#if !UNITY_WSA
            System.Threading.Thread.Sleep(1);
#endif
        }

        private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
        {
#if !ENABLE_DOTNET
            if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
                (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
            {
                var packedModel = (RenderModel_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t_Packed));
                RenderModel_t model = new RenderModel_t();
                packedModel.Unpack(ref model);
                return model;
            }
            else
#endif
            {
                return (RenderModel_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t));
            }
        }

        private RenderModel_TextureMap_t MarshalRenderModel_TextureMap(System.IntPtr pRenderModel)
        {
#if !ENABLE_DOTNET
            if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
                (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
            {
                var packedModel = (RenderModel_TextureMap_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t_Packed));
                RenderModel_TextureMap_t model = new RenderModel_TextureMap_t();
                packedModel.Unpack(ref model);
                return model;
            }
            else
#endif
            {
                return (RenderModel_TextureMap_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t));
            }
        }
    }
}


Page({
  data: {
    status: 'loading'
  },
  handlerNoMore() {
    this.setData({
      status: 'nomore'
    });
  },
  handlerEmpty() {
    this.setData({
      status: 'empty'
    });
  }
})


// Copyright (c) 2015-2016, Robert Escriva, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Consus nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// C
#include <stdio.h>

// POSIX
#include <signal.h>

// Google Log
#include <glog/logging.h>

// po6
#include <po6/io/fd.h>
#include <po6/time.h>

// e
#include <e/daemon.h>
#include <e/endian.h>

// consus
#include "common/coordinator_returncode.h"
#include "common/coordinator_link.h"

using consus::coordinator_link;

coordinator_link :: coordinator_link(const std::string& rendezvous,
                                     comm_id id, po6::net::location bind_to,
                                     const std::string& data_center,
                                     callback* c/*ownership not transferred*/)
    : m_mtx()
    , m_repl(replicant_client_create_conn_str(rendezvous.c_str()))
    , m_id(id)
    , m_bind_to(bind_to)
    , m_data_center(data_center)
    , m_cb(c)
    , m_config_id(-1)
    , m_config_status(REPLICANT_SUCCESS)
    , m_config_state(0)
    , m_config_data(NULL)
    , m_config_data_sz(0)
    , m_last_config_state(0)
    , m_last_config_valid(false)
    , m_last_online_call(0)
    , m_faf_status(REPLICANT_SUCCESS)
    , m_allow_rereg(false)
    , m_error(false)
    , m_orphaned(false)
    , m_online_once(false)
    , m_backoff(250 * PO6_MILLIS)
{
    if (!m_repl)
    {
        throw std::bad_alloc();
    }

    po6::threads::mutex::hold hold(&m_mtx);
    invariant_check();
}

coordinator_link :: ~coordinator_link() throw ()
{
    replicant_client_destroy(m_repl);
}

bool
coordinator_link :: initial_registration()
{
    {
        po6::threads::mutex::hold hold(&m_mtx);
        invariant_check();

        if (m_error)
        {
            LOG(ERROR) << "coordinator link failed";
            return false;
        }

        if (!registration())
        {
            return false;
        }
    }

    return establish();
}

bool
coordinator_link :: establish()
{
    {
        po6::threads::mutex::hold hold(&m_mtx);
        invariant_check();

        if (m_error)
        {
            LOG(ERROR) << "coordinator link failed";
            return false;
        }
    }

    maintain_connection();
    po6::threads::mutex::hold hold(&m_mtx);
    return m_last_config_valid;
}

void
coordinator_link :: allow_reregistration()
{
    po6::threads::mutex::hold hold(&m_mtx);
    m_allow_rereg = true;
}

void
coordinator_link :: maintain_connection()
{
    po6::threads::mutex::hold hold(&m_mtx);
    invariant_check();

    if (m_error)
    {
        LOG(ERROR) << "coordinator link failed";
        return;
    }

    std::string cond = m_cb->prefix() + "conf";

    if (m_config_status != REPLICANT_SUCCESS)
    {
        replicant_client_kill(m_repl, m_config_id);
        m_config_id = -1;
    }

    int timeout = 1000;

    if (m_config_id < 0)
    {
        m_config_id = replicant_client_cond_follow(m_repl, "consus", cond.c_str(),
                                                   &m_config_status, &m_config_state,
                                                   &m_config_data, &m_config_data_sz);
        replicant_returncode rc;

        if (replicant_client_wait(m_repl, m_config_id, -1, &rc) < 0 ||
            m_config_status != REPLICANT_SUCCESS)
        {
            LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
            return;
        }

        timeout = 0;
    }

    if (!m_online_once)
    {
        online();
        m_online_once = true;
        m_last_online_call = po6::monotonic_time();
    }

    replicant_returncode rc;
    m_mtx.unlock();
    replicant_client_block(m_repl, timeout);
    m_mtx.lock();

    if (replicant_client_loop(m_repl, 0, &rc) < 0)
    {
        if (rc == REPLICANT_TIMEOUT ||
            rc == REPLICANT_INTERRUPTED ||
            rc == REPLICANT_NONE_PENDING)
        {
        }
        else if (rc == REPLICANT_COMM_FAILED)
        {
            LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
            LOG(ERROR) << "backing off for " << (m_backoff / PO6_MILLIS) << " milliseconds";
            po6::sleep(m_backoff);
            m_backoff *= 2;
            return;
        }
        else
        {
            LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
            return;
        }
    }

    m_backoff = 250 * PO6_MILLIS;

    if (m_last_config_state < m_config_state)
    {
        m_last_config_valid = m_cb->new_config(m_config_data, m_config_data_sz);
        m_last_config_state = m_config_state;

        if (!m_cb->has_id(m_id) && m_allow_rereg)
        {
            registration();
        }
        else if (!m_cb->has_id(m_id))
        {
            m_orphaned = true;
        }
    }

    if (m_cb->has_id(m_id) &&
        (!m_cb->is_steady_state(m_id) || m_cb->address(m_id) != m_bind_to))
    {
        const uint64_t now = po6::monotonic_time();

        if (m_last_online_call + PO6_SECONDS < now)
        {
            online();
            m_last_online_call = now;
        }
    }
}

bool
coordinator_link :: error()
{
    po6::threads::mutex::hold hold(&m_mtx);
    return m_error;
}

bool
coordinator_link :: orphaned()
{
    po6::threads::mutex::hold hold(&m_mtx);
    return m_orphaned;
}

bool
coordinator_link :: call(const char* func,
                         const char* input, size_t input_sz,
                         coordinator_returncode* rc)
{
    po6::threads::mutex::hold hold(&m_mtx);
    return call_no_lock(func, input, input_sz, rc);
}

void
coordinator_link :: fire_and_forget(const char* func,
                                    const char* input, size_t input_sz)
{
    po6::threads::mutex::hold hold(&m_mtx);
    replicant_client_call(m_repl, "consus", func, input, input_sz,
                          0, &m_faf_status, NULL, NULL);
}

void
coordinator_link :: invariant_check()
{
    if (!m_repl)
    {
        m_error = true;
    }
    else if (!m_cb)
    {
        m_error = true;
    }
    else if (m_id == comm_id())
    {
        m_error = true;
    }
}

bool
coordinator_link :: call_no_lock(const char* func,
                                 const char* input, size_t input_sz,
                                 coordinator_returncode* rc)
{
    replicant_returncode status;
    char* output = NULL;
    size_t output_sz = 0;
    int64_t req = replicant_client_call(m_repl, "consus", func, input, input_sz,
                                        REPLICANT_CALL_ROBUST,
                                        &status, &output, &output_sz);

    if (req < 0)
    {
        LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
        return false;
    }

    int64_t loop = replicant_client_wait(m_repl, req, 10000, &status);

    if (loop < 0)
    {
        LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
        return false;
    }

    assert(loop == req);

    if (status == REPLICANT_TIMEOUT || status == REPLICANT_INTERRUPTED)
    {
        return false;
    }
    else if (status != REPLICANT_SUCCESS)
    {
        LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
        return false;
    }

    if (output_sz != 2 || !output)
    {
        LOG(ERROR) << "coordinator failure: bad response to " << func << " request";
        return false;
    }

    uint16_t x;
    e::unpack16be(output, &x);
    *rc = static_cast<coordinator_returncode>(x);
    free(output);
    return true;
}

bool
coordinator_link :: registration()
{
    std::string func = m_cb->prefix() + "_register";
    std::string input;
    e::packer(&input) << m_id << m_bind_to << e::slice(m_data_center);
    coordinator_returncode rc;

    if (!call_no_lock(func.c_str(), input.data(), input.size(), &rc))
    {
        return false;
    }

    switch (rc)
    {
        case COORD_SUCCESS:
            return true;
        case COORD_DUPLICATE:
            LOG(ERROR) << "cannot register: another server already registered this identity";
            return false;
        case COORD_NOT_FOUND:
            LOG(ERROR) << "cannot register: unknown data center";
            return false;
        case COORD_MALFORMED:
        case COORD_UNINITIALIZED:
        case COORD_NO_CAN_DO:
        default:
            LOG(ERROR) << "coordinator failure: bad response to registration request";
            return false;
    }
}

bool
coordinator_link :: online()
{
    uint64_t x;

    if (!e::generate_token(&x))
    {
        return false;
    }

    std::string func1 = m_cb->prefix() + "_online";
    std::string func2 = m_cb->prefix() + "_offline";
    std::string input;
    e::packer(&input) << m_id << m_bind_to << x;
    replicant_returncode status = REPLICANT_GARBAGE;
    replicant_returncode lstatus = REPLICANT_GARBAGE;
    int64_t req = replicant_client_defended_call(m_repl,
            "consus", func1.c_str(), input.data(), input.size(),
            func2.c_str(), input.data(), input.size(), &status);

    if (req < 0 ||
        replicant_client_wait(m_repl, req, 10000, &lstatus) != req ||
        status != REPLICANT_SUCCESS)
    {
        LOG(ERROR) << "coordinator failure: " << replicant_client_error_message(m_repl);
        return false;
    }

    return true;
}

coordinator_link :: callback :: callback()
{
}

coordinator_link :: callback :: ~callback() throw ()
{
}


//
//  Core+WebDavServer.swift
//  iTorrent
//
//  Created by Daniil Vinogradov on 30.03.2020.
//  Copyright © 2020  XITRIX. All rights reserved.
//

import Foundation
import GCDWebServer

extension Core {
    func startFileSharing() {
        var options = [String: Any]()

        if !UserPreferences.webDavUsername.isEmpty {
            options[GCDWebServerOption_AuthenticationAccounts] = [UserPreferences.webDavUsername: UserPreferences.webDavPassword]
            options[GCDWebServerOption_AuthenticationMethod] = GCDWebServerAuthenticationMethod_DigestAccess
        }

        if UserPreferences.webServerEnabled {
            options[GCDWebServerOption_Port] = 80
            if !webUploadServer.isRunning {
                if (try? webUploadServer.start(options: options)) == nil {
                    repeat {
                        options[GCDWebServerOption_Port] = Int.random(in: 49152 ..< 65535)
                    } while (try? webUploadServer.start(options: options)) == nil
                }
            }
        }

        if UserPreferences.webDavServerEnabled {
            options[GCDWebServerOption_Port] = UserPreferences.webDavPort
            if !webDAVServer.isRunning {
                try? webDAVServer.start(options: options)
            }
        }
    }

    func stopFileSharing() {
        if webUploadServer.isRunning {
            webUploadServer.stop()
        }
        if webDAVServer.isRunning {
            webDAVServer.stop()
        }
    }
}


/*
 *  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.
 */
package org.apache.isis.viewer.restfulobjects.viewer.resources;

import java.util.Collection;
import java.util.stream.Stream;

import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.security.authentication.AuthenticationSession;
import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
import org.apache.isis.viewer.restfulobjects.applib.Rel;
import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
import org.apache.isis.viewer.restfulobjects.rendering.IResourceContext;
import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainServiceLinkTo;
import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.ListReprRenderer;
import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.TypeListReprRenderer;

import lombok.val;

public class HomePageReprRenderer extends ReprRendererAbstract<HomePageReprRenderer, Void> {

    HomePageReprRenderer(final IResourceContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
        super(resourceContext, linkFollower, RepresentationType.HOME_PAGE, representation);
    }

    @Override
    public HomePageReprRenderer with(final Void t) {
        return this;
    }

    @Override
    public JsonRepresentation render() {

        // self
        if (includesSelf) {
            addLinkToSelf();
        }

        val metaModelContext = super.getResourceContext().getMetaModelContext();

        addLinkToUser(getResourceContext().getAuthenticationSessionTracker().getAuthenticationSessionElseFail());
        addLinkToMenuBars();
        addLinkToServices(metaModelContext.streamServiceAdapters());
        addLinkToVersion();
        addLinkToDomainTypes(getResourceContext().getSpecificationLoader().snapshotSpecifications());

        // inks and extensions
        representation.mapPut("extensions", JsonRepresentation.newMap());

        return representation;
    }

    private void addLinkToSelf() {
        final JsonRepresentation link = LinkBuilder.newBuilder(
                resourceContext,
                Rel.SELF.getName(),
                RepresentationType.HOME_PAGE,
                "")
                .build();

        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
        if (linkFollower.matches(link)) {
            final HomePageReprRenderer renderer = new HomePageReprRenderer(
                    getResourceContext(),
                    linkFollower,
                    JsonRepresentation.newMap());

            link.mapPut("value", renderer.render());
        }
        getLinks().arrayAdd(link);
    }

    private void addLinkToVersion() {
        final JsonRepresentation link = LinkBuilder.newBuilder(
                getResourceContext(),
                Rel.VERSION.getName(),
                RepresentationType.VERSION,
                "version")
                .build();

        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
        if (linkFollower.matches(link)) {
            final VersionReprRenderer renderer = new VersionReprRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap());
            link.mapPut("value", renderer.render());
        }

        getLinks().arrayAdd(link);
    }

    private void addLinkToServices(Stream<ManagedObject> serviceAdapters) {

        final JsonRepresentation link = LinkBuilder.newBuilder(
                getResourceContext(),
                Rel.SERVICES.getName(),
                RepresentationType.LIST,
                "services")
                .build();

        final LinkFollowSpecs linkFollowSpecs = getLinkFollowSpecs().follow("links");
        if (linkFollowSpecs.matches(link)) {

            final ListReprRenderer renderer =
                    new ListReprRenderer(
                            getResourceContext(),
                            linkFollowSpecs,
                            JsonRepresentation.newMap());

            renderer.usingLinkToBuilder(new DomainServiceLinkTo())
            .withLink(Rel.SELF, "services")
            .with(serviceAdapters);

            link.mapPut("value", renderer.render());
        }

        getLinks().arrayAdd(link);
    }

    private void addLinkToUser(AuthenticationSession authenticationSession) {
        final JsonRepresentation link = LinkBuilder.newBuilder(
                getResourceContext(),
                Rel.USER.getName(),
                RepresentationType.USER,
                "user")
                .build();

        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
        if (linkFollower.matches(link)) {
            final UserReprRenderer renderer = new UserReprRenderer(
                    getResourceContext(),
                    linkFollower,
                    JsonRepresentation.newMap());

            renderer.with(authenticationSession);
            link.mapPut("value", renderer.render());
        }

        getLinks().arrayAdd(link);
    }

    private void addLinkToMenuBars() {
        final JsonRepresentation link = LinkBuilder.newBuilder(
                        getResourceContext(),
                        Rel.MENUBARS.getName(),
                        RepresentationType.MENUBARS,
                        "menuBars")
                .build();

        getLinks().arrayAdd(link);
    }

    private void addLinkToDomainTypes(final Collection<ObjectSpecification> specifications) {

        final JsonRepresentation link =
                LinkBuilder.newBuilder(
                        getResourceContext(),
                        Rel.DOMAIN_TYPES.getName(),
                        RepresentationType.TYPE_LIST,
                        "domain-types")
                .build();

        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
        if (linkFollower.matches(link)) {
            final TypeListReprRenderer renderer = new TypeListReprRenderer(
                            getResourceContext(),
                            linkFollower,
                            JsonRepresentation.newMap());

            renderer.withLink(Rel.SELF, "domain-types").with(specifications);
            link.mapPut("value", renderer.render());
        }

        getLinks().arrayAdd(link);
    }

}


<?xml version="1.0"?>
<ZopeData>
  <record id="1" aka="AAAAAAAAAAE=">
    <pickle>
      <global name="Base Type" module="erp5.portal_type"/>
    </pickle>
    <pickle>
      <dictionary>
        <item>
            <key> <string>_property_domain_dict</string> </key>
            <value>
              <dictionary>
                <item>
                    <key> <string>short_title</string> </key>
                    <value>
                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
                    </value>
                </item>
                <item>
                    <key> <string>title</string> </key>
                    <value>
                      <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
                    </value>
                </item>
              </dictionary>
            </value>
        </item>
        <item>
            <key> <string>acquire_local_roles</string> </key>
            <value> <int>1</int> </value>
        </item>
        <item>
            <key> <string>content_icon</string> </key>
            <value> <string>document_icon.gif</string> </value>
        </item>
        <item>
            <key> <string>content_meta_type</string> </key>
            <value> <string>ERP5 Alarm</string> </value>
        </item>
        <item>
            <key> <string>description</string> </key>
            <value>
              <none/>
            </value>
        </item>
        <item>
            <key> <string>factory</string> </key>
            <value> <string>addRoundingModel</string> </value>
        </item>
        <item>
            <key> <string>filter_content_types</string> </key>
            <value> <int>1</int> </value>
        </item>
        <item>
            <key> <string>group_list</string> </key>
            <value>
              <tuple/>
            </value>
        </item>
        <item>
            <key> <string>id</string> </key>
            <value> <string>Rounding Model</string> </value>
        </item>
        <item>
            <key> <string>init_script</string> </key>
            <value>
              <none/>
            </value>
        </item>
        <item>
            <key> <string>permission</string> </key>
            <value>
              <none/>
            </value>
        </item>
        <item>
            <key> <string>title</string> </key>
            <value> <string></string> </value>
        </item>
        <item>
            <key> <string>type_class</string> </key>
            <value> <string>RoundingModel</string> </value>
        </item>
      </dictionary>
    </pickle>
  </record>
  <record id="2" aka="AAAAAAAAAAI=">
    <pickle>
      <global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
    </pickle>
    <pickle>
      <dictionary>
        <item>
            <key> <string>domain_name</string> </key>
            <value>
              <none/>
            </value>
        </item>
        <item>
            <key> <string>property_name</string> </key>
            <value> <string>short_title</string> </value>
        </item>
      </dictionary>
    </pickle>
  </record>
  <record id="3" aka="AAAAAAAAAAM=">
    <pickle>
      <global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
    </pickle>
    <pickle>
      <dictionary>
        <item>
            <key> <string>domain_name</string> </key>
            <value>
              <none/>
            </value>
        </item>
        <item>
            <key> <string>property_name</string> </key>
            <value> <string>title</string> </value>
        </item>
      </dictionary>
    </pickle>
  </record>
</ZopeData>


// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package template

import (
	"bytes"
	"fmt"
	"strings"
	"testing"
)

func TestTypedContent(t *testing.T) {
	data := []interface{}{
		`<b> "foo%" O'Reilly &bar;`,
		CSS(`a[href =~ "//example.com"]#foo`),
		HTML(`Hello, <b>World</b> &tc!`),
		HTMLAttr(` dir="ltr"`),
		JS(`c && alert("Hello, World!");`),
		JSStr(`Hello, World & O'Reilly\x21`),
		URL(`greeting=H%69&addressee=(World)`),
	}

	// For each content sensitive escaper, see how it does on
	// each of the typed strings above.
	tests := []struct {
		// A template containing a single {{.}}.
		input string
		want  []string
	}{
		{
			`<style>{{.}} { color: blue }</style>`,
			[]string{
				`ZgotmplZ`,
				// Allowed but not escaped.
				`a[href =~ "//example.com"]#foo`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
			},
		},
		{
			`<div style="{{.}}">`,
			[]string{
				`ZgotmplZ`,
				// Allowed and HTML escaped.
				`a[href =~ "//example.com"]#foo`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
			},
		},
		{
			`{{.}}`,
			[]string{
				`<b> "foo%" O'Reilly &bar;`,
				`a[href =~ "//example.com"]#foo`,
				// Not escaped.
				`Hello, <b>World</b> &tc!`,
				` dir="ltr"`,
				`c && alert("Hello, World!");`,
				`Hello, World & O'Reilly\x21`,
				`greeting=H%69&addressee=(World)`,
			},
		},
		{
			`<a{{.}}>`,
			[]string{
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				// Allowed and HTML escaped.
				` dir="ltr"`,
				`ZgotmplZ`,
				`ZgotmplZ`,
				`ZgotmplZ`,
			},
		},
		{
			`<a title={{.}}>`,
			[]string{
				`<b> "foo%" O'Reilly &bar;`,
				`a[href =~ "//example.com"]#foo`,
				// Tags stripped, spaces escaped, entity not re-escaped.
				`Hello, World &tc!`,
				` dir="ltr"`,
				`c && alert("Hello, World!");`,
				`Hello, World & O'Reilly\x21`,
				`greeting=H%69&addressee=(World)`,
			},
		},
		{
			`<a title='{{.}}'>`,
			[]string{
				`<b> "foo%" O'Reilly &bar;`,
				`a[href =~ "//example.com"]#foo`,
				// Tags stripped, entity not re-escaped.
				`Hello, World &tc!`,
				` dir="ltr"`,
				`c && alert("Hello, World!");`,
				`Hello, World & O'Reilly\x21`,
				`greeting=H%69&addressee=(World)`,
			},
		},
		{
			`<textarea>{{.}}</textarea>`,
			[]string{
				`<b> "foo%" O'Reilly &bar;`,
				`a[href =~ "//example.com"]#foo`,
				// Angle brackets escaped to prevent injection of close tags, entity not re-escaped.
				`Hello, <b>World</b> &tc!`,
				` dir="ltr"`,
				`c && alert("Hello, World!");`,
				`Hello, World & O'Reilly\x21`,
				`greeting=H%69&addressee=(World)`,
			},
		},
		{
			`<script>alert({{.}})</script>`,
			[]string{
				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
				`"a[href =~ \"//example.com\"]#foo"`,
				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
				`" dir=\"ltr\""`,
				// Not escaped.
				`c && alert("Hello, World!");`,
				// Escape sequence not over-escaped.
				`"Hello, World & O'Reilly\x21"`,
				`"greeting=H%69\u0026addressee=(World)"`,
			},
		},
		{
			`<button onclick="alert({{.}})">`,
			[]string{
				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
				`"a[href =~ \"//example.com\"]#foo"`,
				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
				`" dir=\"ltr\""`,
				// Not JS escaped but HTML escaped.
				`c && alert("Hello, World!");`,
				// Escape sequence not over-escaped.
				`"Hello, World & O'Reilly\x21"`,
				`"greeting=H%69\u0026addressee=(World)"`,
			},
		},
		{
			`<script>alert("{{.}}")</script>`,
			[]string{
				`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
				`a[href =~ \x22\/\/example.com\x22]#foo`,
				`Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
				` dir=\x22ltr\x22`,
				`c \x26\x26 alert(\x22Hello, World!\x22);`,
				// Escape sequence not over-escaped.
				`Hello, World \x26 O\x27Reilly\x21`,
				`greeting=H%69\x26addressee=(World)`,
			},
		},
		{
			`<button onclick='alert("{{.}}")'>`,
			[]string{
				`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
				`a[href =~ \x22\/\/example.com\x22]#foo`,
				`Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
				` dir=\x22ltr\x22`,
				`c \x26\x26 alert(\x22Hello, World!\x22);`,
				// Escape sequence not over-escaped.
				`Hello, World \x26 O\x27Reilly\x21`,
				`greeting=H%69\x26addressee=(World)`,
			},
		},
		{
			`<a href="?q={{.}}">`,
			[]string{
				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
				`%20dir%3d%22ltr%22`,
				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
				`Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done.
				`greeting=H%69&addressee=%28World%29`,
			},
		},
		{
			`<style>body { background: url('?img={{.}}') }</style>`,
			[]string{
				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
				`%20dir%3d%22ltr%22`,
				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
				`Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done.
				`greeting=H%69&addressee=%28World%29`,
			},
		},
	}

	for _, test := range tests {
		tmpl := Must(New("x").Parse(test.input))
		pre := strings.Index(test.input, "{{.}}")
		post := len(test.input) - (pre + 5)
		var b bytes.Buffer
		for i, x := range data {
			b.Reset()
			if err := tmpl.Execute(&b, x); err != nil {
				t.Errorf("%q with %v: %s", test.input, x, err)
				continue
			}
			if want, got := test.want[i], b.String()[pre:b.Len()-post]; want != got {
				t.Errorf("%q with %v:\nwant\n\t%q,\ngot\n\t%q\n", test.input, x, want, got)
				continue
			}
		}
	}
}

// Test that we print using the String method. Was issue 3073.
type stringer struct {
	v int
}

func (s *stringer) String() string {
	return fmt.Sprintf("string=%d", s.v)
}

type errorer struct {
	v int
}

func (s *errorer) Error() string {
	return fmt.Sprintf("error=%d", s.v)
}

func TestStringer(t *testing.T) {
	s := &stringer{3}
	b := new(bytes.Buffer)
	tmpl := Must(New("x").Parse("{{.}}"))
	if err := tmpl.Execute(b, s); err != nil {
		t.Fatal(err)
	}
	var expect = "string=3"
	if b.String() != expect {
		t.Errorf("expected %q got %q", expect, b.String())
	}
	e := &errorer{7}
	b.Reset()
	if err := tmpl.Execute(b, e); err != nil {
		t.Fatal(err)
	}
	expect = "error=7"
	if b.String() != expect {
		t.Errorf("expected %q got %q", expect, b.String())
	}
}

// https://golang.org/issue/5982
func TestEscapingNilNonemptyInterfaces(t *testing.T) {
	tmpl := Must(New("x").Parse("{{.E}}"))

	got := new(bytes.Buffer)
	testData := struct{ E error }{} // any non-empty interface here will do; error is just ready at hand
	tmpl.Execute(got, testData)

	// Use this data instead of just hard-coding "<nil>" to avoid
	// dependencies on the html escaper and the behavior of fmt w.r.t. nil.
	want := new(bytes.Buffer)
	data := struct{ E string }{E: fmt.Sprint(nil)}
	tmpl.Execute(want, data)

	if !bytes.Equal(want.Bytes(), got.Bytes()) {
		t.Errorf("expected %q got %q", string(want.Bytes()), string(got.Bytes()))
	}
}


using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

using Microsoft.Recognizers.Definitions.Japanese;

namespace Microsoft.Recognizers.Text.Number.Japanese
{
    public class JapaneseNumberParserConfiguration : BaseNumberParserConfiguration, ICJKNumberParserConfiguration
    {

        private const RegexOptions RegexFlags = RegexOptions.Singleline | RegexOptions.ExplicitCapture;

        public JapaneseNumberParserConfiguration(INumberOptionsConfiguration config)
        {

            this.Config = config;
            this.LanguageMarker = NumbersDefinitions.LangMarker;
            this.CultureInfo = new CultureInfo(config.Culture);

            this.IsCompoundNumberLanguage = NumbersDefinitions.CompoundNumberLanguage;
            this.IsMultiDecimalSeparatorCulture = NumbersDefinitions.MultiDecimalSeparatorCulture;

            this.DecimalSeparatorChar = NumbersDefinitions.DecimalSeparatorChar;
            this.FractionMarkerToken = NumbersDefinitions.FractionMarkerToken;
            this.NonDecimalSeparatorChar = NumbersDefinitions.NonDecimalSeparatorChar;
            this.HalfADozenText = NumbersDefinitions.HalfADozenText;
            this.WordSeparatorToken = NumbersDefinitions.WordSeparatorToken;
            this.ZeroChar = NumbersDefinitions.ZeroChar;
            this.PairChar = NumbersDefinitions.PairChar;

            this.WrittenDecimalSeparatorTexts = Enumerable.Empty<string>();
            this.WrittenGroupSeparatorTexts = Enumerable.Empty<string>();
            this.WrittenIntegerSeparatorTexts = Enumerable.Empty<string>();
            this.WrittenFractionSeparatorTexts = Enumerable.Empty<string>();

            this.CardinalNumberMap = new Dictionary<string, long>().ToImmutableDictionary();
            this.OrdinalNumberMap = new Dictionary<string, long>().ToImmutableDictionary();
            this.RelativeReferenceOffsetMap = NumbersDefinitions.RelativeReferenceOffsetMap.ToImmutableDictionary();
            this.RelativeReferenceRelativeToMap = NumbersDefinitions.RelativeReferenceRelativeToMap.ToImmutableDictionary();
            this.RoundNumberMap = NumbersDefinitions.RoundNumberMap.ToImmutableDictionary();
            this.ZeroToNineMap = NumbersDefinitions.ZeroToNineMap.ToImmutableDictionary();
            this.FullToHalfMap = NumbersDefinitions.FullToHalfMap.ToImmutableDictionary();
            this.RoundNumberMapChar = NumbersDefinitions.RoundNumberMapChar.ToImmutableDictionary();
            this.UnitMap = NumbersDefinitions.UnitMap.ToImmutableDictionary();
            this.RoundDirectList = NumbersDefinitions.RoundDirectList.ToImmutableList();
            this.TenChars = NumbersDefinitions.TenChars.ToImmutableList();

            this.HalfADozenRegex = null;

            // @TODO Change init to follow design in other languages
            this.DigitalNumberRegex = new Regex(NumbersDefinitions.DigitalNumberRegex, RegexFlags);
            this.DozenRegex = new Regex(NumbersDefinitions.DozenRegex, RegexFlags);
            this.PointRegex = new Regex(NumbersDefinitions.PointRegex, RegexFlags);
            this.DigitNumRegex = new Regex(NumbersDefinitions.DigitNumRegex, RegexFlags);
            this.DoubleAndRoundRegex = new Regex(NumbersDefinitions.DoubleAndRoundRegex, RegexFlags);
            this.FracSplitRegex = new Regex(NumbersDefinitions.FracSplitRegex, RegexFlags);
            this.NegativeNumberSignRegex = new Regex(NumbersDefinitions.NegativeNumberSignRegex, RegexFlags);
            this.SpeGetNumberRegex = new Regex(NumbersDefinitions.SpeGetNumberRegex, RegexFlags);
            this.PercentageRegex = new Regex(NumbersDefinitions.PercentageRegex, RegexFlags);
            this.PairRegex = new Regex(NumbersDefinitions.PairRegex, RegexFlags);
            this.RoundNumberIntegerRegex = new Regex(NumbersDefinitions.RoundNumberIntegerRegex, RegexFlags);
        }

        public string NonDecimalSeparatorText { get; private set; }

        public Regex DigitNumRegex { get; private set; }

        public Regex DozenRegex { get; private set; }

        public Regex PercentageRegex { get; private set; }

        public Regex DoubleAndRoundRegex { get; private set; }

        public Regex FracSplitRegex { get; private set; }

        public Regex PointRegex { get; private set; }

        public Regex SpeGetNumberRegex { get; private set; }

        public Regex PairRegex { get; private set; }

        public Regex RoundNumberIntegerRegex { get; private set; }

        public char ZeroChar { get; private set; }

        public char PairChar { get; private set; }

        public ImmutableDictionary<char, double> ZeroToNineMap { get; private set; }

        public ImmutableDictionary<char, long> RoundNumberMapChar { get; private set; }

        public ImmutableDictionary<char, char> FullToHalfMap { get; private set; }

        public ImmutableDictionary<string, string> UnitMap { get; private set; }

        public ImmutableDictionary<char, char> TratoSimMap { get; private set; }

        public ImmutableList<char> RoundDirectList { get; private set; }

        public ImmutableList<char> TenChars { get; private set; }

        public override IEnumerable<string> NormalizeTokenSet(IEnumerable<string> tokens, ParseResult context)
        {
            return tokens;
        }

        public override long ResolveCompositeNumber(string numberStr)
        {
            return 0;
        }
    }
}


==================== Tidy Core ====================
Result size of Tidy Core = {terms: 56, types: 67, coercions: 5, joins: 0/0}

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
T17673.$trModule4 :: GHC.Prim.Addr#
[GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
T17673.$trModule4 = "main"#

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
T17673.$trModule3 :: GHC.Types.TrName
[GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
T17673.$trModule3 = GHC.Types.TrNameS T17673.$trModule4

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
T17673.$trModule2 :: GHC.Prim.Addr#
[GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 30 0}]
T17673.$trModule2 = "T17673"#

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
T17673.$trModule1 :: GHC.Types.TrName
[GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
T17673.$trModule1 = GHC.Types.TrNameS T17673.$trModule2

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
T17673.$trModule :: GHC.Types.Module
[GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 30}]
T17673.$trModule = GHC.Types.Module T17673.$trModule3 T17673.$trModule1

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
lvl :: Int
[GblId, Unf=OtherCon []]
lvl = GHC.Types.I# 1#

Rec {
-- RHS size: {terms: 27, types: 31, coercions: 0, joins: 0/0}
T17673.$wfacIO [InlPrag=NOINLINE, Occ=LoopBreaker] :: GHC.Prim.Int# -> GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, Int #)
[GblId, Arity=2, Str=<L,U><L,U>, Unf=OtherCon []]
T17673.$wfacIO
  = \ (ww :: GHC.Prim.Int#) (w :: GHC.Prim.State# GHC.Prim.RealWorld) ->
      case GHC.Prim.<# ww 2# of {
        __DEFAULT -> case T17673.$wfacIO (GHC.Prim.-# ww 1#) w of { (# ipv, ipv1 #) -> (# ipv, case ipv1 of { GHC.Types.I# y -> GHC.Types.I# (GHC.Prim.*# ww y) } #) };
        1# -> (# w, lvl #)
      }
end Rec }

-- RHS size: {terms: 8, types: 5, coercions: 0, joins: 0/0}
T17673.facIO1 [InlPrag=NOUSERINLINE[-1]] :: Int -> GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, Int #)
[GblId,
 Arity=2,
 Str=<S,1*U(U)><L,U>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=2,unsat_ok=True,boring_ok=False)
         Tmpl= \ (w [Occ=Once!] :: Int) (w1 [Occ=Once] :: GHC.Prim.State# GHC.Prim.RealWorld) -> case w of { GHC.Types.I# ww1 [Occ=Once] -> T17673.$wfacIO ww1 w1 }}]
T17673.facIO1 = \ (w :: Int) (w1 :: GHC.Prim.State# GHC.Prim.RealWorld) -> case w of { GHC.Types.I# ww1 -> T17673.$wfacIO ww1 w1 }

-- RHS size: {terms: 1, types: 0, coercions: 5, joins: 0/0}
facIO [InlPrag=NOUSERINLINE[-1]] :: Int -> IO Int
[GblId,
 Arity=2,
 Str=<S,1*U(U)><L,U>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)
         Tmpl= T17673.facIO1 `cast` (<Int>_R ->_R Sym (GHC.Types.N:IO[0] <Int>_R) :: (Int -> GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, Int #)) ~R# (Int -> IO Int))}]
facIO = T17673.facIO1 `cast` (<Int>_R ->_R Sym (GHC.Types.N:IO[0] <Int>_R) :: (Int -> GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, Int #)) ~R# (Int -> IO Int))


# frozen_string_literal: true

module Facts
  module Linux
    class IsVirtual
      FACT_NAME = 'is_virtual'

      def call_the_resolver # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
        fact_value = check_docker_lxc || check_gce || retrieve_from_virt_what || check_vmware
        fact_value ||= check_open_vz || check_vserver || check_xen || check_other_facts || check_lspci || 'physical'

        Facter::ResolvedFact.new(FACT_NAME, check_if_virtual(fact_value))
      end

      def check_gce
        bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
        'gce' if bios_vendor&.include?('Google')
      end

      def check_docker_lxc
        Facter::Resolvers::Containers.resolve(:vm)
      end

      def check_vmware
        Facter::Resolvers::Vmware.resolve(:vm)
      end

      def retrieve_from_virt_what
        Facter::Resolvers::VirtWhat.resolve(:vm)
      end

      def check_open_vz
        Facter::Resolvers::OpenVz.resolve(:vm)
      end

      def check_vserver
        Facter::Resolvers::VirtWhat.resolve(:vserver)
      end

      def check_xen
        Facter::Resolvers::Xen.resolve(:vm)
      end

      def check_other_facts
        product_name = Facter::Resolvers::Linux::DmiBios.resolve(:product_name)
        bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
        return 'kvm' if bios_vendor&.include?('Amazon EC2')
        return unless product_name

        Facter::FactsUtils::HYPERVISORS_HASH.each { |key, value| return value if product_name.include?(key) }

        nil
      end

      def check_lspci
        Facter::Resolvers::Lspci.resolve(:vm)
      end

      def check_if_virtual(found_vm)
        Facter::FactsUtils::PHYSICAL_HYPERVISORS.count(found_vm).zero?
      end
    end
  end
end