text:
package com.sksamuel.elastic4s.requests.mappings

import com.sksamuel.exts.OptionImplicits._

case class RangeField(name: String,
                      `type`: String,
                      analysis: Analysis = Analysis(),
                      boost: Option[Double] = None,
                      coerce: Option[Boolean] = None,
                      copyTo: Seq[String] = Nil,
                      docValues: Option[Boolean] = None,
                      enabled: Option[Boolean] = None,
                      fields: Seq[FieldDefinition] = Nil,
                      format: Option[String] = None,
                      includeInAll: Option[Boolean] = None,
                      ignoreAbove: Option[Int] = None,
                      ignoreMalformed: Option[Boolean] = None,
                      index: Option[String] = None,
                      indexOptions: Option[String] = None,
                      norms: Option[Boolean] = None,
                      nulls: Nulls = Nulls(),
                      scalingFactor: Option[Double] = None,
                      similarity: Option[String] = None,
                      store: Option[Boolean] = None,
                      termVector: Option[String] = None)
    extends FieldDefinition {

  type T = RangeField

  override def analyzer(analyzer: String): T       = copy(analysis = analysis.copy(analyzer = analyzer.some))
  override def normalizer(normalizer: String): T   = copy(analysis = analysis.copy(normalizer = normalizer.some))
  override def searchAnalyzer(analyzer: String): T = copy(analysis = analysis.copy(searchAnalyzer = analyzer.some))

  override def boost(boost: Double): T          = copy(boost = boost.some)
  override def docValues(docValues: Boolean): T = copy(docValues = docValues.some)

  override def fields(fields: Iterable[FieldDefinition]): T = copy(fields = fields.toSeq)

  def coerce(coerce: Boolean): T                       = copy(coerce = coerce.some)
  override def copyTo(first: String, rest: String*): T = copyTo(first +: rest)
  override def copyTo(copyTo: Iterable[String]): T     = copy(copyTo = copyTo.toSeq)

  override def enabled(enabled: Boolean): T = copy(enabled = enabled.some)

  def format(format: String): T = copy(format = format.some)

  def scalingFactor(scalingFactor: Double): T = copy(scalingFactor = scalingFactor.some)

  def similarity(similarity: String): T = copy(similarity = similarity.some)

  def ignoreAbove(ignoreAbove: Int): T                = copy(ignoreAbove = ignoreAbove.some)
  def ignoreMalformed(ignoreMalformed: Boolean): T    = copy(ignoreMalformed = ignoreMalformed.some)
  override def includeInAll(includeInAll: Boolean): T = copy(includeInAll = includeInAll.some)

  override def index(index: Boolean): T = copy(index = index.toString.some)
  def index(index: String): T = {
    require(`type` == "string")
    copy(index = index.some)
  }

  override def norms(norms: Boolean): T       = copy(norms = norms.some)
  override def nullable(nullable: Boolean): T = copy(nulls = nulls.copy(nullable = nullable.some))
  override def nullValue(nullvalue: Any): T   = copy(nulls = nulls.copy(nullValue = nullvalue.some))

  override def store(b: Boolean): T = copy(store = b.some)

  override def termVector(t: String): T = copy(termVector = t.some)
}


text:
import { EventAggregator, Subscription } from 'aurelia-event-aggregator';
import { User, UserManager } from 'oidc-client';
export declare class OidcEvents {
    private userManager;
    private ea;
    private readonly USER_LOADED;
    private readonly USER_UNLOADED;
    private readonly USER_SIGNED_OUT;
    private readonly ACCESS_TOKEN_EXPIRING;
    private readonly SILENT_RENEW_ERROR;
    constructor(userManager: UserManager, ea: EventAggregator);
    onUserLoaded(callback: (user?: User) => any): Subscription;
    onUserUnloaded(callback: () => any): Subscription;
    onUserSignedOut(callback: () => any): Subscription;
    onAccessTokenExpiring(callback: () => any): Subscription;
    onSilentRenewError(callback: (err?: Error) => any): Subscription;
}

redpajama_set_name: RedPajamaGithub


text:
<ng-template #alertcontainer let-modal>

{{'error.modal.title'|translate}}

        <button type="button" class="close alert" aria-label="{{'modal.close'|translate}}" (click)="modal.dismiss('Cross click')">
            ×
        </button>

{{'error.modal.info'|translate}}

{{message.message}}

        <button type="button" class="btn btn-danger" (click)="modal.close('Save click')">{{'modal.close'|translate}}</button>

</ng-template>
<app-toasts aria-live="polite" aria-atomic="true"></app-toasts>

            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsDefault"
                    aria-controls="navbarsDefault" aria-expanded="false" aria-label="Toggle Navigation">

            </button>

                                {{user.userInfo.full_name}}

                                {{ 'menu.home' |translate }}

                                {{'menu.login' | translate}}

                                {{'menu.logout' | translate}}

                                  English
                                  German

                                {{'menu.about' | translate}}

                                {{ 'menu.contact' | translate }}

            <router-outlet></router-outlet>

© 2020 - archiva.apache.org


text:
package org.opengroup.osdu.workflow.provider.gcp.repository;

import static org.assertj.core.api.Assertions.catchThrowable;
import static org.assertj.core.api.BDDAssertions.then;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.opengroup.osdu.workflow.model.WorkflowStatus.Fields.SUBMITTED_AT;

import java.util.Date;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mapstruct.factory.Mappers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.workflow.ReplaceCamelCase;
import org.opengroup.osdu.workflow.model.WorkflowStatus;
import org.opengroup.osdu.workflow.model.WorkflowStatusType;
import org.opengroup.osdu.workflow.provider.gcp.exception.WorkflowStatusNotFoundException;
import org.opengroup.osdu.workflow.provider.gcp.exception.WorkflowStatusNotUpdatedException;
import org.opengroup.osdu.workflow.provider.gcp.mapper.EnumMapper;
import org.opengroup.osdu.workflow.provider.gcp.mapper.IWorkflowStatusMapper;
import org.opengroup.osdu.workflow.provider.gcp.model.WorkflowStatusEntity;
import org.opengroup.osdu.workflow.provider.interfaces.IWorkflowStatusRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.test.util.ReflectionTestUtils;

@ExtendWith(MockitoExtension.class)
@DisplayNameGeneration(ReplaceCamelCase.class)
class DatastoreWorkflowStatusRepositoryTest {

  private static final String TEST_WORKFLOW_ID = "test-workflow-id";
  private static final String TEST_AIRFLOW_RUN_ID = "test-airflow-run-id";
  private static final String USER = "user-1";

  @Spy
  private IWorkflowStatusMapper workflowStatusMapper = Mappers.getMapper(IWorkflowStatusMapper.class);
  @Mock
  private IWorkflowStatusEntityRepository workflowStatusEntityRepository;

  private IWorkflowStatusRepository workflowStatusRepository;

  @BeforeEach
  void setUp() {
    EnumMapper enumMapper = new EnumMapper();
    ReflectionTestUtils.setField(workflowStatusMapper, "enumMapper", enumMapper);

    workflowStatusRepository = new DatastoreWorkflowStatusRepository(workflowStatusMapper,
        workflowStatusEntityRepository);
  }

  @Nested
  class FindWorkflowStatus {

    @Test
    void shouldFindWorkflowStatusByWorkflowId() {

      // given
      Date createdDate = new Date();

      given(workflowStatusEntityRepository.findByWorkflowId(TEST_WORKFLOW_ID))
          .willReturn(getWorkflowStatusEntity(createdDate));

      // when
      WorkflowStatus workflowStatus = workflowStatusRepository
          .findWorkflowStatus(TEST_WORKFLOW_ID);

      // then
      then(workflowStatus).isEqualTo(getWorkflowStatus(createdDate));
    }

  }

  @Nested
  class SaveWorkflowStatus {

    @Captor
    private ArgumentCaptor<WorkflowStatusEntity> entityCaptor;

    @Test
    void shouldSaveWorkflowStatusAndReturnSavedEntity() {
      // given
      Date createdDate = new Date();
      WorkflowStatus workflowStatus = getWorkflowStatus(createdDate);

      given(workflowStatusEntityRepository.save(any(WorkflowStatusEntity.class)))
          .willAnswer(DatastoreWorkflowStatusRepositoryTest.this::copyWorkflowStatusEntity);

      // when
      WorkflowStatus saved = workflowStatusRepository.saveWorkflowStatus(workflowStatus);

      // then
      then(saved).isEqualTo(workflowStatus);

      InOrder inOrder = Mockito.inOrder(workflowStatusEntityRepository, workflowStatusMapper);
      inOrder.verify(workflowStatusEntityRepository).save(any(WorkflowStatusEntity.class));
      inOrder.verify(workflowStatusMapper).toWorkflowStatus(any(WorkflowStatusEntity.class));
      inOrder.verifyNoMoreInteractions();
    }

    @Test
    void shouldUseServerTimestampWhenCreateAtIsNotSpecified() {
      // given
      WorkflowStatus workflowStatus = WorkflowStatus.builder()
          .workflowId(TEST_WORKFLOW_ID)
          .airflowRunId(TEST_AIRFLOW_RUN_ID)
          .workflowStatusType(WorkflowStatusType.SUBMITTED)
          .submittedBy(USER)
          .build();

      given(workflowStatusEntityRepository.save(any(WorkflowStatusEntity.class)))
          .willAnswer(DatastoreWorkflowStatusRepositoryTest.this::copyWorkflowStatusEntity);

      // when
      WorkflowStatus saved = workflowStatusRepository.saveWorkflowStatus(workflowStatus);

      // then
      then(saved).isEqualToIgnoringGivenFields(saved, SUBMITTED_AT);
      then(saved.getSubmittedAt()).isBefore(new Date());

      InOrder inOrder = Mockito.inOrder(workflowStatusEntityRepository, workflowStatusMapper);
      inOrder.verify(workflowStatusEntityRepository).save(any(WorkflowStatusEntity.class));
      inOrder.verify(workflowStatusMapper).toWorkflowStatus(any(WorkflowStatusEntity.class));
      inOrder.verifyNoMoreInteractions();

    }

  }

  @Nested
  class UpdateWorkflowStatus {

    @Test
    void shouldUpdateWorkflowStatusAndReturnSavedEntity() {
      // given
      Date createdDate = new Date();

      given(workflowStatusEntityRepository.findByWorkflowId(TEST_WORKFLOW_ID))
          .willReturn(getWorkflowStatusEntity(createdDate));
      given(workflowStatusEntityRepository.save(any(WorkflowStatusEntity.class)))
          .willAnswer(DatastoreWorkflowStatusRepositoryTest.this::copyWorkflowStatusEntity);

      // when
      WorkflowStatus saved = workflowStatusRepository
          .updateWorkflowStatus(TEST_WORKFLOW_ID, WorkflowStatusType.RUNNING);

      // then
      then(saved.getWorkflowStatusType()).isEqualTo(WorkflowStatusType.RUNNING);
      then(saved.getWorkflowId()).isEqualTo(TEST_WORKFLOW_ID);

      InOrder inOrder = Mockito.inOrder(workflowStatusEntityRepository, workflowStatusMapper);
      inOrder.verify(workflowStatusEntityRepository).findByWorkflowId(TEST_WORKFLOW_ID);
      inOrder.verify(workflowStatusEntityRepository).save(any(WorkflowStatusEntity.class));
      inOrder.verify(workflowStatusMapper).toWorkflowStatus(any(WorkflowStatusEntity.class));
      inOrder.verifyNoMoreInteractions();
    }

    @Test
    void shouldThrowExceptionWhenNothingWasFound() {
      // when
      Throwable thrown = catchThrowable(() -> workflowStatusRepository
          .updateWorkflowStatus(TEST_WORKFLOW_ID, WorkflowStatusType.RUNNING));

      // then
      // then
      then(thrown)
          .isInstanceOf(WorkflowStatusNotFoundException.class)
          .hasMessage("Workflow status for Workflow id: test-workflow-id not found");

      InOrder inOrder = Mockito.inOrder(workflowStatusEntityRepository, workflowStatusMapper);
      inOrder.verify(workflowStatusEntityRepository).findByWorkflowId(TEST_WORKFLOW_ID);
      inOrder.verifyNoMoreInteractions();
    }

