Информация об изменениях

Сообщение Re: Ширина кода - газетная vs книжная от 12.01.2025 14:53

Изменено 12.01.2025 15:20 swame

Re: Ширина кода - газетная vs книжная
Здравствуйте, Shmj, Вы писали:

S>Вот, по умолчанию в той же Idea — около 75 символов. По сути это газетная строка или близко к ней.


S>А ведь можно было сделать длинным? Ну хотя бы 150-200 символов. И читать код как книгу. Тем более мониторы то расширяются.


S>Не пробовали? Что лучше? Сколько символов ставите?


А вы код только пишете и читаете, или все-таки иногда отлаживаете и запускаете?
У меня стоит дефолт 100 символов. Но такая ширина используется в основном только для заголовков методов со строковыми параметрами и текстовыми строками.
Там где код, обычно длина не более 40-60 символов.

я отлаживаю код.
1. В длинные выражения в одну строку не поставить точку останова, не зайти отладчиком.
Ну или это если у кого вдруг это отладчик позволяет, то неудобно.
2. Промежуточные вычисления я часто сохраняю в локальные переменные, чтобы можно было посмотреть отладчиком . Это не качается тривиальных, но длинных выражений.
Код в результате оказывается внезапно короче, потому что присвоенное в 1 месте переменная используется вместо повторяющихся в одном методе цепочек.
3. Короткий строки кода лучше мерджится гитом в случае, если правили одно место, и легче руками разрешаются конфликты.
4. В Коротких строках легче находить повторения и выносить в отдельные методы.

Вот пример кода другого разработчика который я недавно переформатировал. Какой из вариантов готов к дальнейшему расширению?
  Было
procedure TRestKModelTerminals.Add(const aVertex: Integer; aValues: TStringArray; var aData: ARColumn;
  const aInfo: RKModelInfo; const aInput: TRestInput);
var
  modelState: TKModel2State;
  island: RIsland;
  rowIndex: Integer;
  value: String;
  values: TStringArray;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  column: Integer;
  uri: TURI;
begin
  modelState := aInfo.Model.LastModel;
  island := modelState.Islands.Islands[modelState.IslandNumByVertex(aVertex)];
  terminalInfo := modelState.Graph.GetTerminalInfo(aVertex);
  for column := 0 to length(aValues) - 1 do
  begin
    case column of
      0 {vertex}: value := aVertex.ToString();
      1 {terminal}: value := modelState.Graph.TerminalByVertex(aVertex).index.ToString();
      2 {key}: value := terminalInfo.key;
      3 {island}: value := terminalInfo.Island.ToString();
      4 {isUnderVoltage}: value := BoolToStr(island.UnderVoltage, AInput.ContentType);
      5 {state}: value := '';
      6 {checkPoint}: value := '';
      7 {updateTime}: value := TimeToStr(island.TmStUpdate);
      8 {oppositeTerminals}: value := 'Opposite terminals';
    end;
    aValues[column] := value;
  end;

  rowIndex := aData.AddRow(aValues);

  for column := 0 to length(aValues) - 1 do
  begin
    case column of
      8 {oppositeTerminals}:
        begin
          uri :=  GetUrlHead(TableUseHttps);
          uri.Path := joinStr(['documents', AInput.DocUID.ToString(), 'kmodel-terminals'],'/');
          uri.AddParameter('oppositeFor', aVertex.ToString);
          aData.Links [column, rowIndex] := TIdURI.URLEncode (URI.ToString);
        end;
    end;
  end;

  if AInput.ContentType = ctForm then
    addIcon(aData, rowIndex, aInfo, modelState.Graph.TerminalByVertex(aVertex));
end;

function TRestKModelTerminals.Get(const AInput: TRestInput): ARColumn;
var
  model: TKModel2State;
  info: RKModelInfo;
  fieldsId: TIntArray;
  data: ARColumn;
  values: TStringArray;
  vertex: Integer;
  params: RKModelParams;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  edges, nodeEdges: RSEdges;
  island: RIsland;
  i, j: Integer;
  stat: TServiceStat;
begin
  Result.Clear;
  model := CurrentModel(AInput).LastModel;
  if not Assigned(model) then exit;
  info := CurrentModelInfo(AInput);

