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

package com.google.common.base;

import com.google.caliper.BeforeExperiment;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("unused") // Nested enums used reflectively in setUp.
public class EnumsBenchmark {

  @Param({"Small", "Medium", "Large"})
  String enumSize;

  @Param({"0.2", "0.8"})
  float hitRate;

  // We could avoid the raw type here by initializing this with a ternary (? SmallEnum.class : ...).
  // However, we end up needing a raw type in getIfPresent, as discussed there.
  @SuppressWarnings("rawtypes")
  private Class<? extends Enum> enumType;

  private String[] sampleData;

  @BeforeExperiment
  void setUp() throws ClassNotFoundException {
    Preconditions.checkArgument(hitRate >= 0 && hitRate <= 1, "hitRate must be in the range [0,1]");

    enumType =
        Class.forName(EnumsBenchmark.class.getCanonicalName() + "$" + enumSize + "Enum")
            .asSubclass(Enum.class);

    Enum<?>[] allConstants = enumType.getEnumConstants();
    List<String> hits = new ArrayList<>();
    for (int i = 0; i < hitRate * 256 / 3; ++i) {
      hits.add(allConstants[0].name());
      hits.add(allConstants[allConstants.length / 2].name());
      hits.add(allConstants[allConstants.length - 1].name());
    }

    List<String> misses = new ArrayList<>();
    for (int i = 0; i < 256 - hits.size(); ++i) {
      misses.add("INVALID");
    }

    List<String> sampleDataList = new ArrayList<>();
    sampleDataList.addAll(hits);
    sampleDataList.addAll(misses);
    Collections.shuffle(sampleDataList);
    sampleData = sampleDataList.toArray(new String[sampleDataList.size()]);
  }

  // Since we can't pass a concrete SomeEnum.class directly, we need to use a raw type.
  @SuppressWarnings("unchecked")
  @Benchmark
  boolean getIfPresent(int repetitions) {
    boolean retVal = false;
    for (int i = 0; i < repetitions; ++i) {
      retVal &= Enums.getIfPresent(enumType, sampleData[i & 255]).isPresent();
    }
    return retVal;
  }

  private enum SmallEnum {
    X0,
    X1,
    X2
  }

  private enum MediumEnum {
    X0,
    X1,
    X2,
    X3,
    X4,
    X5,
    X6,
    X7,
    X8,
    X9,
    X10,
    X11,
    X12,
    X13,
    X14,
    X15,
    X16,
    X17,
    X18,
    X19,
    X20,
    X21,
    X22,
    X23,
    X24,
    X25,
    X26,
    X27,
    X28,
    X29,
    X30,
    X31,
    X32,
    X33,
    X34,
    X35,
    X36,
    X37,
    X38,
    X39,
    X40,
    X41,
    X42,
    X43,
    X44,
    X45,
    X46,
    X47,
    X48,
    X49,
    X50,
    X51,
    X52,
    X53,
    X54,
    X55,
    X56,
    X57,
    X58,
    X59,
    X60,
    X61,
    X62,
    X63,
    X64,
    X65,
    X66,
    X67,
    X68,
    X69,
    X70,
    X71,
    X72,
    X73,
    X74,
    X75,
    X76,
    X77,
    X78,
    X79,
    X80,
    X81,
    X82,
    X83,
    X84,
    X85,
    X86,
    X87,
    X88,
    X89,
    X90,
    X91,
    X92,
    X93,
    X94,
    X95,
    X96,
    X97,
    X98,
    X99
  }