    @Test
    void shouldThrowExceptionIfWorkflowHasAlreadyDefinedStatus() {
      // given
      Date createdDate = new Date();
      given(workflowStatusEntityRepository.findByWorkflowId(TEST_WORKFLOW_ID))
          .willReturn(getWorkflowStatusEntity(createdDate));

      // when
      Throwable thrown = catchThrowable(() -> workflowStatusRepository.updateWorkflowStatus(
          TEST_WORKFLOW_ID, WorkflowStatusType.SUBMITTED));

      // then
      then(thrown)
          .isInstanceOf(WorkflowStatusNotUpdatedException.class)
          .hasMessage(
              "Workflow status for workflow id: test-workflow-id already has status:SUBMITTED and can not be updated");

      InOrder inOrder = Mockito.inOrder(workflowStatusEntityRepository, workflowStatusMapper);
      inOrder.verify(workflowStatusEntityRepository).findByWorkflowId(TEST_WORKFLOW_ID);
      inOrder.verifyNoMoreInteractions();
    }

  }

  private WorkflowStatusEntity getWorkflowStatusEntity(Date createdDate) {
    return WorkflowStatusEntity.builder()
        .workflowId(TEST_WORKFLOW_ID)
        .airflowRunId(TEST_AIRFLOW_RUN_ID)
        .workflowStatusType(WorkflowStatusType.SUBMITTED.name())
        .submittedAt(createdDate)
        .submittedBy(USER)
        .build();
  }

  private WorkflowStatus getWorkflowStatus(Date createdDate) {
    return WorkflowStatus.builder()
        .workflowId(TEST_WORKFLOW_ID)
        .airflowRunId(TEST_AIRFLOW_RUN_ID)
        .workflowStatusType(WorkflowStatusType.SUBMITTED)
        .submittedAt(createdDate)
        .submittedBy(USER)
        .build();
  }

  private WorkflowStatusEntity copyWorkflowStatusEntity(InvocationOnMock invocation) {
    WorkflowStatusEntity saved = invocation.getArgument(0);
    WorkflowStatusEntity copied = new WorkflowStatusEntity();
    BeanUtils.copyProperties(saved, copied);
    return copied;
  }

}


text:
package io.dropwizard.util;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableMap;

import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

public class Size implements Comparable<Size> {
    private static final Pattern SIZE_PATTERN = Pattern.compile("(\\d+)\\s*(\\S+)");

    private static final Map<String, SizeUnit> SUFFIXES = new ImmutableMap.Builder<String, SizeUnit>()
            .put("B", SizeUnit.BYTES)
            .put("byte", SizeUnit.BYTES)
            .put("bytes", SizeUnit.BYTES)
            .put("KB", SizeUnit.KILOBYTES)
            .put("KiB", SizeUnit.KILOBYTES)
            .put("kilobyte", SizeUnit.KILOBYTES)
            .put("kilobytes", SizeUnit.KILOBYTES)
            .put("MB", SizeUnit.MEGABYTES)
            .put("MiB", SizeUnit.MEGABYTES)
            .put("megabyte", SizeUnit.MEGABYTES)
            .put("megabytes", SizeUnit.MEGABYTES)
            .put("GB", SizeUnit.GIGABYTES)
            .put("GiB", SizeUnit.GIGABYTES)
            .put("gigabyte", SizeUnit.GIGABYTES)
            .put("gigabytes", SizeUnit.GIGABYTES)
            .put("TB", SizeUnit.TERABYTES)
            .put("TiB", SizeUnit.TERABYTES)
            .put("terabyte", SizeUnit.TERABYTES)
            .put("terabytes", SizeUnit.TERABYTES)
            .build();

    public static Size bytes(long count) {
        return new Size(count, SizeUnit.BYTES);
    }

    public static Size kilobytes(long count) {
        return new Size(count, SizeUnit.KILOBYTES);
    }

    public static Size megabytes(long count) {
        return new Size(count, SizeUnit.MEGABYTES);
    }

    public static Size gigabytes(long count) {
        return new Size(count, SizeUnit.GIGABYTES);
    }

    public static Size terabytes(long count) {
        return new Size(count, SizeUnit.TERABYTES);
    }

    @JsonCreator
    public static Size parse(String size) {
        final Matcher matcher = SIZE_PATTERN.matcher(size);
        checkArgument(matcher.matches(), "Invalid size: " + size);

        final long count = Long.parseLong(matcher.group(1));
        final SizeUnit unit = SUFFIXES.get(matcher.group(2));
        if (unit == null) {
            throw new IllegalArgumentException("Invalid size: " + size + ". Wrong size unit");
        }

        return new Size(count, unit);
    }

    private final long count;
    private final SizeUnit unit;

    private Size(long count, SizeUnit unit) {
        this.count = count;
        this.unit = requireNonNull(unit);
    }

    public long getQuantity() {
        return count;
    }

    public SizeUnit getUnit() {
        return unit;
    }

    public long toBytes() {
        return SizeUnit.BYTES.convert(count, unit);
    }

    public long toKilobytes() {
        return SizeUnit.KILOBYTES.convert(count, unit);
    }

    public long toMegabytes() {
        return SizeUnit.MEGABYTES.convert(count, unit);
    }

    public long toGigabytes() {
        return SizeUnit.GIGABYTES.convert(count, unit);
    }

    public long toTerabytes() {
        return SizeUnit.TERABYTES.convert(count, unit);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if ((obj == null) || (getClass() != obj.getClass())) {
            return false;
        }
        final Size size = (Size) obj;
        return (count == size.count) && (unit == size.unit);
    }

    @Override
    public int hashCode() {
        return (31 * (int) (count ^ (count >>> 32))) + unit.hashCode();
    }

    @Override
    @JsonValue
    public String toString() {
        String units = unit.toString().toLowerCase(Locale.ENGLISH);
        if (count == 1) {
            units = units.substring(0, units.length() - 1);
        }
        return Long.toString(count) + ' ' + units;
    }

    @Override
    public int compareTo(Size other) {
        if (unit == other.unit) {
            return Long.compare(count, other.count);
        }

        return Long.compare(toBytes(), other.toBytes());
    }
}


text:
layout: redirect
permalink: /blog/2013/07/11/software-licensing-models-personal-node-locked
redirect_to: /blog/2013/07/11/software-licensing-models-personal-node-locked/
sitemap:
  exclude: true
---


text:
<?php