//  TMonitor.Enter(model);
  try
    stat := TServiceStat.Create('');
    stat.Start();

    data.Clear;
    fieldsId := Fields_.FindFields(AInput.fields);
    if AInput.ContentType <> ctForm then
    begin
      fieldsId.DeleteValue(8);
    end;

//    Det := AInput.Detailing;
//    if AInput.fields.Count = 0 then begin
//      case Det of
//        tdLow   : SetLength(fa, 7);
//        tdMedium: SetLength(fa, 9);
//      end;
//    end;
    values := Fields_.ColumnsText.PickByNumber(fieldsId);
    data.ColumnsText(values);
    Fields_.AssignFieldsProps(data);

    PrepareParams (AInput, params);
    if params.OppositeFor >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.OppositeFor);
      for i := 0 to edges.Count - 1 do
        if model.Graph.TerminalByVertex(edges[i].ToVertex).id >= 0 then
          Add(edges[i].ToVertex, values, data, info, AInput);
      edges.Free();
    end
    else
    if params.ConnectedFor >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.ConnectedFor);
      for i := 0 to edges.Count - 1 do
      begin
        if model.Graph.TerminalByVertex(edges[i].ToVertex).id < 0 then
        begin
          nodeEdges := model.Graph.SGraph.edgesFrom(edges[i].ToVertex);

          for j := 0 to nodeEdges.Count - 1 do
            if nodeEdges[j].ToVertex <> params.ConnectedFor then
              Add(nodeEdges[j].ToVertex, values, data, info, AInput);

          nodeEdges.Free();
        end;
      end;
      edges.Free();
    end
    else
    if params.Vertex >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.Vertex);
      for i := 0 to edges.Count - 1 do
        Add(edges[i].ToVertex, values, data, info, AInput);
    end
    else
      for vertex := 0 to model.Graph.SGraph.VerticesCount - 1 do
      begin
        terminal := model.Graph.TerminalByVertex(vertex);
        terminalInfo := model.Graph.GetTerminalInfo(vertex);
        island := model.Islands.Islands[model.IslandNumByVertex(vertex)];
        if terminal.id < 0 then continue;
        if (params.IslandIndex >= 0) and (terminalInfo.Island <> params.IslandIndex) then continue;
        if island.TmStUpdate < params.StartTime then continue;

        Add(vertex, values, data, info, AInput);
      end;
  finally
    stat.Stop();
    FStat.SummStat(stat);
//    TMonitor.Exit(model);
    Result := data;
  end;
end;



  Стало

type
  RRowContext = record
    model: TKModel2State;
    ModelState: TKModel2State;
    Vertex: Integer;
    Values: TStringArray;
    aData: ARColumn;
    Info: RKModelInfo;
    AInput: TRestInput;
    procedure Clear;
  end;


function TRestKModelTerminals.GetValue(index: Integer; const RC: RRowContext;
  const Island: RIsland; const terminalInfo: RTerminalInfo): string;
begin
  case index of
    0 {vertex}:   Result := RC.Vertex.ToString;
    1 {terminal}: Result := RC.modelState.Graph.TerminalByVertex(RC.Vertex).index.ToString;
    2 {key}:      Result := terminalInfo.key;
    3 {island}:   Result := terminalInfo.Island.ToString;
    4 {isUnderVoltage}: Result := BoolToStr(island.UnderVoltage, RC.AInput.ContentType);
    5 {state}:          Result := '';
    6 {checkPoint}:     Result := '';
    7 {updateTime}:     Result := {TimeToStr} DateToISO8601(island.TmStUpdate);
    8 {oppositeTerminals}: Result := 'Opposite terminals';
  else
    Assert (false);
  end;
end;

procedure TRestKModelTerminals.Add(const RC: RRowContext);
var
  island: RIsland;
  rowIndex: Integer;
  terminalInfo: RTerminalInfo;
  c: Integer;
  uri: TURI;
begin
  island := RC.modelState.Islands.Islands[RC.modelState.IslandNumByVertex(RC.Vertex)];
  terminalInfo := RC.modelState.Graph.GetTerminalInfo(RC.Vertex);

  for c := 0 to length(RC.Values) - 1 do
    RC.Values[c] := GetValue(c, RC, Island, terminalInfo);

  rowIndex := RC.aData.AddRow(RC.Values);

  c := RC.aData.FindColumn('oppositeTerminals');
  if c >= 0 then begin
    {oppositeTerminals}
    uri :=  GetUrlHead(TableUseHttps);
    uri.Path := joinStr(['documents', RC.AInput.DocUID.ToString, 'kmodel-terminals'],'/');
    uri.AddParameter('oppositeFor', RC.Vertex.ToString);
    RC.aData.Links [c, rowIndex] := TIdURI.URLEncode (URI.ToString);
  end;

  if RC.AInput.ContentType = ctForm then
    addIcon(RC.aData, rowIndex, RC.Info, RC.modelState.Graph.TerminalByVertex(RC.Vertex));
