diff --git a/.github/workflows/rolling-release.yml b/.github/workflows/rolling-release.yml index 885e1ea60..1d97525e3 100644 --- a/.github/workflows/rolling-release.yml +++ b/.github/workflows/rolling-release.yml @@ -93,7 +93,7 @@ jobs: shell: bash run: | sudo apt-get update - sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk2.0-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default + sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk2.0-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default qttools5-dev - name: Compile build shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b17b5ebd..08c240989 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ if(NOT ANDROID) find_package(SDL2 REQUIRED) endif() if(BUILD_QT_FRONTEND) - find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED) + find_package(Qt5 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED) endif() endif() diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6fc5ba71a..ed5e786c6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -5,6 +5,9 @@ The following people have contributed to the project in some way, and are credit - Connor McLaughlin - @stenzek - @ggrtk +## Translators +- Anderson Cardoso - Portuguese + ## Game Compatibility Database - @Zet-sensei - @DarkFrost89 diff --git a/README.md b/README.md index 9ac791c62..6e0f0431f 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Requirements (Debian/Ubuntu package names): - CMake (`cmake`) - SDL2 (`libsdl2-dev`) - GTK2.0 for file selector (`libgtk2.0-dev`) - - Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`) + - Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`, `qttools5-dev`) - Optional for faster building: Ninja (`ninja-build`) 1. Clone the repository. Submodules aren't necessary, there is only one and it is only used for Windows. diff --git a/appimage/generate-appimages.sh b/appimage/generate-appimages.sh index 8dbc5b1d3..945c54df4 100755 --- a/appimage/generate-appimages.sh +++ b/appimage/generate-appimages.sh @@ -48,6 +48,15 @@ for frontend in ${FRONTENDS[@]}; do cp -av ${DATA_DIR}/* ${CURRENT_APPDIR}/usr/bin done +# Add translations into the AppDir. +TRANSLATIONS_DIR=${BUILD_DIR}/bin/translations +echo "Translation directory is: ${BUILD_DIR}" +for frontend in ${FRONTENDS[@]}; do + CURRENT_APPDIR=${BUILD_DIR}/AppDir-duckstation-${frontend} + mkdir -p ${CURRENT_APPDIR}/usr/bin + cp -av ${TRANSLATIONS_DIR} ${CURRENT_APPDIR}/usr/bin +done + # Pass UPDATE_INFORMATION and OUTPUT variables (used by linuxdeploy-plugin-appimage) # to the environment of the linuxdeploy commands diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index eaaa8e068..4361d79d9 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) -add_executable(duckstation-qt +set(SRCS resources/resources.qrc aboutdialog.cpp aboutdialog.h @@ -57,6 +57,14 @@ add_executable(duckstation-qt settingsdialog.ui ) +set(TS_FILES + translations/duckstation-qt_pt.ts +) + +set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations") +qt5_add_translation(QM_FILES ${TS_FILES}) + +add_executable(duckstation-qt ${SRCS} ${QM_FILES}) target_include_directories(duckstation-qt PRIVATE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}") target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui glad minizip scmversion vulkan-loader Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 662700f55..c1e833a5a 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -179,6 +179,11 @@ Document + + + Document + + diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index b96180b5e..429ae02e1 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -41,17 +41,20 @@ + - {3b2587ae-ce3b-4eb5-ada2-237e853620cf} + + {4230e20b-2aff-4c86-966c-b620263a371d} + @@ -75,6 +78,7 @@ + @@ -87,6 +91,7 @@ + @@ -98,6 +103,11 @@ - + + + + + translations + \ No newline at end of file diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 73f7e389f..30a2d37d0 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -53,7 +53,7 @@ const char* QtHostInterface::GetFrontendName() const std::vector> QtHostInterface::getAvailableLanguageList() { - return {{QStringLiteral("English"), QStringLiteral("")}}; + return {{QStringLiteral("English"), QStringLiteral("")}, {QStringLiteral("Portuguese"), QStringLiteral("pt")}}; } bool QtHostInterface::Initialize() diff --git a/src/duckstation-qt/translations/duckstation-qt_pt.ts b/src/duckstation-qt/translations/duckstation-qt_pt.ts new file mode 100644 index 000000000..8f88bf8f2 --- /dev/null +++ b/src/duckstation-qt/translations/duckstation-qt_pt.ts @@ -0,0 +1,1476 @@ + + + + + AboutDialog + + + About DuckStation + SobreDuckstation + + + + DuckStation + Duckstation + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DuckStation is a free and open-source simulator/emulator of the Sony PlayStation<span style=" vertical-align:super;">TM</span> console, focusing on playability, speed, and long-term maintainability.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Authors</span>:</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Connor McLaughlin &lt;stenzek@gmail.com&gt;</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duck icon by <a href="https://icons8.com/icon/74847/platforms.undefined.short-title"><span style=" text-decoration: underline; color:#0057ae;">icons8</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/stenzek/duckstation/blob/master/LICENSE"><span style=" text-decoration: underline; color:#0057ae;">License</span></a> | <a href="https://github.com/stenzek/duckstation"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a> | <a href="https://discord.gg/Buktv3t"><span style=" text-decoration: underline; color:#0057ae;">Discord</span></a></p></body></html> + + + + + %1 (%2) + %1 (%2) + + + + AdvancedSettingsWidget + + + Form + Formulário + + + + Logging + Registro + + + + Log Level: + Nivel do Ratreio: + + + + Log Filters: + Filtros: + + + + Log To System Console + Carregar para o sitema via console + + + + Log To Window + Carregar para Janela + + + + Log To Debug Console + Carregar para o Console + + + + Log To File + Carregar rastreio para arquivo + + + + Tweaks/Hacks + Ajustes e Hacks + + + + These options are tweakable to improve performance/game compatibility. Use at your own risk, modified values will not be supported. + Essas opções são ajustáveis ​​para melhorar a compatibilidade desempenho dos jogos. Use por sua conta e risco, valores modificados não serão suportados. + + + + DMA Max Slice Ticks: + DMA Max Slice Ticks: + + + + DMA Halt Ticks: + DMA Halt Ticks: + + + + GPU FIFO Size: + GPU FIFO Size: + + + + GPU Max Run-Ahead: + GPU Max Run-Ahead: + + + + Reset To Default + Redefinir para o Padrão + + + + AudioSettingsWidget + + + Form + Formulário + + + + Configuration + Configuração + + + + Backend: + Saída de Som: + + + + Buffer Size: + Tamanho do Buffer: + + + + Maximum latency: 0 frames (0.00ms) + Latência Máxima + + + + Sync To Output + Sincronizar + + + + Start Dumping On Boot + Despejar Audio ao Iniciar + + + + Controls + Controles + + + + Volume: + Volume: + + + + Mute + Mudo + + + + 100% + 100% + + + + Maximum latency: %1 frames (%2ms) + Latência Máxima:%1 frames (%2ms) + + + + %1% + %1% + + + + ConsoleSettingsWidget + + + Form + Formulário + + + + Console + Console + + + + Region: + Região: + + + + BIOS Image Path: + Caminho para BIOS: + + + + Fast Boot + Inicio Rápido + + + + Enable TTY Output + Habilitar saída TTY + + + + ... + ... + + + + CPU Emulation + Emulação da CPU + + + + Execution Mode: + Modo de Execução: + + + + CDROM Emulation + Emulação do CD-ROM + + + + Use Read Thread (Asynchronous) + Carregamento de Cache em tempo real + Usar Leitura Asincrona + + + + Enable Region Check + Habilitar Checagem de Região + + + + Preload Image To RAM + Coloca a Iso toda na sua mémoria RAM + Carregar Jogo para RAM + + + + Select BIOS Image + Escolha o Arquivo de BIOS + + + + ControllerSettingsWidget + + + Controller Type: + Tipo de Controle: + + + + Load Profile + Carregar Perfil + + + + Save Profile + Salvar Perfil + + + + Clear All + Limpar Tudo + + + + Clear Bindings + Limpar Atribuições + + + + Are you sure you want to clear all bound controls? This can not be reversed. + Tem certeza de que quer limpar todas as atribuições feitas, isto não poderá ser desfeito. + + + + + Rebind All + Reatribuir Todos + + + + Are you sure you want to rebind all controls? All currently-bound controls will be irreversibly cleared. Rebinding will begin after confirmation. + Tem certeza de que quer reatribuir todos os controles? Todas as mudanças feitas nos controles serão perdidas. A reatribuição se dará após a confirmação. + + + + Port %1 + + + + + Button Bindings: + Atribuição de Botões: + + + + Axis Bindings: + Analogicos + Atribuição de Eixos: + + + + Rumble + Vibração dos Controles + Vibração + + + + + + Browse... + Procurar... + + + + Select File + Escolha o Aruivo + + + + + Select path to input profile ini + Escolha o caminho para inserir o perfil do jogo + + + + New... + Novo... + + + + + Enter Input Profile Name + Escolha um nome para o Perfil + + + + + Error + Erro + + + + No name entered, input profile was not saved. + Nome não atribuido, configuração de controle não foi salva. + + + + No path selected, input profile was not saved. + Caminho não atribuido, configuração de controle não foi salva. + + + + GPUSettingsWidget + + + Form + Formulário + + + + Basic + Básico + + + + Renderer: + Renderizador: + + + + Adapter: + Adaptador: + + + + Use Debug Device + Usar Depuração para Dispositivo + + + + Screen Display + Exibição + + + + Aspect Ratio: + Proporção e Aspecto: + + + + Crop: + Cortar: + + + + Linear Upscaling + Escalonamento Linear + + + + Integer Upscaling + Escalonamento Integro + + + + VSync + Sincronização Vertical (VSync) + + + + Enhancements + Aprimoramentos + + + + Resolution Scale: + Escala de Resolução: + + + + True Color Rendering (24-bit, disables dithering) + Renderização em (24 Cores, desativa o efeito dithering) + + + + Scaled Dithering (scale dither pattern to resolution) + Dithering Escalonado, (escalona o padrão do dithering para a resolução) + + + + Disable Interlacing (force progressive render/scan) + Desativa o entrelaçamento(força rederização progressiva) + + + + Force NTSC Timings (60hz-on-PAL) + Força o temporizador rodar em NTSC(60hz em jogos EU) + + + + Bilinear Texture Filtering + Filtragem de Textura Bilinear + + + + Widescreen Hack + Hack para Telas Widescreen + + + + Automatic based on window size + Automático, baseado no tamanho da janela aberta + + + + %1x (%2x%3 VRAM) + %1x (%2x%3 VRAM) + + + + (Default) + Padrão + + + + GameListModel + + + Type + + + + + Code + + + + + Title + + + + + File Title + + + + + Size + + + + + Region + + + + + Compatibility + + + + + GameListSearchDirectoriesModel + + + Path + Caminho + + + + Recursive + Recursivo + + + + GameListSettingsWidget + + + Form + Formulário + + + + Search Directories + Procurar + + + + Add + Adicionar + + + + Remove + Remover + + + + Scan New + Scanear Novos + + + + Rescan All + Rescanear Tudo + + + + Update Redump Database + Atualizar Base de Dados (Grupo Redump) + + + + Select Search Directory + Escolha o Diretório de Busca + + + + Scan Recursively? + Ler Recursivamente? + + + + Would you like to scan the directory "%1" recursively? + +Scanning recursively takes more time, but will identify files in subdirectories. + Gostaria der ler o diretório recursivamente? Ecanear o diretório desta forma demora mais tempo porém, identificará arquivos em sub-pastas. + + + + Download database from redump.org? + Baixar bando de dados do redump.org? + + + + Do you wish to download the disc database from redump.org? + +This will download approximately 4 megabytes over your current internet connection. + Quer baixar o banco de dados de CDs do redump.org? isto significa que serão baixados até 4megabytes de dados. + + + + Downloading %1... + Baixando %1... + + + + Cancel + Cancelar + + + + Download failed + Falha ao Baixar + + + + Extracting... + Extraindo... + + + + Extract failed + Falha na Extração + + + + Extracting game database failed. + Extração do banco de dados falhou. + + + + GamePropertiesDialog + + + Dialog + Dialogo + + + + Image Path: + Caminho da Imagem: + + + + Game Code: + Código do Jogo: + + + + Title: + Titulo: + + + + Region: + Região: + + + + Compatibility: + Compatibilidade: + + + + Upscaling Issues: + Problemas no Escalonamento: + + + + Comments: + Comentários: + + + + Version Tested: + Versão Testada: + + + + Set to Current + Definir para o Atual + + + + Tracks: + Faixas: + + + + # + # + + + + Mode + Modo + + + + Start + Iniciar + + + + Length + Comprimento + + + + Hash + Valores + + + + Compute Hashes + Calcular Valores + + + + Verify Dump + Validar Jogo + + + + Export Compatibility Info + Exportar Informação de Compatibilidade + + + + Close + Fechar + + + + Game Properties - %1 + Propriedades do Jogo - %1 + + + + %1 + %1 + + + + <not computed> + Não Gerado + + + + Not yet implemented + Ainda não Implementado + + + + Compatibility Info Export + Exportar Informação de compatibilidade + + + + Press OK to copy to clipboard. + Aperto OK para copiar para área de transferência. + + + + GeneralSettingsWidget + + + Form + Formulário + + + + Behaviour + Comportamento + + + + Pause On Start + Pausar ao Iniciar + + + + Confirm Power Off + Confirmar que Deseja Fechar + + + + Save State On Exit + Salvar ao Sair + + + + Load Devices From Save States + Carregar a partir do estado salvo + + + + Start Fullscreen + Iniciar em Tela Cheia + + + + Render To Main Window + Carregar Jogo na janela principal + + + + Emulation Speed + Velocidade da emulação + + + + 100% + 100% + + + + Enable Speed Limiter + Ativa Limitador de Velocidade + + + + Increase Timer Resolution + Aumentar Resolução em Tempo Real + + + + On-Screen Display + Mensagens na Tela + + + + Show Messages + Mostrar Mensagens + + + + Show FPS + Ah, que delicia cara rodando a 60 fps + Mostar FPS + + + + Show Emulation Speed + Mostrar velocidade de emulação + + + + Show VPS + Mostar VPS + + + + Enable Discord Presence + Ativar Presença Rica no Discord + + + + %1% + %1% + + + + InputBindingDialog + + + Edit Bindings + Edita as entradas dos botões já atribuidos + Editar Entradas + + + + Bindings for Controller0/ButtonCircle + Atribuições para o Primeiro Controle/BotãoCirculo + + + + Add Binding + Adicionar Atribuição + + + + Remove Binding + Remover Atribuição + + + + Clear Bindings + Limpar Atribuições + + + + Bindings for %1 %2 + Atribuições para %1 %2 + + + + + Push Button/Axis... [%1] + Aperte Botão/Eixos... [%1] + + + + InputBindingWidget + + + %1 bindings + %1 atribuições + + + + + Push Button/Axis... [%1] + Aperte Botão/Eixo... [%1] + + + + MainWindow + + + + + + DuckStation + DuckStation + + + + System + Sistema + + + + + Change Disc + Mudar Disco + + + + Load State + Carregar Estado + + + + Save State + Salvar Estado + + + + S&ettings + Configurações + + + + Theme + Tema + + + + Language + + + + + &Help + Ajuda + + + + &Debug + Depurar + + + + Switch GPU Renderer + Mudar Renderizador da GPU + + + + Switch CPU Emulation Mode + Mudar Modo de emulação para CPU + + + + toolBar + barra de ferramentas + + + + Start &Disc... + Iniciar Disco + + + + Start &BIOS + Tela de apresentação do Playstation 1 (Clássico) + Iniciar BIOS + + + + &Scan For New Games + Escanear por novos jogos + + + + &Rescan All Games + Rescanear todos os Jogos + + + + Power &Off + Desligar + + + + &Reset + Reiniciar + + + + &Pause + Pausar + + + + &Load State + Carregar Estado + + + + &Save State + Salvar Estado + + + + E&xit + Sair + + + + C&onsole Settings... + Configuração do Console + + + + &Controller Settings... + Configuração de Controles... + + + + &Hotkey Settings... + Configuração de Atalhos... + + + + &GPU Settings... + Configuração da GPU + + + + Fullscreen + Tela Cheia + + + + Resolution Scale + Escala de Resolução + + + + &GitHub Repository... + Repositório no Github... + + + + &Issue Tracker... + Rastreador de Problemas... + + + + &Discord Server... + Servidor no Discord... + + + + &About... + Sobre... + + + + Change Disc... + Mudar Disco... + + + + Audio Settings... + Configurações de Audio... + + + + Game List Settings... + Configurar lista de Jogos... + + + + General Settings... + Configurações Gerais... + + + + Advanced Settings... + Configurações Avançadas... + + + + Add Game Directory... + Adicionar Diretório de Jogo... + + + + &Settings... + Configurações... + + + + From File... + De Arquivo... + + + + From Game List... + Da lista de Jogos... + + + + Remove Disc + Remover Disco + + + + Resume State + Resumir Estado + + + + Global State + Estado Global + + + + Show VRAM + Mostrar VRAM + + + + Dump CPU to VRAM Copies + Despejar cópias do CPU para a VRAM + + + + Dump VRAM to CPU Copies + Despejar cópias da VRAM para o CPU + + + + Dump Audio + Despejar Audio + + + + Show GPU State + Mostrar Estado da GPU + + + + Show CDROM State + Mostrar estado do CD-Rom + + + + Show SPU State + Mostrar estado do SPU + + + + Show Timers State + Mostrar estado do Temporizador + + + + Show MDEC State + Mostrar estado do MDEC + + + + &Screenshot + Captura de Tela + + + + &Memory Card Settings... + Configurações de Cartões de Memória... + + + + Resume + Resumir + + + + Resumes the last save state created. + Resumir o último estado Salvo criado + + + + Failed to get window info from widget + Falha ao tentar obter informação da janela + + + + Failed to create host display device context. + Falha ao criar uma amostra de contexto da tela. + + + + Failed to get new window info from widget + Falha ao tentar obter novas informações da janela + + + + + Select Disc Image + Escolha uma imagem de Disco + + + + Properties... + Propriedades... + + + + Open Containing Directory... + Abrir diretório... + + + + Default Boot + Inicio Padrão + + + + Fast Boot + Inicio Rápido + + + + Full Boot + Inicia com a tela clássica do Playstation 1 + Inicio Completo + + + + Add Search Directory... + Adicione um diretório de busca... + + + + Language changed. Please restart the application to apply. + + + + + Default + Padrão + + + + DarkFusion + Tema escuro + Fusão Escura(DarkFusion) + + + + QDarkStyle + TemaQtEscuro + + + + MemoryCardSettingsWidget + + + If one of the "separate card per game" memory card modes is chosen, these memory cards will be saved to the memcards directory. + Se um dos modos de cartão de memória "cartão separado por jogo" for escolhido, esses cartões de memória serão salvos no diretório de cartões. + + + + Open... + Abrir... + + + + Memory Card %1 + Cartão de Memória %1 + + + + Memory Card Type: + Tipo de Cartão de Memória: + + + + Browse... + Procurar... + + + + Shared Memory Card Path: + Caminho de Cartões de Memória compartilhados: + + + + Select path to memory card image + Escolha o caminho para os Cartões de Memória + + + + QObject + + + DuckStation Error + Erro no Duckstation + + + + Failed to initialize host interface. Cannot continue. + + + + + Failed to open URL + + + + + Failed to open URL. + +The URL was: %1 + + + + + QtHostInterface + + + Resume + Resumir + + + + Load State + Carregar Estado + + + + Resume (%1) + Resumir (%1) + + + + %1 Save %2 (%3) + %1 Salvar %2 (%3) + + + + Game + Jogo + + + + Delete Save States... + Apagar jogos Salvos... + + + + Confirm Save State Deletion + Confirma deleção de Estado Salvo + + + + Are you sure you want to delete all save states for %1? + +The saves will not be recoverable. + Tem certeza de que quer apagar todos os estados salvos %1? +não será possivel reverter esta ação. + + + + QtProgressCallback + + + DuckStation + DuckStation + + + + Cancel + Cancelar + + + + Error + Erro + + + + + Question + Pergunta + + + + SettingsDialog + + + DuckStation Settings + Configurações + + + + General Settings + Config. Gerais + + + + Console Settings + Config. de Console + + + + Game List Settings + Config. Lista de Jogos + + + + Hotkey Settings + Config. de Atalhos + + + + Controller Settings + Config. de Controle + + + + Memory Card Settings + Config. Cartão de Memória + + + + GPU Settings + Config. GPU + + + + Audio Settings + Config. Audio + + + + Advanced Settings + Config. Avançadas + + + + Recommended Value + Valor Recomendado + + + diff --git a/src/duckstation-qt/update_translations.bat b/src/duckstation-qt/update_translations.bat new file mode 100644 index 000000000..6f02b66ad --- /dev/null +++ b/src/duckstation-qt/update_translations.bat @@ -0,0 +1,2 @@ +..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_pt.ts +pause \ No newline at end of file