namespace Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20170513093641 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('CREATE TABLE anexo_downloads (id INT AUTO_INCREMENT NOT NULL, usuario_id INT DEFAULT NULL, anexo_id INT DEFAULT NULL, INDEX IDX_7C83D622DB38439E (usuario_id), INDEX IDX_7C83D622C9348664 (anexo_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE grupo_usuarios (id INT AUTO_INCREMENT NOT NULL, grupo_id INT DEFAULT NULL, usuario_id INT DEFAULT NULL, INDEX IDX_461BB8379C833003 (grupo_id), INDEX IDX_461BB837DB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE sugestao_resposta (id INT AUTO_INCREMENT NOT NULL, sugestao_id INT DEFAULT NULL, usuario_id INT DEFAULT NULL, mensagem VARCHAR(255) NOT NULL, enviada_em DATETIME DEFAULT NULL, INDEX IDX_B11B25F4AF0AA99B (sugestao_id), INDEX IDX_B11B25F4DB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE sugestao (id INT AUTO_INCREMENT NOT NULL, usuario_id INT DEFAULT NULL, mensagem VARCHAR(255) NOT NULL, enviada_em DATETIME DEFAULT NULL, respondida TINYINT(1) NOT NULL, INDEX IDX_36179898DB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE grupo (id INT AUTO_INCREMENT NOT NULL, nome VARCHAR(255) NOT NULL, cidade VARCHAR(255) NOT NULL, uf VARCHAR(30) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE grupo_musicas (id INT AUTO_INCREMENT NOT NULL, grupo_id INT DEFAULT NULL, musica_id INT DEFAULT NULL, INDEX IDX_74CCCD019C833003 (grupo_id), INDEX IDX_74CCCD0199E6F854 (musica_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE emails_enviados (id INT AUTO_INCREMENT NOT NULL, usuario_id INT DEFAULT NULL, mensagem LONGTEXT NOT NULL, data_hora DATETIME NOT NULL, tipo VARCHAR(255) NOT NULL, INDEX IDX_FC7E208FDB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE login (id INT AUTO_INCREMENT NOT NULL, usuario_id INT DEFAULT NULL, data_login DATETIME NOT NULL, data_logout DATETIME DEFAULT NULL, sessao VARCHAR(50) NOT NULL, INDEX IDX_AA08CB10DB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE cidades (id INT AUTO_INCREMENT NOT NULL, codigo INT NOT NULL, nome VARCHAR(255) NOT NULL, uf SMALLINT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE playlist_musicas (id INT AUTO_INCREMENT NOT NULL, playlist_id INT DEFAULT NULL, musica_id INT DEFAULT NULL, usuario_id INT DEFAULT NULL, cadastro DATETIME NOT NULL, INDEX IDX_94FA54BC6BBD148 (playlist_id), INDEX IDX_94FA54BC99E6F854 (musica_id), INDEX IDX_94FA54BCDB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('CREATE TABLE playlist (id INT AUTO_INCREMENT NOT NULL, usuario_id INT DEFAULT NULL, nome VARCHAR(255) NOT NULL, cadastro DATETIME NOT NULL, INDEX IDX_D782112DDB38439E (usuario_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('ALTER TABLE anexo_downloads ADD CONSTRAINT FK_7C83D622DB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE anexo_downloads ADD CONSTRAINT FK_7C83D622C9348664 FOREIGN KEY (anexo_id) REFERENCES musica_anexos (id)');
        $this->addSql('ALTER TABLE grupo_usuarios ADD CONSTRAINT FK_461BB8379C833003 FOREIGN KEY (grupo_id) REFERENCES grupo (id)');
        $this->addSql('ALTER TABLE grupo_usuarios ADD CONSTRAINT FK_461BB837DB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE sugestao_resposta ADD CONSTRAINT FK_B11B25F4AF0AA99B FOREIGN KEY (sugestao_id) REFERENCES sugestao (id)');
        $this->addSql('ALTER TABLE sugestao_resposta ADD CONSTRAINT FK_B11B25F4DB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE sugestao ADD CONSTRAINT FK_36179898DB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE grupo_musicas ADD CONSTRAINT FK_74CCCD019C833003 FOREIGN KEY (grupo_id) REFERENCES grupo (id)');
        $this->addSql('ALTER TABLE grupo_musicas ADD CONSTRAINT FK_74CCCD0199E6F854 FOREIGN KEY (musica_id) REFERENCES musica (id)');
        $this->addSql('ALTER TABLE emails_enviados ADD CONSTRAINT FK_FC7E208FDB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE login ADD CONSTRAINT FK_AA08CB10DB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE playlist_musicas ADD CONSTRAINT FK_94FA54BC6BBD148 FOREIGN KEY (playlist_id) REFERENCES playlist (id)');
        $this->addSql('ALTER TABLE playlist_musicas ADD CONSTRAINT FK_94FA54BC99E6F854 FOREIGN KEY (musica_id) REFERENCES musica_anexos (id)');
        $this->addSql('ALTER TABLE playlist_musicas ADD CONSTRAINT FK_94FA54BCDB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE playlist ADD CONSTRAINT FK_D782112DDB38439E FOREIGN KEY (usuario_id) REFERENCES usuarios (id)');
        $this->addSql('ALTER TABLE categoria ADD apenas_anexos TINYINT(1) NOT NULL');
        $this->addSql('ALTER TABLE email_confirmacao CHANGE ativo_em ativo_em DATETIME DEFAULT NULL');
        $this->addSql('ALTER TABLE musica ADD apenas_anexos TINYINT(1) NOT NULL');
        $this->addSql('ALTER TABLE usuarios ADD grupo_id INT DEFAULT NULL, ADD cidade VARCHAR(255) NOT NULL, ADD uf VARCHAR(50) NOT NULL, ADD senha VARCHAR(50) NOT NULL');
        $this->addSql('ALTER TABLE usuarios ADD CONSTRAINT FK_EF687F29C833003 FOREIGN KEY (grupo_id) REFERENCES grupo (id)');
        $this->addSql('CREATE INDEX IDX_EF687F29C833003 ON usuarios (grupo_id)');
        $this->addSql('ALTER TABLE config ADD about LONGTEXT DEFAULT NULL');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('ALTER TABLE sugestao_resposta DROP FOREIGN KEY FK_B11B25F4AF0AA99B');
        $this->addSql('ALTER TABLE grupo_usuarios DROP FOREIGN KEY FK_461BB8379C833003');
        $this->addSql('ALTER TABLE grupo_musicas DROP FOREIGN KEY FK_74CCCD019C833003');
        $this->addSql('ALTER TABLE usuarios DROP FOREIGN KEY FK_EF687F29C833003');
        $this->addSql('ALTER TABLE playlist_musicas DROP FOREIGN KEY FK_94FA54BC6BBD148');
        $this->addSql('DROP TABLE anexo_downloads');
        $this->addSql('DROP TABLE grupo_usuarios');
        $this->addSql('DROP TABLE sugestao_resposta');
        $this->addSql('DROP TABLE sugestao');
        $this->addSql('DROP TABLE grupo');
        $this->addSql('DROP TABLE grupo_musicas');
        $this->addSql('DROP TABLE emails_enviados');
        $this->addSql('DROP TABLE login');
        $this->addSql('DROP TABLE cidades');
        $this->addSql('DROP TABLE playlist_musicas');
        $this->addSql('DROP TABLE playlist');
        $this->addSql('ALTER TABLE categoria DROP apenas_anexos');
        $this->addSql('ALTER TABLE config DROP about');
        $this->addSql('ALTER TABLE email_confirmacao CHANGE ativo_em ativo_em DATETIME NOT NULL');
        $this->addSql('ALTER TABLE musica DROP apenas_anexos');
        $this->addSql('DROP INDEX IDX_EF687F29C833003 ON usuarios');
        $this->addSql('ALTER TABLE usuarios DROP grupo_id, DROP cidade, DROP uf, DROP senha');
    }
}


text:
/**
 * App Error Messages
 *
 * React Native Starter App
 * https://github.com/mcnamee/react-native-starter-app
 */

export default {
  // Defaults
  default: 'Hmm, an unknown error occured',
  timeout: 'Server Timed Out. Check your internet connection',
  invalidJson: 'Response returned is not valid JSON',

  // Challenges
  challenge404: 'No challenges found',
  missingChallengeId: 'Missing challenge definition',
};


text:
package nak.nakloidGUI.gui.preferencePages.ini;

import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;

import nak.nakloidGUI.NakloidGUI;

public class GeneralIniPage extends FieldEditorPreferencePage {
	public GeneralIniPage() {
		super(FieldEditorPreferencePage.GRID);
		setTitle("Nakloid");
		setMessage(getTitle());
		setDescription("Nakloidに関する設定項目です");
		setPreferenceStore(NakloidGUI.preferenceStore);
	}

	@Override
	protected void createFieldEditors() {
		Composite container = new Composite(getFieldEditorParent(), SWT.LEFT);
		container.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		container.setLayout(new GridLayout());
		{
			BooleanFieldEditor field = new BooleanFieldEditor("ini.output.print_debug", "ログ表示をデバッグモードにする", container);
			addField(field);
		}
		{
			BooleanFieldEditor field = new BooleanFieldEditor("ini.vocal_library.use_uwc_cache", "UWCキャッシュを使用する", container);
			addField(field);
		}
		{
			IntegerFieldEditor ifeVibratoOffset = new IntegerFieldEditor("ini.input.track", "使用するMIDIトラック", container, 2);
			ifeVibratoOffset.setValidRange(1, 99);
			ifeVibratoOffset.setErrorMessage("正の整数を入力して下さい");
			addField(ifeVibratoOffset);
		}
	}
}


text:
source "$SCRIPTPATH/inc/commons.sh"
source "$SCRIPTPATH/inc/header.sh"
echo -e "${GREEN}AtoMiC $APPTITLE Update Script$ENDCOLOR"
source "$SCRIPTPATH/inc/pause.sh"

if DoesAppFolderExist; then
    source "$SCRIPTPATH/inc/app-stop.sh"
    source "$SCRIPTPATH/utils/python/python-installer.sh"
    source "$SCRIPTPATH/utils/nzbtomedia/nzbtomedia-update.sh"
    source "$SCRIPTPATH/sabnzbdplus/sabnzbdplus-constants.sh"
    source "$SCRIPTPATH/$APPNAME/$APPNAME-repository-configurator.sh"
    source "$SCRIPTPATH/inc/app-install-pips.sh"
    source "$SCRIPTPATH/inc/app-update.sh"
    source "$SCRIPTPATH/inc/app-start.sh"
    source "$SCRIPTPATH/inc/app-update-confirmation.sh"
    source "$SCRIPTPATH/inc/thankyou.sh"
fi
source "$SCRIPTPATH/inc/exit.sh"


text:
require 'points'
require 'rails'

module PointsApplicationControllerExtensions
  def award_points
    yield and return if current_user.try(:admin?)
    @point = Point.find_by_controller_and_action(params["controller"], params["action"])
    yield
    if @point
      # Setting @award_points in this method is just for developing so you can see how it
      #   would work, to really get the points in we ought to assign @award_points in each action
      #   that we want to give points out for.
      @award_points ||= ( response.code == '200' || flash[:notice].try(:match, /success/i) )
      @point.award(current_user, @award_points) if @award_points
    end
  end
end

module Points
  class Engine < Rails::Engine
    initializer 'myengine.app_controller' do |app|
      ActiveSupport.on_load(:action_controller) do
#        extend MyModule::ClassMethods
#        include PointsApplicationControllerExtensions
      end
    end
  end
end


text:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#CDCDB4"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginTop="13dp"
            android:layout_marginLeft="17dp"
            android:layout_marginBottom="8dp"
            >
            <TextView
                android:id="@+id/tv_Score"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/score"
                android:layout_gravity="center"
                android:textSize="20sp"
                />
            <TextView
                android:id="@+id/tvScore"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:textSize="20sp"
                android:textStyle="bold"
                android:textColor="#330033"/>
            <FrameLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <Button
                    android:id="@+id/music"
                    android:layout_width="38dp"
                    android:layout_height="38dp"
                    android:layout_gravity="center"
                    android:background="@drawable/music"
                    />
                <Button
                    android:id="@+id/silence"
                    android:layout_width="38dp"
                    android:layout_height="38dp"
                    android:layout_gravity="center"
                    android:background="@drawable/silence"
                    />
            </FrameLayout>
        </LinearLayout>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/app_name"
            android:textSize="25sp"
            android:textStyle="bold"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="#333333"
            />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginTop="13dp"
            android:layout_marginRight="17dp"
            android:layout_marginBottom="8dp"
            >
            <TextView
                android:id="@+id/tv_HighScore"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="@string/HighScore"
                android:textSize="20sp"
                />
            <TextView
                android:id="@+id/tvHighScore"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:textSize="20sp"
                android:textStyle="bold"
                android:textColor="#330000"
                />
            <Button
                android:id="@+id/restart"
                android:layout_width="38dp"
                android:layout_height="38dp"
                android:layout_gravity="center"
                android:background="@drawable/restart"
                />
        </LinearLayout>
    </LinearLayout>

    <com.jikexueyuan.game2048.GameView
        android:id="@+id/game_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >
    </com.jikexueyuan.game2048.GameView>

</LinearLayout>


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252">
<TITLE>Solitaire encryption and key generation (dialog usage)</TITLE>
<link rel="stylesheet" type="text/css" href="CrypTool_Help.css">

<OBJECT TYPE="application/x-oleobject" CLASSID="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
	<PARAM NAME="Keyword" VALUE="Dialog (overview of all dialogs)">
	<PARAM NAME="Keyword" VALUE="Analysis">
	<PARAM NAME="Keyword" VALUE="Card game">
	<PARAM NAME="Keyword" VALUE="Solitaire encryption algorithm">
</OBJECT>

Using the dialog window of the Solitaire algorithm (Menu En- / Decrypt / Symmetric (classic))

This dialog window generates a keystream according to the Solitaire algorithm.

This keystream can be used for encryption of a plaintext as well as for decryption of a Solitaire ciphertext. After opening a plaintext or ciphertext in CrypTool as a document, select the Encrypt or Decrypt button as appropriate.

 Note:CrypTool features a (partially automated cryptanalysis of Solitaire ciphertexts.

1) Key generation

Please follow the frames sequentially from 1 to 3. If you want to change something in an earlier frame, you must restart from the first frame.

Grouping 1 a: Number of cards (classic: 52 +2)

Choose the number of cards to be used in the Solitaire algorithm.

Usually 54 cards are used (the normal deck of 52 plus the two jokers). This is recommended by the algorithm's developer, Bruce Schneier, and is thus the default value.

The minimum allowed value is three, so that at least one regular card accompanies the two jokers.

Grouping 1b: Defining the cards order

Choose the preferred initial deck. There are six available options. Ascending order is selected by default.

Ascending: sorts the cards in ascending order (starting with the lowest).

Descending: sorts the cards in descending order (starting with the highest).

Shuffle: randomly shuffles the cards (can be repeated as desired).

Manual Entry: choose the order of the cards manually in the optional "Manual Entry" frame.

Load Initial deck: load the most recently saved initial deck.

Load Final deck: load the most recently saved final deck.

 To decrypt successfully, you must use the same initial deck as was used to encrypt.

Optional Frame: Enter password

After choosing a card order in Frame 1b, you can modify the initial deck by using a password. The password can be up to 1024 characters, and non-alphabetic characters are not allowed. After entering the password, click on Modify the initial deck. You can click the button multiple times to modify the deck further.

To decrypt, you must use the same password and click Modify the initial deck as often as was done to encrypt.

For example, if you enter the password "test" and click Modify the initial deck twice, it will have the same effect as if you used the password "testtest" just once.

Optional Frame: Manual entry

This frame is only activated if you have chosen "Manual entry" in Frame 1b. Construct your preferred initial deck by clicking the buttons 1-54 in the desired order. If you make a mistake, press Reset to start over. The button values represent the card values as described in the Solitaire description. While constructing the initial deck, you can see the current deck under "Initial deck" in the output frame. Once you have selected the appropriate number of cards as chosen in Frame 1a, this frame will be deactivated.

2) Keystream generation

Grouping 2: Generating the keystream (automatically or manually)

This frame offers two alternatives for generating the keystream.

Automatic

This button automatically runs all five steps of the Solitaire algorithm as often as necessary for the plaintext or ciphertext.

After that, you can see the final deck in the output frame, representing the order of the card deck after generating the keystream.

Manual

This button allows you to operate the Solitaire algorithm manually. After selecting this button, Frame 2a will become active.

Note:Note: If you selected "Manual Entry" in Frame 1b, these buttons will only be active after completion of the initial deck.

Grouping 2 a:  Manual steps of the Solitaire algorithm

This frame will be active if you selected the Manual button in Frame 2. To follow the steps of the actual Solitaire algorithm, click the buttons from step 1 to 5 in ascending order and repeat the process until each keystream characters have been generated. After each step you can see the modification of the deck in the "Final deck" output field. New keystream characters are generated only in step 5.

 Note:Use the Generate remaining characters button if you decide during the process that you no longer want to carry out the process manually. In the small text field near the Step 5 button, you can see the number of generated and necessary keystream characters.

After a keystream with the same number of characters as the plaintext or ciphertext has been generated (within this dialog window at max 65,535 characters will be shown), the Encrypt, Decrypt, and Save buttons will become active.

Save

If you click the upper Save button, the current initial deck is saved to the document "StoredLastInitialdeck.txt" into the CrypTool folder on your hard disk.

If you click the middle Save button, the current final deck is saved to the document "StoredLastFinaldeck.txt" into the CrypTool folder on your hard disk.

If you click the lower Save button, the keystream is saved to the document "StoredLastKeystream.txt" into the CrypTool folder on your hard disk.

3) Encryption or Decryption using the Solitaire keystream

Encrypt

Click this button to generate the ciphertext from the plaintext.

Decrypt

Click this button to obtain the ciphertext from the plaintext.

 Clicking the Encrypt or Decrypt button will automatically close the dialog window and display the newly created file in the CrypTool main window.

Cancel

Click this button to exit the dialog window.


text:
<?php

declare(strict_types=1);

namespace Czim\Repository\Test\Helpers;

use Czim\Repository\BaseRepository;

class TestBaseRepository extends BaseRepository
{
    /**
     * {@inheritDoc}
     */
    public function model(): string
    {
        return TestSimpleModel::class;
    }
}


text:
'use strict';
'require uci';
'require rpc';
'require validation';