end;

procedure TRestKModelTerminals.Get_OppositeFor (var RC: RRowContext; aFromT: integer);
var
  edges: RSEdges;
  i, v: Integer;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  edges := G.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    v := edges[i].ToVertex;
    if G.TerminalByVertex(v).id < 0 then continue;
    RC.Vertex := v;
    Add(RC);
  end;
  edges.Free;
end;

procedure TRestKModelTerminals.Get_ConnectorFor (var RC: RRowContext; aFromT: integer);
var
  edges, nodeEdges: RSEdges;
  i, j, nv, v: Integer;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  edges :=  G.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    v := edges[i].ToVertex;
    if G.TerminalByVertex(v).id >= 0 then continue;
    nodeEdges := G.SGraph.edgesFrom(v);
    for j := 0 to nodeEdges.Count - 1 do begin
      nv := nodeEdges[j].ToVertex;
      if nv = aFromT then continue;
      RC.Vertex := nv;
      Add(RC);
    end;
    nodeEdges.Free;
  end;
  edges.Free;
end;

procedure TRestKModelTerminals.Get_Vertex (var RC: RRowContext; aFromT: integer);
var
  edges: RSEdges;
  i, v: Integer;
begin
  edges :=  RC.model.Graph.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    RC.Vertex := edges[i].ToVertex;
    Add(RC);
  end;
end;

procedure TRestKModelTerminals.Get_All (var RC: RRowContext; aIslandIndex: integer);
var
  v: Integer;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  island: RIsland;
  params: RKModelParams;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  PrepareParams (RC.AInput, params);
  for v := 0 to G.SGraph.VerticesCount - 1 do begin
    terminal := G.TerminalByVertex(v);
    terminalInfo := G.GetTerminalInfo(v);
    island := RC.model.Islands.Islands[RC.model.IslandNumByVertex(v)];
    if terminal.id < 0 then continue;
    if (aIslandIndex >= 0) and (terminalInfo.Island <> params.IslandIndex) then continue;
    if island.TmStUpdate < params.StartTime then continue;
    RC.Vertex := v;
    Add(RC);
  end;
end;

function TRestKModelTerminals.Get(AInput: TRestInput): ARColumn;
var
  RC: RRowContext;
  KModel:  TKModel2;
  fieldsId: TIntArray;
  params: RKModelParams;
  stat: TServiceStat;
begin
  Result.Clear;
  RC.Clear;
  KModel := CurrentModel(AInput);
  if KModel = nil then exit;

  RC.model := KModel.LastModel;
  if not Assigned(RC.model) then exit;
  RC.info :=  KModelServerData.ModelInfoByModel(KModel);
  RC.modelState := RC.Info.Model.LastModel;
  try
    stat := TServiceStat.Create('');
    stat.Start;

    RC.Adata.Clear;
    RC.AInput := AInput;
    fieldsId := Fields_.FindFields(AInput.fields);
    if AInput.ContentType <> ctForm then
      fieldsId.DeleteValue(8);

    RC.values := Fields_.ColumnsText.PickByNumber(fieldsId);
    RC.Adata.ColumnsText(RC.Values);
    Fields_.AssignFieldsProps(RC.Adata);

    PrepareParams (AInput, params);

    if params.OppositeFor >= 0 then
      Get_OppositeFor (RC, params.OppositeFor)
    else if params.ConnectedFor >= 0 then
      Get_ConnectorFor (RC, params.ConnectedFor)
    else if params.Vertex >= 0 then
      Get_Vertex (RC, params.Vertex)
    else
      Get_All (RC, params.IslandIndex);

  finally
    stat.Stop;
    FStat.SummStat(stat);
    Result := RC.Adata;
  end;
end;
Re: Ширина кода - газетная vs книжная
Здравствуйте, Shmj, Вы писали:

S>Вот, по умолчанию в той же Idea — около 75 символов. По сути это газетная строка или близко к ней.


