public static Bindings Create(Bindings prev, ISchema input)
            {
                int groupsLen = prev.GroupInfos.Length;
                var groups = new ColGroupInfo[groupsLen];
                for (int i = 0; i < groupsLen; i++)
                {
                    var groupInfo = prev.GroupInfos[i];
                    var lang = groupInfo.Lang;
                    var srcName = groupInfo.SrcColName;
                    int srcIdx;
                    ColumnType srcType;
                    Bind(input, srcName, t => t.ItemType.IsText, SrcTypeName, out srcIdx, out srcType, false);

                    var langsName = groupInfo.LangsColName;
                    int langsIdx;
                    if (langsName != null)
                    {
                        ColumnType langsType;
                        Bind(input, langsName, t => t.IsText, LangTypeName, out langsIdx, out langsType, false);
                    }
                    else
                        langsIdx = -1;

                    bool requireTypes = groupInfo.RequireTypes;
                    groups[i] = new ColGroupInfo(lang, srcIdx, srcName, srcType, langsIdx, langsName, requireTypes);

                }

                return new Bindings(groups, prev.Infos.ToArray(), input, false, prev._names);

            }
            public static Bindings Create(ModelLoadContext ctx, ISchema input, IChannel ch)
            {
                Contracts.AssertValue(ch);
                ch.AssertValue(ctx);

                // *** Binary format ***
                // int: count of group column infos (ie, count of source columns)
                // For each group column info
                //     int: the tokenizer language
                //     int: the id of source column name
                //     int: the id of languages column name
                //     bool: whether the types output is required
                //     For each column info that belongs to this group column info
                //     (either one column info for tokens or two for tokens and types)
                //          int: the id of the column name

                int groupsLen = ctx.Reader.ReadInt32();
                ch.CheckDecode(groupsLen > 0);

                var names = new List<string>();
                var infos = new List<ColInfo>();
                var groups = new ColGroupInfo[groupsLen];
                for (int i = 0; i < groups.Length; i++)
                {
                    int lang = ctx.Reader.ReadInt32();
                    ch.CheckDecode(Enum.IsDefined(typeof(Language), lang));

                    string srcName = ctx.LoadNonEmptyString();
                    int srcIdx;
                    ColumnType srcType;
                    Bind(input, srcName, t => t.ItemType.IsText, SrcTypeName, out srcIdx, out srcType, false);

                    string langsName = ctx.LoadStringOrNull();
                    int langsIdx;
                    if (langsName != null)
                    {
                        ColumnType langsType;
                        Bind(input, langsName, t => t.IsText, LangTypeName, out langsIdx, out langsType, false);
                    }
                    else
                        langsIdx = -1;

                    bool requireTypes = ctx.Reader.ReadBoolByte();
                    groups[i] = new ColGroupInfo((Language)lang, srcIdx, srcName, srcType, langsIdx, langsName, requireTypes);

                    infos.Add(new ColInfo(i));
                    names.Add(ctx.LoadNonEmptyString());
                    if (requireTypes)
                    {
                        infos.Add(new ColInfo(i, isTypes: true));
                        names.Add(ctx.LoadNonEmptyString());
                    }
                }

                return new Bindings(groups, infos.ToArray(), input, false, names.ToArray());
            }
            public static Bindings Create(Arguments args, ISchema input, IChannel ch, bool exceptUser = true)
            {
                Contracts.AssertValue(ch);
                ch.AssertValue(args);
                ch.CheckUserArg(Utils.Size(args.Column) > 0, nameof(args.Column), "Column is missing");
                ch.CheckUserArg(Enum.IsDefined(typeof(Language), args.Language),
                    nameof(args.Language), "'lang' has invalid value");

                int namesLen = 0;
                foreach (var col in args.Column)
                {
                    ch.CheckUserArg(!string.IsNullOrWhiteSpace(col.Source), nameof(col.Source), "Cannot be empty");
                    ch.CheckUserArg(!string.IsNullOrWhiteSpace(col.TokensColumn), nameof(col.TokensColumn), "Cannot be empty");
                    ch.CheckUserArg(!col.Language.HasValue || Enum.IsDefined(typeof(Language), col.Language),
                        nameof(col.Language), "Value is invalid");

                    namesLen += string.IsNullOrWhiteSpace(col.TypesColumn) && !args.CreateTypesColumn ? 1 : 2;
                }

                int index = 0;
                var names = new string[namesLen];
                var infos = new ColInfo[names.Length];
                var groups = new ColGroupInfo[args.Column.Length];
                for (int i = 0; i < args.Column.Length; i++)
                {
                    var col = args.Column[i];
                    int srcIdx;
                    ColumnType srcType;
                    Bind(input, col.Source, t => t.ItemType.IsText, SrcTypeName, out srcIdx, out srcType, exceptUser);
                    ch.Assert(srcIdx >= 0);

                    int langsColIdx;
                    string langsCol = !string.IsNullOrWhiteSpace(col.LanguagesColumn)
                        ? col.LanguagesColumn
                        : args.LanguagesColumn;
                    if (!string.IsNullOrWhiteSpace(langsCol))
                    {
                        ColumnType langsColType;
                        Bind(input, langsCol, t => t.IsText, LangTypeName, out langsColIdx, out langsColType, exceptUser);
                        ch.Assert(langsColIdx >= 0);
                    }
                    else
                    {
                        langsCol = null;
                        langsColIdx = -1;
                    }

                    var lang = col.Language ?? args.Language;
                    bool requireTypes = !string.IsNullOrWhiteSpace(col.TypesColumn) || args.CreateTypesColumn;

                    groups[i] = new ColGroupInfo(lang, srcIdx, col.Source, srcType, langsColIdx, langsCol, requireTypes);
                    names[index] = col.TokensColumn;
                    infos[index++] = new ColInfo(i);
                    if (requireTypes)
                    {
                        names[index] = !string.IsNullOrWhiteSpace(col.TypesColumn) ? col.TypesColumn
                            : string.Format("{0}_Tokens", col.Source);
                        infos[index++] = new ColInfo(i, isTypes: true);
                    }
                }
                ch.Assert(index == namesLen);

                return new Bindings(groups, infos.ToArray(), input, exceptUser, names.ToArray());
            }