var proto_errors = {
	CONNECT_FAILED:			_('Connection attempt failed'),
	INVALID_ADDRESS:		_('IP address in invalid'),
	INVALID_GATEWAY:		_('Gateway address is invalid'),
	INVALID_LOCAL_ADDRESS:	_('Local IP address is invalid'),
	MISSING_ADDRESS:		_('IP address is missing'),
	MISSING_PEER_ADDRESS:	_('Peer address is missing'),
	NO_DEVICE:				_('Network device is not present'),
	NO_IFACE:				_('Unable to determine device name'),
	NO_IFNAME:				_('Unable to determine device name'),
	NO_WAN_ADDRESS:			_('Unable to determine external IP address'),
	NO_WAN_LINK:			_('Unable to determine upstream interface'),
	PEER_RESOLVE_FAIL:		_('Unable to resolve peer host name'),
	PIN_FAILED:				_('PIN code rejected')
};

var iface_patterns_ignore = [
	/^wmaster\d+/,
	/^wifi\d+/,
	/^hwsim\d+/,
	/^imq\d+/,
	/^ifb\d+/,
	/^mon\.wlan\d+/,
	/^sit\d+/,
	/^gre\d+/,
	/^gretap\d+/,
	/^ip6gre\d+/,
	/^ip6tnl\d+/,
	/^tunl\d+/,
	/^lo$/
];

var iface_patterns_wireless = [
	/^wlan\d+/,
	/^wl\d+/,
	/^ath\d+/,
	/^\w+\.network\d+/
];

var iface_patterns_virtual = [ ];

var callNetworkWirelessStatus = rpc.declare({
	object: 'network.wireless',
	method: 'status'
});

var callLuciNetdevs = rpc.declare({
	object: 'luci',
	method: 'netdevs'
});

var callLuciIfaddrs = rpc.declare({
	object: 'luci',
	method: 'ifaddrs',
	expect: { result: [] }
});

var callLuciBoardjson = rpc.declare({
	object: 'luci',
	method: 'boardjson'
});

var callIwinfoInfo = rpc.declare({
	object: 'iwinfo',
	method: 'info',
	params: [ 'device' ]
});

var callNetworkInterfaceStatus = rpc.declare({
	object: 'network.interface',
	method: 'dump',
	expect: { 'interface': [] }
});

var callNetworkDeviceStatus = rpc.declare({
	object: 'network.device',
	method: 'status',
	expect: { '': {} }
});

var _cache = {},
    _state = null,
    _protocols = {};

function getWifiState() {
	if (_cache.wifi == null)
		return callNetworkWirelessStatus().then(function(state) {
			if (!L.isObject(state))
				throw !1;
			return (_cache.wifi = state);
		}).catch(function() {
			return (_cache.wifi = {});
		});

	return Promise.resolve(_cache.wifi);
}

function getInterfaceState() {
	if (_cache.interfacedump == null)
		return callNetworkInterfaceStatus().then(function(state) {
			if (!Array.isArray(state))
				throw !1;
			return (_cache.interfacedump = state);
		}).catch(function() {
			return (_cache.interfacedump = []);
		});

	return Promise.resolve(_cache.interfacedump);
}

function getDeviceState() {
	if (_cache.devicedump == null)
		return callNetworkDeviceStatus().then(function(state) {
			if (!L.isObject(state))
				throw !1;
			return (_cache.devicedump = state);
		}).catch(function() {
			return (_cache.devicedump = {});
		});

	return Promise.resolve(_cache.devicedump);
}

function getIfaddrState() {
	if (_cache.ifaddrs == null)
		return callLuciIfaddrs().then(function(addrs) {
			if (!Array.isArray(addrs))
				throw !1;
			return (_cache.ifaddrs = addrs);
		}).catch(function() {
			return (_cache.ifaddrs = []);
		});

	return Promise.resolve(_cache.ifaddrs);
}

function getNetdevState() {
	if (_cache.devices == null)
		return callLuciNetdevs().then(function(state) {
			if (!L.isObject(state))
				throw !1;
			return (_cache.devices = state);
		}).catch(function() {
			return (_cache.devices = {});
		});

	return Promise.resolve(_cache.devices);
}

function getBoardState() {
	if (_cache.board == null)
		return callLuciBoardjson().then(function(state) {
			if (!L.isObject(state))
				throw !1;
			return (_cache.board = state);
		}).catch(function() {
			return (_cache.board = {});
		});

	return Promise.resolve(_cache.board);
}

function getWifiStateBySid(sid) {
	var s = uci.get('wireless', sid);

	if (s != null && s['.type'] == 'wifi-iface') {
		for (var radioname in _cache.wifi) {
			for (var i = 0; i < _cache.wifi[radioname].interfaces.length; i++) {
				var netstate = _cache.wifi[radioname].interfaces[i];

				if (typeof(netstate.section) != 'string')
					continue;

				var s2 = uci.get('wireless', netstate.section);

				if (s2 != null && s['.type'] == s2['.type'] && s['.name'] == s2['.name'])
					return [ radioname, _cache.wifi[radioname], netstate ];
			}
		}
	}

	return null;
}

function getWifiStateByIfname(ifname) {
	for (var radioname in _cache.wifi) {
		for (var i = 0; i < _cache.wifi[radioname].interfaces.length; i++) {
			var netstate = _cache.wifi[radioname].interfaces[i];

			if (typeof(netstate.ifname) != 'string')
				continue;

			if (netstate.ifname == ifname)
				return [ radioname, _cache.wifi[radioname], netstate ];
		}
	}

	return null;
}

function isWifiIfname(ifname) {
	for (var i = 0; i < iface_patterns_wireless.length; i++)
		if (iface_patterns_wireless[i].test(ifname))
			return true;

	return false;
}

function getWifiIwinfoByIfname(ifname, forcePhyOnly) {
	var tasks = [ callIwinfoInfo(ifname) ];

	if (!forcePhyOnly)
		tasks.push(getNetdevState());

	return Promise.all(tasks).then(function(info) {
		var iwinfo = info[0],
		    devstate = info[1],
		    phyonly = forcePhyOnly || !devstate[ifname] || (devstate[ifname].type != 1);

		if (L.isObject(iwinfo)) {
			if (phyonly) {
				delete iwinfo.bitrate;
				delete iwinfo.quality;
				delete iwinfo.quality_max;
				delete iwinfo.mode;
				delete iwinfo.ssid;
				delete iwinfo.bssid;
				delete iwinfo.encryption;
			}

			iwinfo.ifname = ifname;
		}

		return iwinfo;
	}).catch(function() {
		return null;
	});
}

function getWifiSidByNetid(netid) {
	var m = /^(\w+)\.network(\d+)$/.exec(netid);
	if (m) {
		var sections = uci.sections('wireless', 'wifi-iface');
		for (var i = 0, n = 0; i < sections.length; i++) {
			if (sections[i].device != m[1])
				continue;

			if (++n == +m[2])
				return sections[i]['.name'];
		}
	}

	return null;
}

function getWifiSidByIfname(ifname) {
	var sid = getWifiSidByNetid(ifname);

	if (sid != null)
		return sid;

	var res = getWifiStateByIfname(ifname);

	if (res != null && L.isObject(res[2]) && typeof(res[2].section) == 'string')
		return res[2].section;

	return null;
}

function getWifiNetidBySid(sid) {
	var s = uci.get('wireless', sid);
	if (s != null && s['.type'] == 'wifi-iface') {
		var radioname = s.device;
		if (typeof(s.device) == 'string') {
			var i = 0, netid = null, sections = uci.sections('wireless', 'wifi-iface');
			for (var i = 0, n = 0; i < sections.length; i++) {
				if (sections[i].device != s.device)
					continue;

				n++;

				if (sections[i]['.name'] != s['.name'])
					continue;

				return [ '%s.network%d'.format(s.device, n), s.device ];
			}

		}
	}

	return null;
}

function getWifiNetidByNetname(name) {
	var sections = uci.sections('wireless', 'wifi-iface');
	for (var i = 0; i < sections.length; i++) {
		if (typeof(sections[i].network) != 'string')
			continue;

		var nets = sections[i].network.split(/\s+/);
		for (var j = 0; j < nets.length; j++) {
			if (nets[j] != name)
				continue;

			return getWifiNetidBySid(sections[i]['.name']);
		}
	}

	return null;
}

function isVirtualIfname(ifname) {
	for (var i = 0; i < iface_patterns_virtual.length; i++)
		if (iface_patterns_virtual[i].test(ifname))
			return true;

	return false;
}

function isIgnoredIfname(ifname) {
	for (var i = 0; i < iface_patterns_ignore.length; i++)
		if (iface_patterns_ignore[i].test(ifname))
			return true;

	return false;
}

function appendValue(config, section, option, value) {
	var values = uci.get(config, section, option),
	    isArray = Array.isArray(values),
	    rv = false;

	if (isArray == false)
		values = String(values || '').split(/\s+/);

	if (values.indexOf(value) == -1) {
		values.push(value);
		rv = true;
	}

	uci.set(config, section, option, isArray ? values : values.join(' '));

	return rv;
}

function removeValue(config, section, option, value) {
	var values = uci.get(config, section, option),
	    isArray = Array.isArray(values),
	    rv = false;

	if (isArray == false)
		values = String(values || '').split(/\s+/);

	for (var i = values.length - 1; i >= 0; i--) {
		if (values[i] == value) {
			values.splice(i, 1);
			rv = true;
		}
	}

	if (values.length > 0)
		uci.set(config, section, option, isArray ? values : values.join(' '));
	else
		uci.unset(config, section, option);

	return rv;
}

function prefixToMask(bits, v6) {
	var w = v6 ? 128 : 32,
	    m = [];

	if (bits > w)
		return null;

	for (var i = 0; i < w / 16; i++) {
		var b = Math.min(16, bits);
		m.push((0xffff << (16 - b)) & 0xffff);
		bits -= b;
	}

	if (v6)
		return String.prototype.format.apply('%x:%x:%x:%x:%x:%x:%x:%x', m).replace(/:0(?::0)+$/, '::');
	else
		return '%d.%d.%d.%d'.format(m[0] >>> 8, m[0] & 0xff, m[1] >>> 8, m[1] & 0xff);
}

function maskToPrefix(mask, v6) {
	var m = v6 ? validation.parseIPv6(mask) : validation.parseIPv4(mask);

	if (!m)
		return null;

	var bits = 0;

	for (var i = 0, z = false; i < m.length; i++) {
		z = z || !m[i];

		while (!z && (m[i] & (v6 ? 0x8000 : 0x80))) {
			m[i] = (m[i] << 1) & (v6 ? 0xffff : 0xff);
			bits++;
		}

		if (m[i])
			return null;
	}

	return bits;
}

function initNetworkState() {
	if (_state == null)
		return (_state = Promise.all([
			getInterfaceState(), getDeviceState(), getBoardState(),
			getWifiState(), getIfaddrState(), getNetdevState(),
			uci.load('network'), uci.load('wireless'), uci.load('luci')
		]).finally(function() {
			var ifaddrs = _cache.ifaddrs,
			    devices = _cache.devices,
			    board = _cache.board,
			    s = { isTunnel: {}, isBridge: {}, isSwitch: {}, isWifi: {}, interfaces: {}, bridges: {}, switches: {} };

			for (var i = 0, a; (a = ifaddrs[i]) != null; i++) {
				var name = a.name.replace(/:.+$/, '');

				if (isVirtualIfname(name))
					s.isTunnel[name] = true;

				if (s.isTunnel[name] || !(isIgnoredIfname(name) || isVirtualIfname(name))) {
					s.interfaces[name] = s.interfaces[name] || {
						idx:      a.ifindex || i,
						name:     name,
						rawname:  a.name,
						flags:    [],
						ipaddrs:  [],
						ip6addrs: []
					};

					if (a.family == 'packet') {
						s.interfaces[name].flags   = a.flags;
						s.interfaces[name].stats   = a.data;
						s.interfaces[name].macaddr = a.addr;
					}
					else if (a.family == 'inet') {
						s.interfaces[name].ipaddrs.push(a.addr + '/' + a.netmask);
					}
					else if (a.family == 'inet6') {
						s.interfaces[name].ip6addrs.push(a.addr + '/' + a.netmask);
					}
				}
			}

			for (var devname in devices) {
				var dev = devices[devname];

				if (dev.bridge) {
					var b = {
						name:    devname,
						id:      dev.id,
						stp:     dev.stp,
						ifnames: []
					};

					for (var i = 0; dev.ports && i < dev.ports.length; i++) {
						var subdev = s.interfaces[dev.ports[i]];

						if (subdev == null)
							continue;

						b.ifnames.push(subdev);
						subdev.bridge = b;
					}

					s.bridges[devname] = b;
				}
			}

			if (L.isObject(board.switch)) {
				for (var switchname in board.switch) {
					var layout = board.switch[switchname],
					    netdevs = {},
					    nports = {},
					    ports = [],
					    pnum = null,
					    role = null;

					if (L.isObject(layout) && Array.isArray(layout.ports)) {
						for (var i = 0, port; (port = layout.ports[i]) != null; i++) {
							if (typeof(port) == 'object' && typeof(port.num) == 'number' &&
								(typeof(port.role) == 'string' || typeof(port.device) == 'string')) {
								var spec = {
									num:   port.num,
									role:  port.role || 'cpu',
									index: (port.index != null) ? port.index : port.num
								};

								if (port.device != null) {
									spec.device = port.device;
									spec.tagged = spec.need_tag;
									netdevs[port.num] = port.device;
								}

								ports.push(spec);

								if (port.role != null)
									nports[port.role] = (nports[port.role] || 0) + 1;
							}
						}

						ports.sort(function(a, b) {
							if (a.role != b.role)
								return (a.role < b.role) ? -1 : 1;

							return (a.index - b.index);
						});

						for (var i = 0, port; (port = ports[i]) != null; i++) {
							if (port.role != role) {
								role = port.role;
								pnum = 1;
							}

							if (role == 'cpu')
								port.label = 'CPU (%s)'.format(port.device);
							else if (nports[role] > 1)
								port.label = '%s %d'.format(role.toUpperCase(), pnum++);
							else
								port.label = role.toUpperCase();

							delete port.role;
							delete port.index;
						}

						s.switches[switchname] = {
							ports: ports,
							netdevs: netdevs
						};
					}
				}
			}

			return (_state = s);
		}));

	return Promise.resolve(_state);
}