S>А ведь можно было сделать длинным? Ну хотя бы 150-200 символов. И читать код как книгу. Тем более мониторы то расширяются.


S>Не пробовали? Что лучше? Сколько символов ставите?


А вы код только пишете и читаете, или все-таки иногда отлаживаете и запускаете?
У меня стоит дефолт 100 символов. Но такая ширина используется в основном только для заголовков методов со строковыми параметрами и текстовыми строками.
Там где код, обычно длина не более 40-60 символов.

я отлаживаю код.
1. В длинные выражения в одну строку не поставить точку останова, не зайти отладчиком.
Ну или это если у кого вдруг это отладчик позволяет, то неудобно.
2. Промежуточные вычисления я часто сохраняю в локальные переменные, чтобы можно было посмотреть отладчиком . Это не качается тривиальных, но длинных выражений.
Код в результате оказывается внезапно короче, потому что присвоенное в 1 месте переменная используется вместо повторяющихся в одном методе цепочек.
3. Короткий строки кода лучше мерджится гитом в случае, если правили одно место, и легче руками разрешаются конфликты.
4. В Коротких строках легче находить повторения и выносить в отдельные методы.

В коде я допускаю не больше 3-4 уровней вложенности (циклов, блоков if и т.п ), за счет этого он получается не широкий, больше уровней необходимо выносить в отдельные методы.

Вот пример кода другого разработчика который я недавно переформатировал. Какой из вариантов готов к дальнейшему расширению?
  Было
procedure TRestKModelTerminals.Add(const aVertex: Integer; aValues: TStringArray; var aData: ARColumn;
  const aInfo: RKModelInfo; const aInput: TRestInput);
var
  modelState: TKModel2State;
  island: RIsland;
  rowIndex: Integer;
  value: String;
  values: TStringArray;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  column: Integer;
  uri: TURI;
begin
  modelState := aInfo.Model.LastModel;
  island := modelState.Islands.Islands[modelState.IslandNumByVertex(aVertex)];
  terminalInfo := modelState.Graph.GetTerminalInfo(aVertex);
  for column := 0 to length(aValues) - 1 do
  begin
    case column of
      0 {vertex}: value := aVertex.ToString();
      1 {terminal}: value := modelState.Graph.TerminalByVertex(aVertex).index.ToString();
      2 {key}: value := terminalInfo.key;
      3 {island}: value := terminalInfo.Island.ToString();
      4 {isUnderVoltage}: value := BoolToStr(island.UnderVoltage, AInput.ContentType);
      5 {state}: value := '';
      6 {checkPoint}: value := '';
      7 {updateTime}: value := TimeToStr(island.TmStUpdate);
      8 {oppositeTerminals}: value := 'Opposite terminals';
    end;
    aValues[column] := value;
  end;

  rowIndex := aData.AddRow(aValues);

  for column := 0 to length(aValues) - 1 do
  begin
    case column of
      8 {oppositeTerminals}:
        begin
          uri :=  GetUrlHead(TableUseHttps);
          uri.Path := joinStr(['documents', AInput.DocUID.ToString(), 'kmodel-terminals'],'/');
          uri.AddParameter('oppositeFor', aVertex.ToString);
          aData.Links [column, rowIndex] := TIdURI.URLEncode (URI.ToString);
        end;
    end;
  end;

  if AInput.ContentType = ctForm then
    addIcon(aData, rowIndex, aInfo, modelState.Graph.TerminalByVertex(aVertex));
end;

function TRestKModelTerminals.Get(const AInput: TRestInput): ARColumn;
var
  model: TKModel2State;
  info: RKModelInfo;
  fieldsId: TIntArray;
  data: ARColumn;
  values: TStringArray;
  vertex: Integer;
  params: RKModelParams;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  edges, nodeEdges: RSEdges;
  island: RIsland;
  i, j: Integer;
  stat: TServiceStat;
begin
  Result.Clear;
  model := CurrentModel(AInput).LastModel;
  if not Assigned(model) then exit;
  info := CurrentModelInfo(AInput);

//  TMonitor.Enter(model);
  try
    stat := TServiceStat.Create('');
    stat.Start();

    data.Clear;
    fieldsId := Fields_.FindFields(AInput.fields);
    if AInput.ContentType <> ctForm then
    begin
      fieldsId.DeleteValue(8);
    end;