  private enum LargeEnum {
    X0,
    X1,
    X2,
    X3,
    X4,
    X5,
    X6,
    X7,
    X8,
    X9,
    X10,
    X11,
    X12,
    X13,
    X14,
    X15,
    X16,
    X17,
    X18,
    X19,
    X20,
    X21,
    X22,
    X23,
    X24,
    X25,
    X26,
    X27,
    X28,
    X29,
    X30,
    X31,
    X32,
    X33,
    X34,
    X35,
    X36,
    X37,
    X38,
    X39,
    X40,
    X41,
    X42,
    X43,
    X44,
    X45,
    X46,
    X47,
    X48,
    X49,
    X50,
    X51,
    X52,
    X53,
    X54,
    X55,
    X56,
    X57,
    X58,
    X59,
    X60,
    X61,
    X62,
    X63,
    X64,
    X65,
    X66,
    X67,
    X68,
    X69,
    X70,
    X71,
    X72,
    X73,
    X74,
    X75,
    X76,
    X77,
    X78,
    X79,
    X80,
    X81,
    X82,
    X83,
    X84,
    X85,
    X86,
    X87,
    X88,
    X89,
    X90,
    X91,
    X92,
    X93,
    X94,
    X95,
    X96,
    X97,
    X98,
    X99,
    X100,
    X101,
    X102,
    X103,
    X104,
    X105,
    X106,
    X107,
    X108,
    X109,
    X110,
    X111,
    X112,
    X113,
    X114,
    X115,
    X116,
    X117,
    X118,
    X119,
    X120,
    X121,
    X122,
    X123,
    X124,
    X125,
    X126,
    X127,
    X128,
    X129,
    X130,
    X131,
    X132,
    X133,
    X134,
    X135,
    X136,
    X137,
    X138,
    X139,
    X140,
    X141,
    X142,
    X143,
    X144,
    X145,
    X146,
    X147,
    X148,
    X149,
    X150,
    X151,
    X152,
    X153,
    X154,
    X155,
    X156,
    X157,
    X158,
    X159,
    X160,
    X161,
    X162,
    X163,
    X164,
    X165,
    X166,
    X167,
    X168,
    X169,
    X170,
    X171,
    X172,
    X173,
    X174,
    X175,
    X176,
    X177,
    X178,
    X179,
    X180,
    X181,
    X182,
    X183,
    X184,
    X185,
    X186,
    X187,
    X188,
    X189,
    X190,
    X191,
    X192,
    X193,
    X194,
    X195,
    X196,
    X197,
    X198,
    X199,
    X200,
    X201,
    X202,
    X203,
    X204,
    X205,
    X206,
    X207,
    X208,
    X209,
    X210,
    X211,
    X212,
    X213,
    X214,
    X215,
    X216,
    X217,
    X218,
    X219,
    X220,
    X221,
    X222,
    X223,
    X224,
    X225,
    X226,
    X227,
    X228,
    X229,
    X230,
    X231,
    X232,
    X233,
    X234,
    X235,
    X236,
    X237,
    X238,
    X239,
    X240,
    X241,
    X242,
    X243,
    X244,
    X245,
    X246,
    X247,
    X248,
    X249,
    X250,
    X251,
    X252,
    X253,
    X254,
    X255,
    X256,
    X257,
    X258,
    X259,
    X260,
    X261,
    X262,
    X263,
    X264,
    X265,
    X266,
    X267,
    X268,
    X269,
    X270,
    X271,
    X272,
    X273,
    X274,
    X275,
    X276,
    X277,
    X278,
    X279,
    X280,
    X281,
    X282,
    X283,
    X284,
    X285,
    X286,
    X287,
    X288,
    X289,
    X290,
    X291,
    X292,
    X293,
    X294,
    X295,
    X296,
    X297,
    X298,
    X299,
    X300,
    X301,
    X302,
    X303,
    X304,
    X305,
    X306,
    X307,
    X308,
    X309,
    X310,
    X311,
    X312,
    X313,
    X314,
    X315,
    X316,
    X317,
    X318,
    X319,
    X320,
    X321,
    X322,
    X323,
    X324,
    X325,
    X326,
    X327,
    X328,
    X329,
    X330,
    X331,
    X332,
    X333,
    X334,
    X335,
    X336,
    X337,
    X338,
    X339,
    X340,
    X341,
    X342,
    X343,
    X344,
    X345,
    X346,
    X347,
    X348,
    X349,
    X350,
    X351,
    X352,
    X353,
    X354,
    X355,
    X356,
    X357,
    X358,
    X359,
    X360,
    X361,
    X362,
    X363,
    X364,
    X365,
    X366,
    X367,
    X368,
    X369,
    X370,
    X371,
    X372,
    X373,
    X374,
    X375,
    X376,
    X377,
    X378,
    X379,
    X380,
    X381,
    X382,
    X383,
    X384,
    X385,
    X386,
    X387,
    X388,
    X389,
    X390,
    X391,
    X392,
    X393,
    X394,
    X395,
    X396,
    X397,
    X398,
    X399,
    X400,
    X401,
    X402,
    X403,
    X404,
    X405,
    X406,
    X407,
    X408,
    X409,
    X410,
    X411,
    X412,
    X413,
    X414,
    X415,
    X416,
    X417,
    X418,
    X419,
    X420,
    X421,
    X422,
    X423,
    X424,
    X425,
    X426,
    X427,
    X428,
    X429,
    X430,
    X431,
    X432,
    X433,
    X434,
    X435,
    X436,
    X437,
    X438,
    X439,
    X440,
    X441,
    X442,
    X443,
    X444,
    X445,
    X446,
    X447,
    X448,
    X449,
    X450,
    X451,
    X452,
    X453,
    X454,
    X455,
    X456,
    X457,
    X458,
    X459,
    X460,
    X461,
    X462,
    X463,
    X464,
    X465,
    X466,
    X467,
    X468,
    X469,
    X470,
    X471,
    X472,
    X473,
    X474,
    X475,
    X476,
    X477,
    X478,
    X479,
    X480,
    X481,
    X482,
    X483,
    X484,
    X485,
    X486,
    X487,
    X488,
    X489,
    X490,
    X491,
    X492,
    X493,
    X494,
    X495,
    X496,
    X497,
    X498,
    X499,
    X500,
    X501,
    X502,
    X503,
    X504,
    X505,
    X506,
    X507,
    X508,
    X509,
    X510,
    X511,
    X512,
    X513,
    X514,
    X515,
    X516,
    X517,
    X518,
    X519,
    X520,
    X521,
    X522,
    X523,
    X524,
    X525,
    X526,
    X527,
    X528,
    X529,
    X530,
    X531,
    X532,
    X533,
    X534,
    X535,
    X536,
    X537,
    X538,
    X539,
    X540,
    X541,
    X542,
    X543,
    X544,
    X545,
    X546,
    X547,
    X548,
    X549,
    X550,
    X551,
    X552,
    X553,
    X554,
    X555,
    X556,
    X557,
    X558,
    X559,
    X560,
    X561,
    X562,
    X563,
    X564,
    X565,
    X566,
    X567,
    X568,
    X569,
    X570,
    X571,
    X572,
    X573,
    X574,
    X575,
    X576,
    X577,
    X578,
    X579,
    X580,
    X581,
    X582,
    X583,
    X584,
    X585,
    X586,
    X587,
    X588,
    X589,
    X590,
    X591,
    X592,
    X593,
    X594,
    X595,
    X596,
    X597,
    X598,
    X599,
    X600,
    X601,
    X602,
    X603,
    X604,
    X605,
    X606,
    X607,
    X608,
    X609,
    X610,
    X611,
    X612,
    X613,
    X614,
    X615,
    X616,
    X617,
    X618,
    X619,
    X620,
    X621,
    X622,
    X623,
    X624,
    X625,
    X626,
    X627,
    X628,
    X629,
    X630,
    X631,
    X632,
    X633,
    X634,
    X635,
    X636,
    X637,
    X638,
    X639,
    X640,
    X641,
    X642,
    X643,
    X644,
    X645,
    X646,
    X647,
    X648,
    X649,
    X650,
    X651,
    X652,
    X653,
    X654,
    X655,
    X656,
    X657,
    X658,
    X659,
    X660,
    X661,
    X662,
    X663,
    X664,
    X665,
    X666,
    X667,
    X668,
    X669,
    X670,
    X671,
    X672,
    X673,
    X674,
    X675,
    X676,
    X677,
    X678,
    X679,
    X680,
    X681,
    X682,
    X683,
    X684,
    X685,
    X686,
    X687,
    X688,
    X689,
    X690,
    X691,
    X692,
    X693,
    X694,
    X695,
    X696,
    X697,
    X698,
    X699,
    X700,
    X701,
    X702,
    X703,
    X704,
    X705,
    X706,
    X707,
    X708,
    X709,
    X710,
    X711,
    X712,
    X713,
    X714,
    X715,
    X716,
    X717,
    X718,
    X719,
    X720,
    X721,
    X722,
    X723,
    X724,
    X725,
    X726,
    X727,
    X728,
    X729,
    X730,
    X731,
    X732,
    X733,
    X734,
    X735,
    X736,
    X737,
    X738,
    X739,
    X740,
    X741,
    X742,
    X743,
    X744,
    X745,
    X746,
    X747,
    X748,
    X749,
    X750,
    X751,
    X752,
    X753,
    X754,
    X755,
    X756,
    X757,
    X758,
    X759,
    X760,
    X761,
    X762,
    X763,
    X764,
    X765,
    X766,
    X767,
    X768,
    X769,
    X770,
    X771,
    X772,
    X773,
    X774,
    X775,
    X776,
    X777,
    X778,
    X779,
    X780,
    X781,
    X782,
    X783,
    X784,
    X785,
    X786,
    X787,
    X788,
    X789,
    X790,
    X791,
    X792,
    X793,
    X794,
    X795,
    X796,
    X797,
    X798,
    X799,
    X800,
    X801,
    X802,
    X803,
    X804,
    X805,
    X806,
    X807,
    X808,
    X809,
    X810,
    X811,
    X812,
    X813,
    X814,
    X815,
    X816,
    X817,
    X818,
    X819,
    X820,
    X821,
    X822,
    X823,
    X824,
    X825,
    X826,
    X827,
    X828,
    X829,
    X830,
    X831,
    X832,
    X833,
    X834,
    X835,
    X836,
    X837,
    X838,
    X839,
    X840,
    X841,
    X842,
    X843,
    X844,
    X845,
    X846,
    X847,
    X848,
    X849,
    X850,
    X851,
    X852,
    X853,
    X854,
    X855,
    X856,
    X857,
    X858,
    X859,
    X860,
    X861,
    X862,
    X863,
    X864,
    X865,
    X866,
    X867,
    X868,
    X869,
    X870,
    X871,
    X872,
    X873,
    X874,
    X875,
    X876,
    X877,
    X878,
    X879,
    X880,
    X881,
    X882,
    X883,
    X884,
    X885,
    X886,
    X887,
    X888,
    X889,
    X890,
    X891,
    X892,
    X893,
    X894,
    X895,
    X896,
    X897,
    X898,
    X899,
    X900,
    X901,
    X902,
    X903,
    X904,
    X905,
    X906,
    X907,
    X908,
    X909,
    X910,
    X911,
    X912,
    X913,
    X914,
    X915,
    X916,
    X917,
    X918,
    X919,
    X920,
    X921,
    X922,
    X923,
    X924,
    X925,
    X926,
    X927,
    X928,
    X929,
    X930,
    X931,
    X932,
    X933,
    X934,
    X935,
    X936,
    X937,
    X938,
    X939,
    X940,
    X941,
    X942,
    X943,
    X944,
    X945,
    X946,
    X947,
    X948,
    X949,
    X950,
    X951,
    X952,
    X953,
    X954,
    X955,
    X956,
    X957,
    X958,
    X959,
    X960,
    X961,
    X962,
    X963,
    X964,
    X965,
    X966,
    X967,
    X968,
    X969,
    X970,
    X971,
    X972,
    X973,
    X974,
    X975,
    X976,
    X977,
    X978,
    X979,
    X980,
    X981,
    X982,
    X983,
    X984,
    X985,
    X986,
    X987,
    X988,
    X989,
    X990,
    X991,
    X992,
    X993,
    X994,
    X995,
    X996,
    X997,
    X998,
    X999,
    X1000,
    X1001,
    X1002,
    X1003,
    X1004,
    X1005,
    X1006,
    X1007,
    X1008,
    X1009,
    X1010,
    X1011,
    X1012,
    X1013,
    X1014,
    X1015,
    X1016,
    X1017,
    X1018,
    X1019,
    X1020,
    X1021,
    X1022,
    X1023,
    X1024,
    X1025,
    X1026,
    X1027,
    X1028,
    X1029,
    X1030,
    X1031,
    X1032,
    X1033,
    X1034,
    X1035,
    X1036,
    X1037,
    X1038,
    X1039,
    X1040,
    X1041,
    X1042,
    X1043,
    X1044,
    X1045,
    X1046,
    X1047,
    X1048,
    X1049,
    X1050,
    X1051,
    X1052,
    X1053,
    X1054,
    X1055,
    X1056,
    X1057,
    X1058,
    X1059,
    X1060,
    X1061,
    X1062,
    X1063,
    X1064,
    X1065,
    X1066,
    X1067,
    X1068,
    X1069,
    X1070,
    X1071,
    X1072,
    X1073,
    X1074,
    X1075,
    X1076,
    X1077,
    X1078,
    X1079,
    X1080,
    X1081,
    X1082,
    X1083,
    X1084,
    X1085,
    X1086,
    X1087,
    X1088,
    X1089,
    X1090,
    X1091,
    X1092,
    X1093,
    X1094,
    X1095,
    X1096,
    X1097,
    X1098,
    X1099,
    X1100,
    X1101,
    X1102,
    X1103,
    X1104,
    X1105,
    X1106,
    X1107,
    X1108,
    X1109,
    X1110,
    X1111,
    X1112,
    X1113,
    X1114,
    X1115,
    X1116,
    X1117,
    X1118,
    X1119,
    X1120,
    X1121,
    X1122,
    X1123,
    X1124,
    X1125,
    X1126,
    X1127,
    X1128,
    X1129,
    X1130,
    X1131,
    X1132,
    X1133,
    X1134,
    X1135,
    X1136,
    X1137,
    X1138,
    X1139,
    X1140,
    X1141,
    X1142,
    X1143,
    X1144,
    X1145,
    X1146,
    X1147,
    X1148,
    X1149,
    X1150,
    X1151,
    X1152,
    X1153,
    X1154,
    X1155,
    X1156,
    X1157,
    X1158,
    X1159,
    X1160,
    X1161,
    X1162,
    X1163,
    X1164,
    X1165,
    X1166,
    X1167,
    X1168,
    X1169,
    X1170,
    X1171,
    X1172,
    X1173,
    X1174,
    X1175,
    X1176,
    X1177,
    X1178,
    X1179,
    X1180,
    X1181,
    X1182,
    X1183,
    X1184,
    X1185,
    X1186,
    X1187,
    X1188,
    X1189,
    X1190,
    X1191,
    X1192,
    X1193,
    X1194,
    X1195,
    X1196,
    X1197,
    X1198,
    X1199,
    X1200,
    X1201,
    X1202,
    X1203,
    X1204,
    X1205,
    X1206,
    X1207,
    X1208,
    X1209,
    X1210,
    X1211,
    X1212,
    X1213,
    X1214,
    X1215,
    X1216,
    X1217,
    X1218,
    X1219,
    X1220,
    X1221,
    X1222,
    X1223,
    X1224,
    X1225,
    X1226,
    X1227,
    X1228,
    X1229,
    X1230,
    X1231,
    X1232,
    X1233,
    X1234,
    X1235,
    X1236,
    X1237,
    X1238,
    X1239,
    X1240,
    X1241,
    X1242,
    X1243,
    X1244,
    X1245,
    X1246,
    X1247,
    X1248,
    X1249,
    X1250,
    X1251,
    X1252,
    X1253,
    X1254,
    X1255,
    X1256,
    X1257,
    X1258,
    X1259,
    X1260,
    X1261,
    X1262,
    X1263,
    X1264,
    X1265,
    X1266,
    X1267,
    X1268,
    X1269,
    X1270,
    X1271,
    X1272,
    X1273,
    X1274,
    X1275,
    X1276,
    X1277,
    X1278,
    X1279,
    X1280,
    X1281,
    X1282,
    X1283,
    X1284,
    X1285,
    X1286,
    X1287,
    X1288,
    X1289,
    X1290,
    X1291,
    X1292,
    X1293,
    X1294,
    X1295,
    X1296,
    X1297,
    X1298,
    X1299,
    X1300,
    X1301,
    X1302,
    X1303,
    X1304,
    X1305,
    X1306,
    X1307,
    X1308,
    X1309,
    X1310,
    X1311,
    X1312,
    X1313,
    X1314,
    X1315,
    X1316,
    X1317,
    X1318,
    X1319,
    X1320,
    X1321,
    X1322,
    X1323,
    X1324,
    X1325,
    X1326,
    X1327,
    X1328,
    X1329,
    X1330,
    X1331,
    X1332,
    X1333,
    X1334,
    X1335,
    X1336,
    X1337,
    X1338,
    X1339,
    X1340,
    X1341,
    X1342,
    X1343,
    X1344,
    X1345,
    X1346,
    X1347,
    X1348,
    X1349,
    X1350,
    X1351,
    X1352,
    X1353,
    X1354,
    X1355,
    X1356,
    X1357,
    X1358,
    X1359,
    X1360,
    X1361,
    X1362,
    X1363,
    X1364,
    X1365,
    X1366,
    X1367,
    X1368,
    X1369,
    X1370,
    X1371,
    X1372,
    X1373,
    X1374,
    X1375,
    X1376,
    X1377,
    X1378,
    X1379,
    X1380,
    X1381,
    X1382,
    X1383,
    X1384,
    X1385,
    X1386,
    X1387,
    X1388,
    X1389,
    X1390,
    X1391,
    X1392,
    X1393,
    X1394,
    X1395,
    X1396,
    X1397,
    X1398,
    X1399,
    X1400,
    X1401,
    X1402,
    X1403,
    X1404,
    X1405,
    X1406,
    X1407,
    X1408,
    X1409,
    X1410,
    X1411,
    X1412,
    X1413,
    X1414,
    X1415,
    X1416,
    X1417,
    X1418,
    X1419,
    X1420,
    X1421,
    X1422,
    X1423,
    X1424,
    X1425,
    X1426,
    X1427,
    X1428,
    X1429,
    X1430,
    X1431,
    X1432,
    X1433,
    X1434,
    X1435,
    X1436,
    X1437,
    X1438,
    X1439,
    X1440,
    X1441,
    X1442,
    X1443,
    X1444,
    X1445,
    X1446,
    X1447,
    X1448,
    X1449,
    X1450,
    X1451,
    X1452,
    X1453,
    X1454,
    X1455,
    X1456,
    X1457,
    X1458,
    X1459,
    X1460,
    X1461,
    X1462,
    X1463,
    X1464,
    X1465,
    X1466,
    X1467,
    X1468,
    X1469,
    X1470,
    X1471,
    X1472,
    X1473,
    X1474,
    X1475,
    X1476,
    X1477,
    X1478,
    X1479,
    X1480,
    X1481,
    X1482,
    X1483,
    X1484,
    X1485,
    X1486,
    X1487,
    X1488,
    X1489,
    X1490,
    X1491,
    X1492,
    X1493,
    X1494,
    X1495,
    X1496,
    X1497,
    X1498,
    X1499,
    X1500,
    X1501,
    X1502,
    X1503,
    X1504,
    X1505,
    X1506,
    X1507,
    X1508,
    X1509,
    X1510,
    X1511,
    X1512,
    X1513,
    X1514,
    X1515,
    X1516,
    X1517,
    X1518,
    X1519,
    X1520,
    X1521,
    X1522,
    X1523,
    X1524,
    X1525,
    X1526,
    X1527,
    X1528,
    X1529,
    X1530,
    X1531,
    X1532,
    X1533,
    X1534,
    X1535,
    X1536,
    X1537,
    X1538,
    X1539,
    X1540,
    X1541,
    X1542,
    X1543,
    X1544,
    X1545,
    X1546,
    X1547,
    X1548,
    X1549,
    X1550,
    X1551,
    X1552,
    X1553,
    X1554,
    X1555,
    X1556,
    X1557,
    X1558,
    X1559,
    X1560,
    X1561,
    X1562,
    X1563,
    X1564,
    X1565,
    X1566,
    X1567,
    X1568,
    X1569,
    X1570,
    X1571,
    X1572,
    X1573,
    X1574,
    X1575,
    X1576,
    X1577,
    X1578,
    X1579,
    X1580,
    X1581,
    X1582,
    X1583,
    X1584,
    X1585,
    X1586,
    X1587,
    X1588,
    X1589,
    X1590,
    X1591,
    X1592,
    X1593,
    X1594,
    X1595,
    X1596,
    X1597,
    X1598,
    X1599,
    X1600,
    X1601,
    X1602,
    X1603,
    X1604,
    X1605,
    X1606,
    X1607,
    X1608,
    X1609,
    X1610,
    X1611,
    X1612,
    X1613,
    X1614,
    X1615,
    X1616,
    X1617,
    X1618,
    X1619,
    X1620,
    X1621,
    X1622,
    X1623,
    X1624,
    X1625,
    X1626,
    X1627,
    X1628,
    X1629,
    X1630,
    X1631,
    X1632,
    X1633,
    X1634,
    X1635,
    X1636,
    X1637,
    X1638,
    X1639,
    X1640,
    X1641,
    X1642,
    X1643,
    X1644,
    X1645,
    X1646,
    X1647,
    X1648,
    X1649,
    X1650,
    X1651,
    X1652,
    X1653,
    X1654,
    X1655,
    X1656,
    X1657,
    X1658,
    X1659,
    X1660,
    X1661,
    X1662,
    X1663,
    X1664,
    X1665,
    X1666,
    X1667,
    X1668,
    X1669,
    X1670,
    X1671,
    X1672,
    X1673,
    X1674,
    X1675,
    X1676,
    X1677,
    X1678,
    X1679,
    X1680,
    X1681,
    X1682,
    X1683,
    X1684,
    X1685,
    X1686,
    X1687,
    X1688,
    X1689,
    X1690,
    X1691,
    X1692,
    X1693,
    X1694,
    X1695,
    X1696,
    X1697,
    X1698,
    X1699,
    X1700,
    X1701,
    X1702,
    X1703,
    X1704,
    X1705,
    X1706,
    X1707,
    X1708,
    X1709,
    X1710,
    X1711,
    X1712,
    X1713,
    X1714,
    X1715,
    X1716,
    X1717,
    X1718,
    X1719,
    X1720,
    X1721,
    X1722,
    X1723,
    X1724,
    X1725,
    X1726,
    X1727,
    X1728,
    X1729,
    X1730,
    X1731,
    X1732,
    X1733,
    X1734,
    X1735,
    X1736,
    X1737,
    X1738,
    X1739,
    X1740,
    X1741,
    X1742,
    X1743,
    X1744,
    X1745,
    X1746,
    X1747,
    X1748,
    X1749,
    X1750,
    X1751,
    X1752,
    X1753,
    X1754,
    X1755,
    X1756,
    X1757,
    X1758,
    X1759,
    X1760,
    X1761,
    X1762,
    X1763,
    X1764,
    X1765,
    X1766,
    X1767,
    X1768,
    X1769,
    X1770,
    X1771,
    X1772,
    X1773,
    X1774,
    X1775,
    X1776,
    X1777,
    X1778,
    X1779,
    X1780,
    X1781,
    X1782,
    X1783,
    X1784,
    X1785,
    X1786,
    X1787,
    X1788,
    X1789,
    X1790,
    X1791,
    X1792,
    X1793,
    X1794,
    X1795,
    X1796,
    X1797,
    X1798,
    X1799,
    X1800,
    X1801,
    X1802,
    X1803,
    X1804,
    X1805,
    X1806,
    X1807,
    X1808,
    X1809,
    X1810,
    X1811,
    X1812,
    X1813,
    X1814,
    X1815,
    X1816,
    X1817,
    X1818,
    X1819,
    X1820,
    X1821,
    X1822,
    X1823,
    X1824,
    X1825,
    X1826,
    X1827,
    X1828,
    X1829,
    X1830,
    X1831,
    X1832,
    X1833,
    X1834,
    X1835,
    X1836,
    X1837,
    X1838,
    X1839,
    X1840,
    X1841,
    X1842,
    X1843,
    X1844,
    X1845,
    X1846,
    X1847,
    X1848,
    X1849,
    X1850,
    X1851,
    X1852,
    X1853,
    X1854,
    X1855,
    X1856,
    X1857,
    X1858,
    X1859,
    X1860,
    X1861,
    X1862,
    X1863,
    X1864,
    X1865,
    X1866,
    X1867,
    X1868,
    X1869,
    X1870,
    X1871,
    X1872,
    X1873,
    X1874,
    X1875,
    X1876,
    X1877,
    X1878,
    X1879,
    X1880,
    X1881,
    X1882,
    X1883,
    X1884,
    X1885,
    X1886,
    X1887,
    X1888,
    X1889,
    X1890,
    X1891,
    X1892,
    X1893,
    X1894,
    X1895,
    X1896,
    X1897,
    X1898,
    X1899,
    X1900,
    X1901,
    X1902,
    X1903,
    X1904,
    X1905,
    X1906,
    X1907,
    X1908,
    X1909,
    X1910,
    X1911,
    X1912,
    X1913,
    X1914,
    X1915,
    X1916,
    X1917,
    X1918,
    X1919,
    X1920,
    X1921,
    X1922,
    X1923,
    X1924,
    X1925,
    X1926,
    X1927,
    X1928,
    X1929,
    X1930,
    X1931,
    X1932,
    X1933,
    X1934,
    X1935,
    X1936,
    X1937,
    X1938,
    X1939,
    X1940,
    X1941,
    X1942,
    X1943,
    X1944,
    X1945,
    X1946,
    X1947,
    X1948,
    X1949,
    X1950,
    X1951,
    X1952,
    X1953,
    X1954,
    X1955,
    X1956,
    X1957,
    X1958,
    X1959,
    X1960,
    X1961,
    X1962,
    X1963,
    X1964,
    X1965,
    X1966,
    X1967,
    X1968,
    X1969,
    X1970,
    X1971,
    X1972,
    X1973,
    X1974,
    X1975,
    X1976,
    X1977,
    X1978,
    X1979,
    X1980,
    X1981,
    X1982,
    X1983,
    X1984,
    X1985,
    X1986,
    X1987,
    X1988,
    X1989,
    X1990,
    X1991,
    X1992,
    X1993,
    X1994,
    X1995,
    X1996,
    X1997,
    X1998,
    X1999,
    X2000,
    X2001,
    X2002,
    X2003,
    X2004,
    X2005,
    X2006,
    X2007,
    X2008,
    X2009,
    X2010,
    X2011,
    X2012,
    X2013,
    X2014,
    X2015,
    X2016,
    X2017,
    X2018,
    X2019,
    X2020,
    X2021,
    X2022,
    X2023,
    X2024,
    X2025,
    X2026,
    X2027,
    X2028,
    X2029,
    X2030,
    X2031,
    X2032,
    X2033,
    X2034,
    X2035,
    X2036,
    X2037,
    X2038,
    X2039,
    X2040,
    X2041,
    X2042,
    X2043,
    X2044,
    X2045,
    X2046,
    X2047,
    X2048,
    X2049,
    X2050,
    X2051,
    X2052,
    X2053,
    X2054,
    X2055,
    X2056,
    X2057,
    X2058,
    X2059,
    X2060,
    X2061,
    X2062,
    X2063,
    X2064,
    X2065,
    X2066,
    X2067,
    X2068,
    X2069,
    X2070,
    X2071,
    X2072,
    X2073,
    X2074,
    X2075,
    X2076,
    X2077,
    X2078,
    X2079,
    X2080,
    X2081,
    X2082,
    X2083,
    X2084,
    X2085,
    X2086,
    X2087,
    X2088,
    X2089,
    X2090,
    X2091,
    X2092,
    X2093,
    X2094,
    X2095,
    X2096,
    X2097,
    X2098,
    X2099,
    X2100,
    X2101,
    X2102,
    X2103,
    X2104,
    X2105,
    X2106,
    X2107,
    X2108,
    X2109,
    X2110,
    X2111,
    X2112,
    X2113,
    X2114,
    X2115,
    X2116,
    X2117,
    X2118,
    X2119,
    X2120,
    X2121,
    X2122,
    X2123,
    X2124,
    X2125,
    X2126,
    X2127,
    X2128,
    X2129,
    X2130,
    X2131,
    X2132,
    X2133,
    X2134,
    X2135,
    X2136,
    X2137,
    X2138,
    X2139,
    X2140,
    X2141,
    X2142,
    X2143,
    X2144,
    X2145,
    X2146,
    X2147,
    X2148,
    X2149,
    X2150,
    X2151,
    X2152,
    X2153,
    X2154,
    X2155,
    X2156,
    X2157,
    X2158,
    X2159,
    X2160,
    X2161,
    X2162,
    X2163,
    X2164,
    X2165,
    X2166,
    X2167,
    X2168,
    X2169,
    X2170,
    X2171,
    X2172,
    X2173,
    X2174,
    X2175,
    X2176,
    X2177,
    X2178,
    X2179,
    X2180,
    X2181,
    X2182,
    X2183,
    X2184,
    X2185,
    X2186,
    X2187,
    X2188,
    X2189,
    X2190,
    X2191,
    X2192,
    X2193,
    X2194,
    X2195,
    X2196,
    X2197,
    X2198,
    X2199,
    X2200,
    X2201,
    X2202,
    X2203,
    X2204,
    X2205,
    X2206,
    X2207,
    X2208,
    X2209,
    X2210,
    X2211,
    X2212,
    X2213,
    X2214,
    X2215,
    X2216,
    X2217,
    X2218,
    X2219,
    X2220,
    X2221,
    X2222,
    X2223,
    X2224,
    X2225,
    X2226,
    X2227,
    X2228,
    X2229,
    X2230,
    X2231,
    X2232,
    X2233,
    X2234,
    X2235,
    X2236,
    X2237,
    X2238,
    X2239,
    X2240,
    X2241,
    X2242,
    X2243,
    X2244,
    X2245,
    X2246,
    X2247,
    X2248,
    X2249,
    X2250,
    X2251,
    X2252,
    X2253,
    X2254,
    X2255,
    X2256,
    X2257,
    X2258,
    X2259,
    X2260,
    X2261,
    X2262,
    X2263,
    X2264,
    X2265,
    X2266,
    X2267,
    X2268,
    X2269,
    X2270,
    X2271,
    X2272,
    X2273,
    X2274,
    X2275,
    X2276,
    X2277,
    X2278,
    X2279,
    X2280,
    X2281,
    X2282,
    X2283,
    X2284,
    X2285,
    X2286,
    X2287,
    X2288,
    X2289,
    X2290,
    X2291,
    X2292,
    X2293,
    X2294,
    X2295,
    X2296,
    X2297,
    X2298,
    X2299,
    X2300,
    X2301,
    X2302,
    X2303,
    X2304,
    X2305,
    X2306,
    X2307,
    X2308,
    X2309,
    X2310,
    X2311,
    X2312,
    X2313,
    X2314,
    X2315,
    X2316,
    X2317,
    X2318,
    X2319,
    X2320,
    X2321,
    X2322,
    X2323,
    X2324,
    X2325,
    X2326,
    X2327,
    X2328,
    X2329,
    X2330,
    X2331,
    X2332,
    X2333,
    X2334,
    X2335,
    X2336,
    X2337,
    X2338,
    X2339,
    X2340,
    X2341,
    X2342,
    X2343,
    X2344,
    X2345,
    X2346,
    X2347,
    X2348,
    X2349,
    X2350,
    X2351,
    X2352,
    X2353,
    X2354,
    X2355,
    X2356,
    X2357,
    X2358,
    X2359,
    X2360,
    X2361,
    X2362,
    X2363,
    X2364,
    X2365,
    X2366,
    X2367,
    X2368,
    X2369,
    X2370,
    X2371,
    X2372,
    X2373,
    X2374,
    X2375,
    X2376,
    X2377,
    X2378,
    X2379,
    X2380,
    X2381,
    X2382,
    X2383,
    X2384,
    X2385,
    X2386,
    X2387,
    X2388,
    X2389,
    X2390,
    X2391,
    X2392,
    X2393,
    X2394,
    X2395,
    X2396,
    X2397,
    X2398,
    X2399,
    X2400,
    X2401,
    X2402,
    X2403,
    X2404,
    X2405,
    X2406,
    X2407,
    X2408,
    X2409,
    X2410,
    X2411,
    X2412,
    X2413,
    X2414,
    X2415,
    X2416,
    X2417,
    X2418,
    X2419,
    X2420,
    X2421,
    X2422,
    X2423,
    X2424,
    X2425,
    X2426,
    X2427,
    X2428,
    X2429,
    X2430,
    X2431,
    X2432,
    X2433,
    X2434,
    X2435,
    X2436,
    X2437,
    X2438,
    X2439,
    X2440,
    X2441,
    X2442,
    X2443,
    X2444,
    X2445,
    X2446,
    X2447,
    X2448,
    X2449,
    X2450,
    X2451,
    X2452,
    X2453,
    X2454,
    X2455,
    X2456,
    X2457,
    X2458,
    X2459,
    X2460,
    X2461,
    X2462,
    X2463,
    X2464,
    X2465,
    X2466,
    X2467,
    X2468,
    X2469,
    X2470,
    X2471,
    X2472,
    X2473,
    X2474,
    X2475,
    X2476,
    X2477,
    X2478,
    X2479,
    X2480,
    X2481,
    X2482,
    X2483,
    X2484,
    X2485,
    X2486,
    X2487,
    X2488,
    X2489,
    X2490,
    X2491,
    X2492,
    X2493,
    X2494,
    X2495,
    X2496,
    X2497,
    X2498,
    X2499
  }
}