function ifnameOf(obj) {
	if (obj instanceof Interface)
		return obj.name();
	else if (obj instanceof Protocol)
		return obj.ifname();
	else if (typeof(obj) == 'string')
		return obj.replace(/:.+$/, '');

	return null;
}

function networkSort(a, b) {
	return a.getName() > b.getName();
}

function deviceSort(a, b) {
	var typeWeigth = { wifi: 2, alias: 3 },
        weightA = typeWeigth[a.getType()] || 1,
        weightB = typeWeigth[b.getType()] || 1;

    if (weightA != weightB)
    	return weightA - weightB;

	return a.getName() > b.getName();
}

var Network, Protocol, Device, WifiDevice, WifiNetwork;

Network = L.Class.extend({
	getProtocol: function(protoname, netname) {
		var v = _protocols[protoname];
		if (v != null)
			return v(netname || '__dummy__');

		return null;
	},

	getProtocols: function() {
		var rv = [];

		for (var protoname in _protocols)
			rv.push(_protocols[protoname]('__dummy__'));

		return rv;
	},

	registerProtocol: function(protoname, methods) {
		var proto = Protocol.extend(Object.assign({}, methods, {
			__init__: function(name) {
				this.sid = name;
			},

			proto: function() {
				return protoname;
			}
		}));

		_protocols[protoname] = proto;

		return proto;
	},

	registerPatternVirtual: function(pat) {
		iface_patterns_virtual.push(pat);
	},

	registerErrorCode: function(code, message) {
		if (typeof(code) == 'string' &&
		    typeof(message) == 'string' &&
		    proto_errors.hasOwnProperty(code)) {
			proto_errors[code] = message;
			return true;
		}

		return false;
	},

	addNetwork: function(name, options) {
		return this.getNetwork(name).then(L.bind(function(existingNetwork) {
			if (name != null && /^[a-zA-Z0-9_]+$/.test(name) && existingNetwork == null) {
				var sid = uci.add('network', 'interface', name);

				if (sid != null) {
					if (L.isObject(options))
						for (var key in options)
							if (options.hasOwnProperty(key))
								uci.set('network', sid, key, options[key]);

					return this.instantiateNetwork(sid);
				}
			}
			else if (existingNetwork != null && existingNetwork.isEmpty()) {
				if (L.isObject(options))
					for (var key in options)
						if (options.hasOwnProperty(key))
							existingNetwork.set(key, options[key]);

				return existingNetwork;
			}
		}, this));
	},

	getNetwork: function(name) {
		return initNetworkState().then(L.bind(function() {
			var section = (name != null) ? uci.get('network', name) : null;

			if (section != null && section['.type'] == 'interface') {
				return this.instantiateNetwork(name);
			}
			else if (name != null) {
				for (var i = 0; i < _cache.interfacedump.length; i++)
					if (_cache.interfacedump[i].interface == name)
						return this.instantiateNetwork(name, _cache.interfacedump[i].proto);
			}

			return null;
		}, this));
	},

	getNetworks: function() {
		return initNetworkState().then(L.bind(function() {
			var uciInterfaces = uci.sections('network', 'interface'),
			    networks = {};

			for (var i = 0; i < uciInterfaces.length; i++)
				networks[uciInterfaces[i]['.name']] = this.instantiateNetwork(uciInterfaces[i]['.name']);

			for (var i = 0; i < _cache.interfacedump.length; i++)
				if (networks[_cache.interfacedump[i].interface] == null)
					networks[_cache.interfacedump[i].interface] =
						this.instantiateNetwork(_cache.interfacedump[i].interface, _cache.interfacedump[i].proto);

			var rv = [];

			for (var network in networks)
				if (networks.hasOwnProperty(network))
					rv.push(networks[network]);

			rv.sort(networkSort);

			return rv;
		}, this));
	},

	deleteNetwork: function(name) {
		return Promise.all([ L.require('firewall').catch(function() { return null }), initNetworkState() ]).then(function() {
			var uciInterface = uci.get('network', name);

			if (uciInterface != null && uciInterface['.type'] == 'interface') {
				uci.remove('network', name);

				uci.sections('luci', 'ifstate', function(s) {
					if (s.interface == name)
						uci.remove('luci', s['.name']);
				});

				uci.sections('network', 'alias', function(s) {
					if (s.interface == name)
						uci.remove('network', s['.name']);
				});

				uci.sections('network', 'route', function(s) {
					if (s.interface == name)
						uci.remove('network', s['.name']);
				});

				uci.sections('network', 'route6', function(s) {
					if (s.interface == name)
						uci.remove('network', s['.name']);
				});

				uci.sections('wireless', 'wifi-iface', function(s) {
					var networks = L.toArray(s.network).filter(function(network) { return network != name });

					if (networks.length > 0)
						uci.set('wireless', s['.name'], 'network', networks.join(' '));
					else
						uci.unset('wireless', s['.name'], 'network');
				});

				if (L.firewall)
					return L.firewall.deleteNetwork(name).then(function() { return true });

				return true;
			}

			return false;
		});
	},

	renameNetwork: function(oldName, newName) {
		return initNetworkState().then(function() {
			if (newName == null || !/^[a-zA-Z0-9_]+$/.test(newName) || uci.get('network', newName) != null)
				return false;

			var oldNetwork = uci.get('network', oldName);

			if (oldNetwork == null || oldNetwork['.type'] != 'interface')
				return false;

			var sid = uci.add('network', 'interface', newName);

			for (var key in oldNetwork)
				if (oldNetwork.hasOwnProperty(key) && key.charAt(0) != '.')
					uci.set('network', sid, key, oldNetwork[key]);

			uci.sections('luci', 'ifstate', function(s) {
				if (s.interface == oldName)
					uci.set('luci', s['.name'], 'interface', newName);
			});

			uci.sections('network', 'alias', function(s) {
				if (s.interface == oldName)
					uci.set('network', s['.name'], 'interface', newName);
			});

			uci.sections('network', 'route', function(s) {
				if (s.interface == oldName)
					uci.set('network', s['.name'], 'interface', newName);
			});

			uci.sections('network', 'route6', function(s) {
				if (s.interface == oldName)
					uci.set('network', s['.name'], 'interface', newName);
			});

			uci.sections('wireless', 'wifi-iface', function(s) {
				var networks = L.toArray(s.network).map(function(network) { return (network == oldName ? newName : network) });

				if (networks.length > 0)
					uci.set('wireless', s['.name'], 'network', networks.join(' '));
			});

			uci.remove('network', oldName);

			return true;
		});
	},

	getDevice: function(name) {
		return initNetworkState().then(L.bind(function() {
			if (name == null)
				return null;

			if (_state.interfaces.hasOwnProperty(name) || isWifiIfname(name))
				return this.instantiateDevice(name);

			var netid = getWifiNetidBySid(name);
			if (netid != null)
				return this.instantiateDevice(netid[0]);

			return null;
		}, this));
	},

	getDevices: function() {
		return initNetworkState().then(L.bind(function() {
			var devices = {};

			/* find simple devices */
			var uciInterfaces = uci.sections('network', 'interface');
			for (var i = 0; i < uciInterfaces.length; i++) {
				var ifnames = L.toArray(uciInterfaces[i].ifname);

				for (var j = 0; j < ifnames.length; j++) {
					if (ifnames[j].charAt(0) == '@')
						continue;

					if (isIgnoredIfname(ifnames[j]) || isVirtualIfname(ifnames[j]) || isWifiIfname(ifnames[j]))
						continue;

					devices[ifnames[j]] = this.instantiateDevice(ifnames[j]);
				}
			}

			for (var ifname in _state.interfaces) {
				if (devices.hasOwnProperty(ifname))
					continue;

				if (isIgnoredIfname(ifname) || isVirtualIfname(ifname) || isWifiIfname(ifname))
					continue;

				devices[ifname] = this.instantiateDevice(ifname);
			}

			/* find VLAN devices */
			var uciSwitchVLANs = uci.sections('network', 'switch_vlan');
			for (var i = 0; i < uciSwitchVLANs.length; i++) {
				if (typeof(uciSwitchVLANs[i].ports) != 'string' ||
				    typeof(uciSwitchVLANs[i].device) != 'string' ||
				    !_state.switches.hasOwnProperty(uciSwitchVLANs[i].device))
					continue;

				var ports = uciSwitchVLANs[i].ports.split(/\s+/);
				for (var j = 0; j < ports.length; j++) {
					var m = ports[j].match(/^(\d+)([tu]?)$/);
					if (m == null)
						continue;

					var netdev = _state.switches[uciSwitchVLANs[i].device].netdevs[m[1]];
					if (netdev == null)
						continue;

					if (!devices.hasOwnProperty(netdev))
						devices[netdev] = this.instantiateDevice(netdev);

					_state.isSwitch[netdev] = true;

					if (m[2] != 't')
						continue;

					var vid = uciSwitchVLANs[i].vid || uciSwitchVLANs[i].vlan;
					    vid = (vid != null ? +vid : null);

					if (vid == null || vid < 0 || vid > 4095)
						continue;

					var vlandev = '%s.%d'.format(netdev, vid);

					if (!devices.hasOwnProperty(vlandev))
						devices[vlandev] = this.instantiateDevice(vlandev);

					_state.isSwitch[vlandev] = true;
				}
			}

			/* find wireless interfaces */
			var uciWifiIfaces = uci.sections('wireless', 'wifi-iface'),
			    networkCount = {};

			for (var i = 0; i < uciWifiIfaces.length; i++) {
				if (typeof(uciWifiIfaces[i].device) != 'string')
					continue;

				networkCount[uciWifiIfaces[i].device] = (networkCount[uciWifiIfaces[i].device] || 0) + 1;

				var netid = '%s.network%d'.format(uciWifiIfaces[i].device, networkCount[uciWifiIfaces[i].device]);

				devices[netid] = this.instantiateDevice(netid);
			}

			var rv = [];

			for (var netdev in devices)
				if (devices.hasOwnProperty(netdev))
					rv.push(devices[netdev]);

			rv.sort(deviceSort);

			return rv;
		}, this));
	},

	isIgnoredDevice: function(name) {
		return isIgnoredIfname(name);
	},

	getWifiDevice: function(devname) {
		return Promise.all([ getWifiIwinfoByIfname(devname, true), initNetworkState() ]).then(L.bind(function(res) {
			var existingDevice = uci.get('wireless', devname);

			if (existingDevice == null || existingDevice['.type'] != 'wifi-device')
				return null;

			return this.instantiateWifiDevice(devname, res[0]);
		}, this));
	},

	getWifiDevices: function() {
		var deviceNames = [];

		return initNetworkState().then(L.bind(function() {
			var uciWifiDevices = uci.sections('wireless', 'wifi-device'),
			    tasks = [];

			for (var i = 0; i < uciWifiDevices.length; i++) {
				tasks.push(callIwinfoInfo(uciWifiDevices['.name'], true));
				deviceNames.push(uciWifiDevices['.name']);
			}

			return Promise.all(tasks);
		}, this)).then(L.bind(function(iwinfos) {
			var rv = [];

			for (var i = 0; i < deviceNames.length; i++)
				if (L.isObject(iwinfos[i]))
					rv.push(this.instantiateWifiDevice(deviceNames[i], iwinfos[i]));

			rv.sort(function(a, b) { return a.getName() < b.getName() });

			return rv;
		}, this));
	},

	getWifiNetwork: function(netname) {
		var sid, res, netid, radioname, radiostate, netstate;

		return initNetworkState().then(L.bind(function() {
			sid = getWifiSidByNetid(netname);

			if (sid != null) {
				res        = getWifiStateBySid(sid);
				netid      = netname;
				radioname  = res ? res[0] : null;
				radiostate = res ? res[1] : null;
				netstate   = res ? res[2] : null;
			}
			else {
				res = getWifiStateByIfname(netname);

				if (res != null) {
					radioname  = res[0];
					radiostate = res[1];
					netstate   = res[2];
					sid        = netstate.section;
					netid      = L.toArray(getWifiNetidBySid(sid))[0];
				}
				else {
					res = getWifiStateBySid(netname);

					if (res != null) {
						radioname  = res[0];
						radiostate = res[1];
						netstate   = res[2];
						sid        = netname;
						netid      = L.toArray(getWifiNetidBySid(sid))[0];
					}
					else {
						res = getWifiNetidBySid(netname);

						if (res != null) {
							netid     = res[0];
							radioname = res[1];
							sid       = netname;
						}
					}
				}
			}

			return (netstate ? getWifiIwinfoByIfname(netstate.ifname) : Promise.reject())
				.catch(function() { return radioname ? getWifiIwinfoByIfname(radioname) : Promise.reject() })
				.catch(function() { return Promise.resolve({ ifname: netid || sid || netname }) });
		}, this)).then(L.bind(function(iwinfo) {
			return this.instantiateWifiNetwork(sid || netname, radioname, radiostate, netid, netstate, iwinfo);
		}, this));
	},

	addWifiNetwork: function(options) {
		return initNetworkState().then(L.bind(function() {
			if (options == null ||
			    typeof(options) != 'object' ||
			    typeof(options.device) != 'string')
			    return null;

			var existingDevice = uci.get('wireless', options.device);
			if (existingDevice == null || existingDevice['.type'] != 'wifi-device')
				return null;

			var sid = uci.add('wireless', 'wifi-iface');
			for (var key in options)
				if (options.hasOwnProperty(key))
					uci.set('wireless', sid, key, options[key]);

			var radioname = existingDevice['.name'],
			    netid = getWifiNetidBySid(sid) || [];

			return this.instantiateWifiNetwork(sid, radioname, _cache.wifi[radioname], netid[0], null, { ifname: netid });
		}, this));
	},

	deleteWifiNetwork: function(netname) {
		return initNetworkState().then(L.bind(function() {
			var sid = getWifiSidByIfname(netname);

			if (sid == null)
				return false;

			uci.remove('wireless', sid);
			return true;
		}, this));
	},

	getStatusByRoute: function(addr, mask) {
		return initNetworkState().then(L.bind(function() {
			var rv = [];

			for (var i = 0; i < _state.interfacedump.length; i++) {
				if (!Array.isArray(_state.interfacedump[i].route))
					continue;

				for (var j = 0; j < _state.interfacedump[i].route.length; j++) {
					if (typeof(_state.interfacedump[i].route[j]) != 'object' ||
					    typeof(_state.interfacedump[i].route[j].target) != 'string' ||
					    typeof(_state.interfacedump[i].route[j].mask) != 'number')
					    continue;

					if (_state.interfacedump[i].route[j].table)
						continue;

					rv.push(_state.interfacedump[i]);
				}
			}

			return rv;
		}, this));
	},

	getStatusByAddress: function(addr) {
		return initNetworkState().then(L.bind(function() {
			var rv = [];

			for (var i = 0; i < _state.interfacedump.length; i++) {
				if (Array.isArray(_state.interfacedump[i]['ipv4-address']))
					for (var j = 0; j < _state.interfacedump[i]['ipv4-address'].length; j++)
						if (typeof(_state.interfacedump[i]['ipv4-address'][j]) == 'object' &&
						    _state.interfacedump[i]['ipv4-address'][j].address == addr)
							return _state.interfacedump[i];

				if (Array.isArray(_state.interfacedump[i]['ipv6-address']))
					for (var j = 0; j < _state.interfacedump[i]['ipv6-address'].length; j++)
						if (typeof(_state.interfacedump[i]['ipv6-address'][j]) == 'object' &&
						    _state.interfacedump[i]['ipv6-address'][j].address == addr)
							return _state.interfacedump[i];

				if (Array.isArray(_state.interfacedump[i]['ipv6-prefix-assignment']))
					for (var j = 0; j < _state.interfacedump[i]['ipv6-prefix-assignment'].length; j++)
						if (typeof(_state.interfacedump[i]['ipv6-prefix-assignment'][j]) == 'object' &&
							typeof(_state.interfacedump[i]['ipv6-prefix-assignment'][j]['local-address']) == 'object' &&
						    _state.interfacedump[i]['ipv6-prefix-assignment'][j]['local-address'].address == addr)
							return _state.interfacedump[i];
			}

			return null;
		}, this));
	},

	getWANNetworks: function() {
		return this.getStatusByRoute('0.0.0.0', 0).then(L.bind(function(statuses) {
			var rv = [];

			for (var i = 0; i < statuses.length; i++)
				rv.push(this.instantiateNetwork(statuses[i].interface, statuses[i].proto));

			return rv;
		}, this));
	},

	getWAN6Networks: function() {
		return this.getStatusByRoute('::', 0).then(L.bind(function(statuses) {
			var rv = [];

			for (var i = 0; i < statuses.length; i++)
				rv.push(this.instantiateNetwork(statuses[i].interface, statuses[i].proto));

			return rv;
		}, this));
	},

	getSwitchTopologies: function() {
		return initNetworkState().then(function() {
			return _state.switches;
		});
	},

	instantiateNetwork: function(name, proto) {
		if (name == null)
			return null;

		proto = (proto == null ? uci.get('network', name, 'proto') : proto);

		var protoClass = _protocols[proto] || Protocol;
		return new protoClass(name);
	},

	instantiateDevice: function(name, network) {
		return new Device(name, network);
	},

	instantiateWifiDevice: function(radioname, iwinfo) {
		return new WifiDevice(radioname, iwinfo);
	},

	instantiateWifiNetwork: function(sid, radioname, radiostate, netid, netstate, iwinfo) {
		return new WifiNetwork(sid, radioname, radiostate, netid, netstate, iwinfo);
	}
});