//    Det := AInput.Detailing;
//    if AInput.fields.Count = 0 then begin
//      case Det of
//        tdLow   : SetLength(fa, 7);
//        tdMedium: SetLength(fa, 9);
//      end;
//    end;
    values := Fields_.ColumnsText.PickByNumber(fieldsId);
    data.ColumnsText(values);
    Fields_.AssignFieldsProps(data);

    PrepareParams (AInput, params);
    if params.OppositeFor >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.OppositeFor);
      for i := 0 to edges.Count - 1 do
        if model.Graph.TerminalByVertex(edges[i].ToVertex).id >= 0 then
          Add(edges[i].ToVertex, values, data, info, AInput);
      edges.Free();
    end
    else
    if params.ConnectedFor >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.ConnectedFor);
      for i := 0 to edges.Count - 1 do
      begin
        if model.Graph.TerminalByVertex(edges[i].ToVertex).id < 0 then
        begin
          nodeEdges := model.Graph.SGraph.edgesFrom(edges[i].ToVertex);

          for j := 0 to nodeEdges.Count - 1 do
            if nodeEdges[j].ToVertex <> params.ConnectedFor then
              Add(nodeEdges[j].ToVertex, values, data, info, AInput);

          nodeEdges.Free();
        end;
      end;
      edges.Free();
    end
    else
    if params.Vertex >= 0 then
    begin
      edges :=  model.Graph.SGraph.edgesFrom(params.Vertex);
      for i := 0 to edges.Count - 1 do
        Add(edges[i].ToVertex, values, data, info, AInput);
    end
    else
      for vertex := 0 to model.Graph.SGraph.VerticesCount - 1 do
      begin
        terminal := model.Graph.TerminalByVertex(vertex);
        terminalInfo := model.Graph.GetTerminalInfo(vertex);
        island := model.Islands.Islands[model.IslandNumByVertex(vertex)];
        if terminal.id < 0 then continue;
        if (params.IslandIndex >= 0) and (terminalInfo.Island <> params.IslandIndex) then continue;
        if island.TmStUpdate < params.StartTime then continue;

        Add(vertex, values, data, info, AInput);
      end;
  finally
    stat.Stop();
    FStat.SummStat(stat);
//    TMonitor.Exit(model);
    Result := data;
  end;
end;



  Стало

type
  RRowContext = record
    model: TKModel2State;
    ModelState: TKModel2State;
    Vertex: Integer;
    Values: TStringArray;
    aData: ARColumn;
    Info: RKModelInfo;
    AInput: TRestInput;
    procedure Clear;
  end;


function TRestKModelTerminals.GetValue(index: Integer; const RC: RRowContext;
  const Island: RIsland; const terminalInfo: RTerminalInfo): string;
begin
  case index of
    0 {vertex}:   Result := RC.Vertex.ToString;
    1 {terminal}: Result := RC.modelState.Graph.TerminalByVertex(RC.Vertex).index.ToString;
    2 {key}:      Result := terminalInfo.key;
    3 {island}:   Result := terminalInfo.Island.ToString;
    4 {isUnderVoltage}: Result := BoolToStr(island.UnderVoltage, RC.AInput.ContentType);
    5 {state}:          Result := '';
    6 {checkPoint}:     Result := '';
    7 {updateTime}:     Result := {TimeToStr} DateToISO8601(island.TmStUpdate);
    8 {oppositeTerminals}: Result := 'Opposite terminals';
  else
    Assert (false);
  end;
end;

procedure TRestKModelTerminals.Add(const RC: RRowContext);
var
  island: RIsland;
  rowIndex: Integer;
  terminalInfo: RTerminalInfo;
  c: Integer;
  uri: TURI;
begin
  island := RC.modelState.Islands.Islands[RC.modelState.IslandNumByVertex(RC.Vertex)];
  terminalInfo := RC.modelState.Graph.GetTerminalInfo(RC.Vertex);

  for c := 0 to length(RC.Values) - 1 do
    RC.Values[c] := GetValue(c, RC, Island, terminalInfo);

  rowIndex := RC.aData.AddRow(RC.Values);

  c := RC.aData.FindColumn('oppositeTerminals');
  if c >= 0 then begin
    {oppositeTerminals}
    uri :=  GetUrlHead(TableUseHttps);
    uri.Path := joinStr(['documents', RC.AInput.DocUID.ToString, 'kmodel-terminals'],'/');
    uri.AddParameter('oppositeFor', RC.Vertex.ToString);
    RC.aData.Links [c, rowIndex] := TIdURI.URLEncode (URI.ToString);
  end;

  if RC.AInput.ContentType = ctForm then
    addIcon(RC.aData, rowIndex, RC.Info, RC.modelState.Graph.TerminalByVertex(RC.Vertex));