Protocol = L.Class.extend({
	__init__: function(name) {
		this.sid = name;
	},

	_get: function(opt) {
		var val = uci.get('network', this.sid, opt);

		if (Array.isArray(val))
			return val.join(' ');

		return val || '';
	},

	_ubus: function(field) {
		for (var i = 0; i < _cache.interfacedump.length; i++) {
			if (_cache.interfacedump[i].interface != this.sid)
				continue;

			return (field != null ? _cache.interfacedump[i][field] : _cache.interfacedump[i]);
		}
	},

	get: function(opt) {
		return uci.get('network', this.sid, opt);
	},

	set: function(opt, val) {
		return uci.set('network', this.sid, opt, val);
	},

	getIfname: function() {
		var ifname;

		if (this.isFloating())
			ifname = this._ubus('l3_device');
		else
			ifname = this._ubus('device');

		if (ifname != null)
			return ifname;

		var res = getWifiNetidByNetname(this.sid);
		return (res != null ? res[0] : null);
	},

	getProtocol: function() {
		return 'none';
	},

	getI18n: function() {
		switch (this.getProtocol()) {
		case 'none':   return _('Unmanaged');
		case 'static': return _('Static address');
		case 'dhcp':   return _('DHCP client');
		default:       return _('Unknown');
		}
	},

	getType: function() {
		return this._get('type');
	},

	getName: function() {
		return this.sid;
	},

	getUptime: function() {
		return this._ubus('uptime') || 0;
	},

	getExpiry: function() {
		var u = this._ubus('uptime'),
		    d = this._ubus('data');

		if (typeof(u) == 'number' && d != null &&
		    typeof(d) == 'object' && typeof(d.leasetime) == 'number') {
			var r = d.leasetime - (u % d.leasetime);
			return (r > 0 ? r : 0);
		}

		return -1;
	},

	getMetric: function() {
		return this._ubus('metric') || 0;
	},

	getZoneName: function() {
		var d = this._ubus('data');

		if (L.isObject(d) && typeof(d.zone) == 'string')
			return d.zone;

		return null;
	},

	getIPAddr: function() {
		var addrs = this._ubus('ipv4-address');
		return ((Array.isArray(addrs) && addrs.length) ? addrs[0].address : null);
	},

	getIPAddrs: function() {
		var addrs = this._ubus('ipv4-address'),
		    rv = [];

		if (Array.isArray(addrs))
			for (var i = 0; i < addrs.length; i++)
				rv.push('%s/%d'.format(addrs[i].address, addrs[i].mask));

		return rv;
	},

	getNetmask: function() {
		var addrs = this._ubus('ipv4-address');
		if (Array.isArray(addrs) && addrs.length)
			return prefixToMask(addrs[0].mask, false);
	},

	getGatewayAddr: function() {
		var routes = this._ubus('route');

		if (Array.isArray(routes))
			for (var i = 0; i < routes.length; i++)
				if (typeof(routes[i]) == 'object' &&
				    routes[i].target == '0.0.0.0' &&
				    routes[i].mask == 0)
				    return routes[i].nexthop;

		return null;
	},

	getDNSAddrs: function() {
		var addrs = this._ubus('dns-server'),
		    rv = [];

		if (Array.isArray(addrs))
			for (var i = 0; i < addrs.length; i++)
				if (!/:/.test(addrs[i]))
					rv.push(addrs[i]);

		return rv;
	},

	getIP6Addr: function() {
		var addrs = this._ubus('ipv6-address');

		if (Array.isArray(addrs) && L.isObject(addrs[0]))
			return '%s/%d'.format(addrs[0].address, addrs[0].mask);

		addrs = this._ubus('ipv6-prefix-assignment');

		if (Array.isArray(addrs) && L.isObject(addrs[0]) && L.isObject(addrs[0]['local-address']))
			return '%s/%d'.format(addrs[0]['local-address'].address, addrs[0]['local-address'].mask);

		return null;
	},

	getIP6Addrs: function() {
		var addrs = this._ubus('ipv6-address'),
		    rv = [];

		if (Array.isArray(addrs))
			for (var i = 0; i < addrs.length; i++)
				if (L.isObject(addrs[i]))
					rv.push('%s/%d'.format(addrs[i].address, addrs[i].mask));

		addrs = this._ubus('ipv6-prefix-assignment');

		if (Array.isArray(addrs))
			for (var i = 0; i < addrs.length; i++)
				if (L.isObject(addrs[i]) && L.isObject(addrs[i]['local-address']))
					rv.push('%s/%d'.format(addrs[i]['local-address'].address, addrs[i]['local-address'].mask));

		return rv;
	},

	getDNS6Addrs: function() {
		var addrs = this._ubus('dns-server'),
		    rv = [];

		if (Array.isArray(addrs))
			for (var i = 0; i < addrs.length; i++)
				if (/:/.test(addrs[i]))
					rv.push(addrs[i]);

		return rv;
	},

	getIP6Prefix: function() {
		var prefixes = this._ubus('ipv6-prefix');

		if (Array.isArray(prefixes) && L.isObject(prefixes[0]))
			return '%s/%d'.format(prefixes[0].address, prefixes[0].mask);

		return null;
	},

	getErrors: function() {
		var errors = this._ubus('errors'),
		    rv = null;

		if (Array.isArray(errors)) {
			for (var i = 0; i < errors.length; i++) {
				if (!L.isObject(errors[i]) || typeof(errors[i].code) != 'string')
					continue;

				rv = rv || [];
				rv.push(proto_errors[errors[i].code] || _('Unknown error (%s)').format(errors[i].code));
			}
		}

		return rv;
	},

	isBridge: function() {
		return (!this.isVirtual() && this.getType() == 'bridge');
	},

	getOpkgPackage: function() {
		return null;
	},

	isInstalled: function() {
		return true;
	},

	isVirtual: function() {
		return false;
	},

	isFloating: function() {
		return false;
	},

	isDynamic: function() {
		return (this._ubus('dynamic') == true);
	},

	isAlias: function() {
		var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')),
		    parent = null;

		for (var i = 0; i < ifnames.length; i++)
			if (ifnames[i].charAt(0) == '@')
				parent = ifnames[i].substr(1);
			else if (parent != null)
				parent = null;

		return parent;
	},

	isEmpty: function() {
		if (this.isFloating())
			return false;

		var empty = true,
		    ifname = this._get('ifname');

		if (ifname != null && ifname.match(/\S+/))
			empty = false;

		if (empty == true && getWifiNetidBySid(this.sid) != null)
			empty = false;

		return empty;
	},

	isUp: function() {
		return (this._ubus('up') == true);
	},

	addDevice: function(ifname) {
		ifname = ifnameOf(ifname);

		if (ifname == null || this.isFloating())
			return false;

		var wif = getWifiSidByIfname(ifname);

		if (wif != null)
			return appendValue('wireless', wif, 'network', this.sid);

		return appendValue('network', this.sid, 'ifname', ifname);
	},

	deleteDevice: function(ifname) {
		var rv = false;

		ifname = ifnameOf(ifname);

		if (ifname == null || this.isFloating())
			return false;

		var wif = getWifiSidByIfname(ifname);

		if (wif != null)
			rv = removeValue('wireless', wif, 'network', this.sid);

		if (removeValue('network', this.sid, 'ifname', ifname))
			rv = true;

		return rv;
	},

	getDevice: function() {
		if (this.isVirtual()) {
			var ifname = '%s-%s'.format(this.getProtocol(), this.sid);
			_state.isTunnel[this.getProtocol() + '-' + this.sid] = true;
			return L.network.instantiateDevice(ifname, this);
		}
		else if (this.isBridge()) {
			var ifname = 'br-%s'.format(this.sid);
			_state.isBridge[ifname] = true;
			return new Device(ifname, this);
		}
		else {
			var ifname = this._ubus('l3_device') || this._ubus('device');

			if (ifname != null)
				return L.network.instantiateDevice(ifname, this);

			var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));

			for (var i = 0; i < ifnames.length; i++) {
				var m = ifnames[i].match(/^([^:/]+)/);
				return ((m && m[1]) ? L.network.instantiateDevice(m[1], this) : null);
			}

			ifname = getWifiNetidByNetname(this.sid);

			return (ifname != null ? L.network.instantiateDevice(ifname[0], this) : null);
		}
	},

	getDevices: function() {
		var rv = [];

		if (!this.isBridge() && !(this.isVirtual() && !this.isFloating()))
			return null;

		var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));

		for (var i = 0; i < ifnames.length; i++) {
			if (ifnames[i].charAt(0) == '@')
				continue;

			var m = ifnames[i].match(/^([^:/]+)/);
			if (m != null)
				rv.push(L.network.instantiateDevice(m[1], this));
		}

		var uciWifiIfaces = uci.sections('wireless', 'wifi-iface');

		for (var i = 0; i < uciWifiIfaces.length; i++) {
			if (typeof(uciWifiIfaces[i].device) != 'string')
				continue;

			var networks = L.toArray(uciWifiIfaces[i].network);

			for (var j = 0; j < networks.length; j++) {
				if (networks[j] != this.sid)
					continue;

				var netid = getWifiNetidBySid(uciWifiIfaces[i]['.name']);

				if (netid != null)
					rv.push(L.network.instantiateDevice(netid[0], this));
			}
		}

		rv.sort(deviceSort);

		return rv;
	},

	containsDevice: function(ifname) {
		ifname = ifnameOf(ifname);

		if (ifname == null)
			return false;
		else if (this.isVirtual() && '%s-%s'.format(this.getProtocol(), this.sid) == ifname)
			return true;
		else if (this.isBridge() && 'br-%s'.format(this.sid) == ifname)
			return true;

		var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));

		for (var i = 0; i < ifnames.length; i++) {
			var m = ifnames[i].match(/^([^:/]+)/);
			if (m != null && m[1] == ifname)
				return true;
		}

		var wif = getWifiSidByIfname(ifname);

		if (wif != null) {
			var networks = L.toArray(uci.get('wireless', wif, 'network'));

			for (var i = 0; i < networks.length; i++)
				if (networks[i] == this.sid)
					return true;
		}

		return false;
	}
});

Device = L.Class.extend({
	__init__: function(ifname, network) {
		var wif = getWifiSidByIfname(ifname);

		if (wif != null) {
			var res = getWifiStateBySid(wif) || [],
			    netid = getWifiNetidBySid(wif) || [];

			this.wif    = new WifiNetwork(wif, res[0], res[1], netid[0], res[2], { ifname: ifname });
			this.ifname = this.wif.getIfname();
		}

		this.ifname  = this.ifname || ifname;
		this.dev     = _state.interfaces[this.ifname];
		this.network = network;
	},

	_ubus: function(field) {
		var dump = _cache.devicedump[this.ifname] || {};

		return (field != null ? dump[field] : dump);
	},

	getName: function() {
		return (this.wif != null ? this.wif.getIfname() : this.ifname);
	},

	getMAC: function() {
		return this._ubus('macaddr');
	},

	getIPAddrs: function() {
		var addrs = (this.dev != null ? this.dev.ipaddrs : null);
		return (Array.isArray(addrs) ? addrs : []);
	},

	getIP6Addrs: function() {
		var addrs = (this.dev != null ? this.dev.ip6addrs : null);
		return (Array.isArray(addrs) ? addrs : []);
	},

	getType: function() {
		if (this.ifname != null && this.ifname.charAt(0) == '@')
			return 'alias';
		else if (this.wif != null || isWifiIfname(this.ifname))
			return 'wifi';
		else if (_state.isBridge[this.ifname])
			return 'bridge';
		else if (_state.isTunnel[this.ifname])
			return 'tunnel';
		else if (this.ifname.indexOf('.') > -1)
			return 'vlan';
		else if (_state.isSwitch[this.ifname])
			return 'switch';
		else
			return 'ethernet';
	},

	getShortName: function() {
		if (this.wif != null)
			return this.wif.getShortName();

		return this.ifname;
	},

	getI18n: function() {
		if (this.wif != null) {
			return '%s: %s "%s"'.format(
				_('Wireless Network'),
				this.wif.getActiveMode(),
				this.wif.getActiveSSID() || this.wif.getActiveBSSID() || this.wif.getID() || '?');
		}

		return '%s: "%s"'.format(this.getTypeI18n(), this.getName());
	},

	getTypeI18n: function() {
		switch (this.getType()) {
		case 'alias':
			return _('Alias Interface');

		case 'wifi':
			return _('Wireless Adapter');

		case 'bridge':
			return _('Bridge');

		case 'switch':
			return _('Ethernet Switch');

		case 'vlan':
			return (_state.isSwitch[this.ifname] ? _('Switch VLAN') : _('Software VLAN'));

		case 'tunnel':
			return _('Tunnel Interface');

		default:
			return _('Ethernet Adapter');
		}
	},

	getPorts: function() {
		var br = _state.bridges[this.ifname],
		    rv = [];

		if (br == null || !Array.isArray(br.ifnames))
			return null;

		for (var i = 0; i < br.ifnames.length; i++)
			rv.push(L.network.instantiateDevice(br.ifnames[i]));

		return rv;
	},

	getBridgeID: function() {
		var br = _state.bridges[this.ifname];
		return (br != null ? br.id : null);
	},

	getBridgeSTP: function() {
		var br = _state.bridges[this.ifname];
		return (br != null ? !!br.stp : false);
	},

	isUp: function() {
		var up = this._ubus('up');

		if (up == null)
			up = (this.getType() == 'alias');

		return up;
	},

	isBridge: function() {
		return (this.getType() == 'bridge');
	},

	isBridgePort: function() {
		return (this.dev != null && this.dev.bridge != null);
	},

	getTXBytes: function() {
		var stat = this._ubus('statistics');
		return (stat != null ? stat.tx_bytes || 0 : 0);
	},

	getRXBytes: function() {
		var stat = this._ubus('statistics');
		return (stat != null ? stat.rx_bytes || 0 : 0);
	},

	getTXPackets: function() {
		var stat = this._ubus('statistics');
		return (stat != null ? stat.tx_packets || 0 : 0);
	},

	getRXPackets: function() {
		var stat = this._ubus('statistics');
		return (stat != null ? stat.rx_packets || 0 : 0);
	},

	getNetwork: function() {
		return this.getNetworks()[0];
	},

	getNetworks: function() {
		if (this.networks == null) {
			this.networks = [];

			var networks = L.network.getNetworks();

			for (var i = 0; i < networks.length; i++)
				if (networks[i].containsDevice(this.ifname) || networks[i].getIfname() == this.ifname)
					this.networks.push(networks[i]);

			this.networks.sort(networkSort);
		}

		return this.networks;
	},

	getWifiNetwork: function() {
		return (this.wif != null ? this.wif : null);
	}
});

WifiDevice = L.Class.extend({
	__init__: function(name, iwinfo) {
		var uciWifiDevice = uci.get('wireless', name);

		if (uciWifiDevice != null &&
		    uciWifiDevice['.type'] == 'wifi-device' &&
		    uciWifiDevice['.name'] != null) {
			this.sid    = uciWifiDevice['.name'];
			this.iwinfo = iwinfo;
		}

		this.sid    = this.sid    || name;
		this.iwinfo = this.iwinfo || { ifname: this.sid };
	},

	get: function(opt) {
		return uci.get('wireless', this.sid, opt);
	},

	set: function(opt, value) {
		return uci.set('wireless', this.sid, opt, value);
	},

	getName: function() {
		return this.sid;
	},

	getHWModes: function() {
		if (L.isObject(this.iwinfo.hwmodelist))
			for (var k in this.iwinfo.hwmodelist)
				return this.iwinfo.hwmodelist;

		return { b: true, g: true };
	},

	getI18n: function() {
		var type = this.iwinfo.hardware_name || 'Generic';

		if (this.iwinfo.type == 'wl')
			type = 'Broadcom';

		var hwmodes = this.getHWModes(),
		    modestr = '';

		if (hwmodes.a) modestr += 'a';
		if (hwmodes.b) modestr += 'b';
		if (hwmodes.g) modestr += 'g';
		if (hwmodes.n) modestr += 'n';
		if (hwmodes.ad) modestr += 'ac';

		return '%s 802.11%s Wireless Controller (%s)'.format(type, modestr, this.getName());
	},

	isUp: function() {
		if (L.isObject(_cache.wifi[this.sid]))
			return (_cache.wifi[this.sid].up == true);

		return false;
	},

	getWifiNetwork: function(network) {
		return L.network.getWifiNetwork(network).then(L.bind(function(networkInstance) {
			var uciWifiIface = (networkInstance.sid ? uci.get('wireless', networkInstance.sid) : null);

			if (uciWifiIface == null || uciWifiIface['.type'] != 'wifi-iface' || uciWifiIface.device != this.sid)
				return Promise.reject();

			return networkInstance;
		}, this));
	},

	getWifiNetworks: function() {
		var uciWifiIfaces = uci.sections('wireless', 'wifi-iface'),
		    tasks = [];

		for (var i = 0; i < uciWifiIfaces.length; i++)
			if (uciWifiIfaces[i].device == this.sid)
				tasks.push(L.network.getWifiNetwork(uciWifiIfaces[i]['.name']));

		return Promise.all(tasks);
	},

	addWifiNetwork: function(options) {
		if (!L.isObject(options))
			options = {};

		options.device = this.sid;

		return L.network.addWifiNetwork(options);
	},

	deleteWifiNetwork: function(network) {
		var sid = null;

		if (network instanceof WifiNetwork) {
			sid = network.sid;
		}
		else {
			var uciWifiIface = uci.get('wireless', network);

			if (uciWifiIface == null || uciWifiIface['.type'] != 'wifi-iface')
				sid = getWifiSidByIfname(network);
		}

		if (sid == null || uci.get('wireless', sid, 'device') != this.sid)
			return Promise.resolve(false);

		uci.delete('wireless', network);

		return Promise.resolve(true);
	}
});