end;

procedure TRestKModelTerminals.Get_OppositeFor (var RC: RRowContext; aFromT: integer);
var
  edges: RSEdges;
  i, v: Integer;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  edges := G.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    v := edges[i].ToVertex;
    if G.TerminalByVertex(v).id < 0 then continue;
    RC.Vertex := v;
    Add(RC);
  end;
  edges.Free;
end;

procedure TRestKModelTerminals.Get_ConnectorFor (var RC: RRowContext; aFromT: integer);
var
  edges, nodeEdges: RSEdges;
  i, j, nv, v: Integer;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  edges :=  G.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    v := edges[i].ToVertex;
    if G.TerminalByVertex(v).id >= 0 then continue;
    nodeEdges := G.SGraph.edgesFrom(v);
    for j := 0 to nodeEdges.Count - 1 do begin
      nv := nodeEdges[j].ToVertex;
      if nv = aFromT then continue;
      RC.Vertex := nv;
      Add(RC);
    end;
    nodeEdges.Free;
  end;
  edges.Free;
end;

procedure TRestKModelTerminals.Get_Vertex (var RC: RRowContext; aFromT: integer);
var
  edges: RSEdges;
  i, v: Integer;
begin
  edges :=  RC.model.Graph.SGraph.edgesFrom(aFromT);
  for i := 0 to edges.Count - 1 do begin
    RC.Vertex := edges[i].ToVertex;
    Add(RC);
  end;
end;

procedure TRestKModelTerminals.Get_All (var RC: RRowContext; aIslandIndex: integer);
var
  v: Integer;
  terminal: RTerminal;
  terminalInfo: RTerminalInfo;
  island: RIsland;
  params: RKModelParams;
  G: TKModelGraph;
begin
  G := RC.model.Graph;
  PrepareParams (RC.AInput, params);
  for v := 0 to G.SGraph.VerticesCount - 1 do begin
    terminal := G.TerminalByVertex(v);
    terminalInfo := G.GetTerminalInfo(v);
    island := RC.model.Islands.Islands[RC.model.IslandNumByVertex(v)];
    if terminal.id < 0 then continue;
    if (aIslandIndex >= 0) and (terminalInfo.Island <> params.IslandIndex) then continue;
    if island.TmStUpdate < params.StartTime then continue;
    RC.Vertex := v;
    Add(RC);
  end;
end;

function TRestKModelTerminals.Get(AInput: TRestInput): ARColumn;
var
  RC: RRowContext;
  KModel:  TKModel2;
  fieldsId: TIntArray;
  params: RKModelParams;
  stat: TServiceStat;
begin
  Result.Clear;
  RC.Clear;
  KModel := CurrentModel(AInput);
  if KModel = nil then exit;

  RC.model := KModel.LastModel;
  if not Assigned(RC.model) then exit;
  RC.info :=  KModelServerData.ModelInfoByModel(KModel);
  RC.modelState := RC.Info.Model.LastModel;
  try
    stat := TServiceStat.Create('');
    stat.Start;

    RC.Adata.Clear;
    RC.AInput := AInput;
    fieldsId := Fields_.FindFields(AInput.fields);
    if AInput.ContentType <> ctForm then
      fieldsId.DeleteValue(8);

    RC.values := Fields_.ColumnsText.PickByNumber(fieldsId);
    RC.Adata.ColumnsText(RC.Values);
    Fields_.AssignFieldsProps(RC.Adata);

    PrepareParams (AInput, params);

    if params.OppositeFor >= 0 then
      Get_OppositeFor (RC, params.OppositeFor)
    else if params.ConnectedFor >= 0 then
      Get_ConnectorFor (RC, params.ConnectedFor)
    else if params.Vertex >= 0 then
      Get_Vertex (RC, params.Vertex)
    else
      Get_All (RC, params.IslandIndex);

  finally
    stat.Stop;
    FStat.SummStat(stat);
    Result := RC.Adata;
  end;
end;