WifiNetwork = L.Class.extend({
	__init__: function(sid, radioname, radiostate, netid, netstate, iwinfo) {
		this.sid    = sid;
		this.wdev   = iwinfo.ifname;
		this.iwinfo = iwinfo;
		this.netid  = netid;
		this._ubusdata = {
			radio: radioname,
			dev:   radiostate,
			net:   netstate
		};
	},

	ubus: function(/* ... */) {
		var v = this._ubusdata;

		for (var i = 0; i < arguments.length; i++)
			if (L.isObject(v))
				v = v[arguments[i]];
			else
				return null;

		return v;
	},

	get: function(opt) {
		return uci.get('wireless', this.sid, opt);
	},

	set: function(opt, value) {
		return uci.set('wireless', this.sid, opt, value);
	},

	getMode: function() {
		return this.ubus('net', 'config', 'mode') || this.get('mode') || 'ap';
	},

	getSSID: function() {
		return this.ubus('net', 'config', 'ssid') || this.get('ssid');
	},

	getBSSID: function() {
		return this.ubus('net', 'config', 'bssid') || this.get('bssid');
	},

	getNetworkNames: function() {
		return L.toArray(this.ubus('net', 'config', 'network') || this.get('network'));
	},

	getID: function() {
		return this.netid;
	},

	getName: function() {
		return this.sid;
	},

	getIfname: function() {
		var ifname = this.ubus('net', 'ifname') || this.iwinfo.ifname;

		if (ifname == null || ifname.match(/^(wifi|radio)\d/))
			ifname = this.netid;

		return ifname;
	},

	getWifiDevice: function() {
		var radioname = this.ubus('radio') || this.get('device');

		if (radioname == null)
			return Promise.reject();

		return L.network.getWifiDevice(radioname);
	},

	isUp: function() {
		var device = this.getDevice();

		if (device == null)
			return false;

		return device.isUp();
	},

	getActiveMode: function() {
		var mode = this.iwinfo.mode || this.ubus('net', 'config', 'mode') || this.get('mode') || 'ap';

		switch (mode) {
		case 'ap':      return 'Master';
		case 'sta':     return 'Client';
		case 'adhoc':   return 'Ad-Hoc';
		case 'mesh':    return 'Mesh';
		case 'monitor': return 'Monitor';
		default:        return mode;
		}
	},

	getActiveModeI18n: function() {
		var mode = this.getActiveMode();

		switch (mode) {
		case 'Master':  return _('Master');
		case 'Client':  return _('Client');
		case 'Ad-Hoc':  return _('Ad-Hoc');
		case 'Mash':    return _('Mesh');
		case 'Monitor': return _('Monitor');
		default:        return mode;
		}
	},

	getActiveSSID: function() {
		return this.iwinfo.ssid || this.ubus('net', 'config', 'ssid') || this.get('ssid');
	},

	getActiveBSSID: function() {
		return this.iwinfo.bssid || this.ubus('net', 'config', 'bssid') || this.get('bssid');
	},

	getActiveEncryption: function() {
		var encryption = this.iwinfo.encryption;

		return (L.isObject(encryption) ? encryption.description || '-' : '-');
	},

	getAssocList: function() {
		// XXX tbd
	},

	getFrequency: function() {
		var freq = this.iwinfo.frequency;

		if (freq != null && freq > 0)
			return '%.03f'.format(freq / 1000);

		return null;
	},

	getBitRate: function() {
		var rate = this.iwinfo.bitrate;

		if (rate != null && rate > 0)
			return (rate / 1000);

		return null;
	},

	getChannel: function() {
		return this.iwinfo.channel || this.ubus('dev', 'config', 'channel') || this.get('channel');
	},

	getSignal: function() {
		return this.iwinfo.signal || 0;
	},

	getNoise: function() {
		return this.iwinfo.noise || 0;
	},

	getCountryCode: function() {
		return this.iwinfo.country || this.ubus('dev', 'config', 'country') || '00';
	},

	getTXPower: function() {
		var pwr = this.iwinfo.txpower || 0;
		return (pwr + this.getTXPowerOffset());
	},

	getTXPowerOffset: function() {
		return this.iwinfo.txpower_offset || 0;
	},

	getSignalLevel: function(signal, noise) {
		if (this.getActiveBSSID() == '00:00:00:00:00:00')
			return -1;

		signal = signal || this.getSignal();
		noise  = noise  || this.getNoise();

		if (signal < 0 && noise < 0) {
			var snr = -1 * (noise - signal);
			return Math.floor(snr / 5);
		}

		return 0;
	},

	getSignalPercent: function() {
		var qc = this.iwinfo.quality || 0,
		    qm = this.iwinfo.quality_max || 0;

		if (qc > 0 && qm > 0)
			return Math.floor((100 / qm) * qc);

		return 0;
	},

	getShortName: function() {
		return '%s "%s"'.format(
			this.getActiveModeI18n(),
			this.getActiveSSID() || this.getActiveBSSID() || this.getID());
	},

	getI18n: function() {
		return '%s: %s "%s" (%s)'.format(
			_('Wireless Network'),
			this.getActiveModeI18n(),
			this.getActiveSSID() || this.getActiveBSSID() || this.getID(),
			this.getIfname());
	},

	getNetwork: function() {
		return this.getNetworks()[0];
	},

	getNetworks: function() {
		var networkNames = this.getNetworkNames(),
		    networks = [];

		for (var i = 0; i < networkNames.length; i++) {
			var uciInterface = uci.get('network', networkNames[i]);

			if (uciInterface == null || uciInterface['.type'] != 'interface')
				continue;

			networks.push(L.network.instantiateNetwork(networkNames[i]));
		}

		networks.sort(networkSort);

		return networks;
	},

	getDevice: function() {
		return L.network.instantiateDevice(this.getIfname());
	}
});

return Network;


text:
using System.Net;
using System.Net.Sockets;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Https;

namespace Microsoft.AspNetCore.Server.Kestrel.Core;

/// <summary>
/// Describes either an <see cref="IPEndPoint"/>, Unix domain socket path, or a file descriptor for an already open
/// socket that Kestrel should bind to or open.
/// </summary>
public class ListenOptions : IConnectionBuilder, IMultiplexedConnectionBuilder
{
    internal const HttpProtocols DefaultHttpProtocols = HttpProtocols.Http1AndHttp2;

    internal readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _middleware = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
    internal readonly List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>> _multiplexedMiddleware = new List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>>();

    internal ListenOptions(EndPoint endPoint)
    {
        EndPoint = endPoint;
    }

    internal ListenOptions(string socketPath)
    {
        EndPoint = new UnixDomainSocketEndPoint(socketPath);
    }

    internal ListenOptions(ulong fileHandle)
        : this(fileHandle, FileHandleType.Auto)
    {
    }

    internal ListenOptions(ulong fileHandle, FileHandleType handleType)
    {
        EndPoint = new FileHandleEndPoint(fileHandle, handleType);
    }

    /// <summary>
    /// Gets the <see cref="EndPoint"/>.
    /// </summary>
    public EndPoint EndPoint { get; internal set; }

    // For comparing bound endpoints to changed config during endpoint config reload.
    internal EndpointConfig? EndpointConfig { get; set; }

    // IPEndPoint is mutable so port 0 can be updated to the bound port.
    /// <summary>
    /// The <see cref="IPEndPoint"/> to bind to.
    /// Only set if the <see cref="ListenOptions"/> <see cref="Type"/> is <see cref="IPEndPoint"/>.
    /// </summary>
    public IPEndPoint? IPEndPoint => EndPoint as IPEndPoint;

    /// <summary>
    /// The absolute path to a Unix domain socket to bind to.
    /// Only set if the <see cref="ListenOptions"/> <see cref="Type"/> is <see cref="UnixDomainSocketEndPoint"/>.
    /// </summary>
    public string? SocketPath => (EndPoint as UnixDomainSocketEndPoint)?.ToString();

    /// <summary>
    /// A file descriptor for the socket to open.
    /// Only set if the <see cref="ListenOptions"/> <see cref="Type"/> is <see cref="FileHandleEndPoint"/>.
    /// </summary>
    public ulong FileHandle => (EndPoint as FileHandleEndPoint)?.FileHandle ?? 0;

    /// <summary>
    /// Enables connection middleware to resolve and use services registered by the application during startup.
    /// Only set if accessed from the callback of a <see cref="KestrelServerOptions"/> Listen* method.
    /// </summary>
    public KestrelServerOptions KestrelServerOptions { get; internal set; } = default!; // Set via ConfigureKestrel callback

    /// <summary>
    /// The protocols enabled on this endpoint.
    /// </summary>
    /// <remarks>Defaults to HTTP/1.x and HTTP/2.</remarks>
    public HttpProtocols Protocols { get; set; } = DefaultHttpProtocols;

    /// <summary>
    /// Gets or sets a value that controls whether the "Alt-Svc" header is included with response headers.
    /// The "Alt-Svc" header is used by clients to upgrade HTTP/1.1 and HTTP/2 connections to HTTP/3.
    /// <para>
    /// The "Alt-Svc" header is automatically included with a response if <see cref="Protocols"/> has either
    /// HTTP/1.1 or HTTP/2 enabled, and HTTP/3 is enabled. If an "Alt-Svc" header value has already been set
    /// by the app then it isn't changed.
    /// </para>
    /// </summary>
    /// <remarks>
    /// Defaults to false.
    /// </remarks>
    public bool DisableAltSvcHeader { get; set; }

    /// <summary>
    /// Gets the application <see cref="IServiceProvider"/>.
    /// </summary>
    public IServiceProvider ApplicationServices => KestrelServerOptions?.ApplicationServices!; // TODO - Always available?

    internal string Scheme
    {
        get
        {
            return IsTls ? HttpProtocol.SchemeHttps : HttpProtocol.SchemeHttp;
        }
    }

    internal bool IsTls { get; set; }
    internal HttpsConnectionAdapterOptions? HttpsOptions { get; set; }
    internal TlsHandshakeCallbackOptions? HttpsCallbackOptions { get; set; }

    /// <summary>
    /// Gets the name of this endpoint to display on command-line when the web server starts.
    /// </summary>
    internal virtual string GetDisplayName()
    {
        switch (EndPoint)
        {
            case UnixDomainSocketEndPoint _:
                return $"{Scheme}://unix:{EndPoint}";
            case FileHandleEndPoint _:
                return $"{Scheme}://<file handle>";
            default:
                return $"{Scheme}://{EndPoint}";
        }
    }

    /// <inheritdoc />
    public override string? ToString() => GetDisplayName();

    /// <summary>
    /// Adds a middleware delegate to the connection pipeline.
    /// Configured by the <c>UseHttps()</c> and <see cref="Hosting.ListenOptionsConnectionLoggingExtensions.UseConnectionLogging(ListenOptions)"/>
    /// extension methods.
    /// </summary>
    /// <param name="middleware">The middleware delegate.</param>
    /// <returns>The <see cref="IConnectionBuilder"/>.</returns>
    public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
    {
        _middleware.Add(middleware);
        return this;
    }

    IMultiplexedConnectionBuilder IMultiplexedConnectionBuilder.Use(Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate> middleware)
    {
        _multiplexedMiddleware.Add(middleware);
        return this;
    }

    /// <summary>
    /// Builds the <see cref="ConnectionDelegate"/>.
    /// </summary>
    /// <returns>The <see cref="ConnectionDelegate"/>.</returns>
    public ConnectionDelegate Build()
    {
        ConnectionDelegate app = context =>
        {
            return Task.CompletedTask;
        };

        for (var i = _middleware.Count - 1; i >= 0; i--)
        {
            var component = _middleware[i];
            app = component(app);
        }

        return app;
    }

    MultiplexedConnectionDelegate IMultiplexedConnectionBuilder.Build()
    {
        MultiplexedConnectionDelegate app = context =>
        {
            return Task.CompletedTask;
        };

        for (int i = _multiplexedMiddleware.Count - 1; i >= 0; i--)
        {
            var component = _multiplexedMiddleware[i];
            app = component(app);
        }

        return app;
    }

    internal virtual async Task BindAsync(AddressBindContext context, CancellationToken cancellationToken)
    {
        await AddressBinder.BindEndpointAsync(this, context, cancellationToken).ConfigureAwait(false);
        context.Addresses.Add(GetDisplayName());
    }
}