Merge pull request #15 from OriolBonjoch/master

Removed notes, fixed footer gap and hide Twitter if not configured
This commit is contained in:
Olga 2019-11-25 08:53:46 -08:00 коммит произвёл GitHub
Родитель be4959e710 87082a2064
Коммит dec38c3d8f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
37 изменённых файлов: 1464 добавлений и 6437 удалений

Просмотреть файл

@ -1,19 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-dotnet.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-dotnet.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-dotnet.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-dotnet.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -1,19 +1,6 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.inf.ingress.game.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-game.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-game.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-game.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-game.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -1,19 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-java.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-java.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-java.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-java.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -11,5 +11,6 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
APPLICATION_INSIGHTS_IKEY: {{ .Values.inf.appinsights.id }}
APPLICATION_INSIGHTS_IKEY: {{ .Values.inf.appinsights.id }}
APPLICATION_INSIGHTS_ENABLED: {{ if .Values.inf.appinsights.id }}'true'{{ else }}'false'{{ end }}
PREDICTOR_URL: {{ .Values.inf.apiurls.predictor }}

Просмотреть файл

@ -1,19 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-node.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-node.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-node.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-node.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -1,19 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-php.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-php.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-php.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-php.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -1,19 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-python.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-python.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-python.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-python.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:80 to use your application"
kubectl port-forward $POD_NAME 80:80
{{- end }}

Просмотреть файл

@ -1,19 +1,9 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.inf.ingress.web.path }}
{{- if $.Values.uploaderEnabled }}
http{{ if $.Values.ingress.tlsEnabled }}s{{ end }}://{{ . }}{{ $.Values.inf.ingress.web.uploaderPath }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "rpsls-web.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "rpsls-web.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "rpsls-web.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "rpsls-web.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

Просмотреть файл

@ -6,16 +6,6 @@ inf:
googleanalytics:
id: {{googleanalyticsid}}
ingress:
dotnet:
path: /dotnet-player
node:
path: /node-player
python:
path: /python-player
php:
path: /php-player
java:
path: /java-player
game:
path: /game-manager
web:

Просмотреть файл

@ -6,16 +6,6 @@ inf:
googleanalytics:
id: {{googleanalyticsid}}
ingress:
dotnet:
path: /dotnet-player
node:
path: /node-player
python:
path: /python-player
php:
path: /php-player
java:
path: /java-player
game:
path: /game-manager
web:

Просмотреть файл

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.8.2" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.4.10" />
</ItemGroup>

Просмотреть файл

@ -7,9 +7,6 @@ using RPSLS.DotNetPlayer.Api.Services;
using RPSLS.DotNetPlayer.Api.Settings;
using RPSLS.DotNetPlayer.API.Services;
using RPSLS.DotNetPlayer.API.Settings;
using RPSLS.DotNetPlayer.API.Strategies;
using System;
using System.Net.Http;
namespace RPSLS.DotNetPlayer.API
{
@ -27,6 +24,7 @@ namespace RPSLS.DotNetPlayer.API
{
services.Configure<StrategySettings>(Configuration);
services.Configure<PredictorSettings>(Configuration);
services.AddApplicationInsightsTelemetry();
services.AddControllers();
services.AddHealthChecks();
services.AddHttpClient("Predictor");

Просмотреть файл

@ -39,7 +39,12 @@
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>applicationinsights-spring-boot-starter</artifactId>
<version>2.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>

Просмотреть файл

@ -1,2 +1,4 @@
rpsls.player.pick.strategy=${PICK_STRATEGY:random}
rpsls.predictor.pick.url=${PREDICTOR_URL:}
rpsls.predictor.pick.url=${PREDICTOR_URL:}
azure.application-insights.instrumentation-key=${APPLICATION_INSIGHTS_IKEY:00000000-0000-0000-0000-000000000000}
azure.application-insights.enabled=${APPLICATION_INSIGHTS_ENABLED:false}

Просмотреть файл

@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

Просмотреть файл

@ -1,9 +1,17 @@
const express = require('express');
const cors = require('cors');
require('dotenv').config();
const appInsights = require("applicationinsights");
const routes = require('./api/routes/index.route');
require('dotenv').config();
// Start application insights
const applicationInsightsIK = process.env.APPLICATION_INSIGHTS_IKEY;
if (applicationInsightsIK) {
appInsights.setup(applicationInsightsIK).start();
}
const app = express();
// Application-Level Middleware

1617
Source/Services/RPSLS.NodePlayer.Api/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -11,6 +11,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"applicationinsights": "^1.6.0",
"axios": "^0.19.0",
"cors": "^2.8.5",
"dotenv": "^8.1.0",

Просмотреть файл

@ -7,25 +7,29 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use App\Services\PickStrategyFactory;
use App\Services\PredictorProxy;
use App\Services\AppInsightsService;
class PickController extends BaseController
{
private $_context;
private $_strategy;
private $_predictor;
private $_appinsights;
public function __construct(PickStrategyFactory $strategyFactory, PredictorProxy $predictorProxy)
public function __construct(PickStrategyFactory $strategyFactory, PredictorProxy $predictorProxy, AppInsightsService $appinsights)
{
$this->_strategy = config('strategies.PICK_STRATEGY');
$strategyFactory->setDefaultStrategy($this->_strategy);
Log::info('Configured pick strategy with '.$this->_strategy);
$this->_context = $strategyFactory->getStrategy();
$this->_predictor = $predictorProxy;
$this->_appinsights = $appinsights;
}
public function index()
{
$username = Request::get('username', '');
$this->_appinsights->trackRequest('PickController:index()', 'GET /pick', time());
if($username != '') {
try {
$predicted = $this->_predictor->getPickPredicted($username);
@ -33,6 +37,7 @@ class PickController extends BaseController
return response()->json($predicted);
} catch(\Throwable $e) {
Log::error('Predictor had a problem');
$this->_appinsights->trackException($e);
}
}

Просмотреть файл

@ -20,5 +20,9 @@ class AppServiceProvider extends ServiceProvider
$this->app->singleton(PredictorProxy::class, function ($app) {
return new PredictorProxy();
});
$this->app->singleton(AppInsightsService::class, function($app) {
return new AppInsightsService();
});
}
}

Просмотреть файл

@ -0,0 +1,28 @@
<?php
namespace App\Services;
class AppInsightsService
{
private $_telemetryClient;
public function __construct()
{
$key = config('appinsights.APPLICATION_INSIGHTS_IKEY');
$this->_telemetryClient = new \ApplicationInsights\Telemetry_Client();
$context = $this->_telemetryClient->getContext();
$context->setInstrumentationKey($key);
}
public function trackRequest($name, $url, $startTime)
{
$this->_telemetryClient->trackRequest($name, $url, $startTime);
$this->_telemetryClient->flush();
}
public function trackException($ex)
{
$telemetryClient->trackException($ex);
$telemetryClient->flush();
}
}

Просмотреть файл

@ -93,6 +93,7 @@ $app->register(App\Providers\AppServiceProvider::class);
$app->configure('strategies');
$app->configure('predictor');
$app->configure('appinsights');
$app->router->group([
'namespace' => 'App\Http\Controllers',

Просмотреть файл

@ -6,8 +6,9 @@
"type": "project",
"require": {
"php": "^7.2",
"guzzlehttp/guzzle": "^6.4",
"laravel/lumen-framework": "^6.0"
"guzzlehttp/guzzle": "~5.0",
"laravel/lumen-framework": "^6.0",
"microsoft/application-insights": "~0.2.4"
},
"require-dev": {
"fzaninotto/faker": "^1.4",

5006
Source/Services/RPSLS.PHPPlayer.Api/src/composer.lock сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,5 @@
<?php
return [
'APPLICATION_INSIGHTS_IKEY' => getenv('APPLICATION_INSIGHTS_IKEY') ?: env('APPLICATION_INSIGHTS_IKEY', ''),
];

Просмотреть файл

@ -1,17 +1,24 @@
from flask import Flask, request
from healthcheck import HealthCheck
from applicationinsights.flask.ext import AppInsights
import logging
import os
from .pick import Picker
app = Flask(__name__)
appinsightskey = os.getenv('APPLICATION_INSIGHTS_IKEY', '')
if appinsightskey:
app.config['APPINSIGHTS_INSTRUMENTATIONKEY'] = appinsightskey
# log requests, traces and exceptions to the Application Insights service
appinsights = AppInsights(app)
health = HealthCheck()
app.add_url_rule("/healthcheck", "healthcheck", view_func=lambda: health.run())
app.add_url_rule('/pick', 'pick', view_func=Picker.as_view('picker'))
if __name__ == "__main__":
app.run(threaded=True)
else:

Просмотреть файл

@ -1,5 +1,4 @@
import random
import socket
from flask import jsonify
from .rpsls import RPSLS

Просмотреть файл

@ -1,3 +1,4 @@
gunicorn
flask
py-healthcheck
py-healthcheck
applicationinsights

Просмотреть файл

@ -1,174 +1,180 @@
@layout ConsoleLayout
@page "/battle"
@attribute [Authorize]
@inject IGameService Game
@inject BattleHelper battleHelper
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthenticationStateProvider
<div class="console-screen">
<p class="console-text">@Username</p>
<div class="user-picks">
<div class="user-picks-container">
@if (battleToBeStarted)
{
<div class="pick active toplay">
<div class="pick-images @(shakeHand ? "shakingHand" : string.Empty)">
<img class="@(battleHelper.GetAnimatedClass(shakeHand)) placeholder" src="/assets/images/png/hands/user/rock.png">
<img class="pick @(battleHelper.GetAnimatedClass(shakeHand))" src="/assets/images/png/hands/user/@(battleHelper.GetHandIcon(userHandToShow)).png">
<img class="base" src="/assets/images/png/hands/user/base.png">
</div>
</div>
}
else
{
@foreach (var pick in picks)
{
var active = pick.Value == Game.Pick;
<div class="pick selectable @(active ? "active" : string.Empty)" @onclick="() => SelectPick(pick)">
<div class="pick-images"><img src='@("/assets/images/png/hands/user/"+pick.Image+".png")'></div>
<p class="pick-text">@pick.Text</p>
</div>
@if (pick.BreakAfter)
{
<div class="break"></div>
}
}
}
</div>
</div>
@if (!battleToBeStarted)
{
<div class="cam-content">
<div class="cam-button"><a class="cam-link" href="/cambattle">use webcam</a></div>
</div>
}
</div>
@if (Game.Pick == -1 || battleToBeStarted)
{
<div class="console-vs">
<div class="vs-circle">
<p class="vs-text">VS</p>
</div>
</div>
}
else
{
<div class="console-vs">
<div class="start-battle-circle" @onclick="async () => await StartBattle()">
<p class="start-battle-text">start</p>
<p class="start-battle-text">battle</p>
</div>
</div>
}
<div class="console-screen">
<p class="console-text">@Game.Challenger?.DisplayName</p>
<div class="challenger-picks">
<div class="challenger-player challenger-picks-container">
@if (battleToBeStarted)
{
<div style="transform: scaleX(-1)" class="pick active toplay">
<div class="pick-images @(shakeHand ? "shakingHand" : string.Empty)">
<img class="@(battleHelper.GetAnimatedClass(shakeHand)) placeholder" src="/assets/images/png/hands/@Game.Challenger.Name/0.png">
@if (Game.GameResult != null)
{
<img class="pick @(battleHelper.GetAnimatedClass(shakeHand))" src="/assets/images/png/hands/@Game.Challenger.Name/@(battleHelper.GetHandIcon(Game.GameResult.ChallengerPick)).png">
}
<img class="base bot" src="/assets/images/png/hands/@Game.Challenger.Name/base.png">
</div>
</div>
}
else
{
@if (Game.Challenger != null)
{
<div class="challenger-image">
<div class="challenger-spiral">
<ul>
<li></li>
<li></li>
<li></li>
</ul>
<div class="challenger-circle challenger-circle-big"></div>
<div class="challenger-circle challenger-circle-small"></div>
</div>
<img src='@("/assets/images/png/"+Game.Challenger.Name+".png")'>
</div>
}
}
</div>
</div>
</div>
@code
{
[CascadingParameter] ConsoleLayout Layout { get; set; }
string Username = "-";
bool battleToBeStarted = false;
string userHandToShow = "rock";
bool shakeHand = false;
RPSLSViewModel pickedToPlay;
RPSLSViewModel[] picks;
bool isTwitterUser = false;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Layout.Initialize(title: "the battle", withHelp: true);
}
}
protected override async Task OnInitializedAsync()
{
if (Game.Challenger == null)
{
NavigationManager.NavigateTo("/challenger");
}
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
Username = state.User.Identity.Name;
isTwitterUser = state.User.Identity.AuthenticationType == "Twitter";
Game.Pick = -1;
picks = new RPSLSViewModel[]
{
new RPSLSViewModel { Text = "Rock", Value = 0, Image = "rock" },
new RPSLSViewModel { Text = "Paper", Value = 1, Image = "paper", BreakAfter = true },
new RPSLSViewModel { Text = "Scissors", Value = 2, Image = "scissors" },
new RPSLSViewModel { Text = "Lizard", Value = 3, Image = "lizard" },
new RPSLSViewModel { Text = "Spock", Value = 4, Image = "spock", BreakAfter = true }
};
}
void SelectPick(RPSLSViewModel pick)
{
pickedToPlay = pick;
Game.Pick = pick.Value;
}
private async Task ShakeHand()
{
battleToBeStarted = true;
shakeHand = true;
await Game.Play(Username, isTwitterUser);
await Task.Delay(2000);
shakeHand = false;
userHandToShow = pickedToPlay.Image;
StateHasChanged();
await Task.Delay(2000);
}
async Task StartBattle()
{
await ShakeHand();
NavigationManager.NavigateTo("/result");
}
}
@layout ConsoleLayout
@page "/battle"
@attribute [Authorize]
@inject IGameService Game
@inject BattleHelper battleHelper
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthenticationStateProvider
<div class="console-screen">
<p class="console-text">@Username</p>
<div class="user-picks">
<div class="user-picks-container">
@if (battleToBeStarted)
{
<div class="pick active toplay">
<div class="pick-images @(shakeHand ? "shakingHand" : string.Empty)">
<img class="@(battleHelper.GetAnimatedClass(shakeHand)) placeholder" src="/assets/images/png/hands/user/rock.png">
<img class="pick @(battleHelper.GetAnimatedClass(shakeHand))" src="/assets/images/png/hands/user/@(battleHelper.GetHandIcon(userHandToShow)).png">
<img class="base" src="/assets/images/png/hands/user/base.png">
</div>
</div>
}
else
{
@foreach (var pick in picks)
{
var active = pick.Value == Game.Pick;
<div class="pick selectable @(active ? "active" : string.Empty)" @onclick="() => SelectPick(pick)">
<div class="pick-images"><img src='@("/assets/images/png/hands/user/"+pick.Image+".png")'></div>
<p class="pick-text">@pick.Text</p>
</div>
@if (pick.BreakAfter)
{
<div class="break"></div>
}
}
}
</div>
</div>
@if (!battleToBeStarted)
{
<div class="cam-content">
<div class="cam-button"><a class="cam-link" href="/cambattle">use webcam</a></div>
</div>
}
</div>
@if (Game.Pick == -1 || battleToBeStarted)
{
<div class="console-vs">
<div class="vs-circle">
<p class="vs-text">VS</p>
</div>
</div>
}
else
{
<div class="console-vs">
<div class="start-battle-circle" @onclick="async () => await StartBattle()">
<p class="start-battle-text">start</p>
<p class="start-battle-text">battle</p>
</div>
</div>
}
<div class="console-screen">
<p class="console-text">@Game.Challenger?.DisplayName</p>
<div class="challenger-picks">
<div class="challenger-player challenger-picks-container">
@if (battleToBeStarted)
{
<div style="transform: scaleX(-1)" class="pick active toplay">
<div class="pick-images @(shakeHand ? "shakingHand" : string.Empty)">
<img class="@(battleHelper.GetAnimatedClass(shakeHand)) placeholder" src="/assets/images/png/hands/@Game.Challenger.Name/0.png">
@if (Game.GameResult != null)
{
<img class="pick @(battleHelper.GetAnimatedClass(shakeHand))" src="/assets/images/png/hands/@Game.Challenger.Name/@(battleHelper.GetHandIcon(Game.GameResult.ChallengerPick)).png">
}
<img class="base bot" src="/assets/images/png/hands/@Game.Challenger.Name/base.png">
</div>
</div>
}
else
{
@if (Game.Challenger != null)
{
<div class="challenger-image">
<div class="challenger-spiral">
<ul>
<li></li>
<li></li>
<li></li>
</ul>
<div class="challenger-circle challenger-circle-big"></div>
<div class="challenger-circle challenger-circle-small"></div>
</div>
<img src='@("/assets/images/png/"+Game.Challenger.Name+".png")'>
</div>
}
}
</div>
</div>
</div>
@code
{
[CascadingParameter] ConsoleLayout Layout { get; set; }
string Username = "-";
bool battleToBeStarted = false;
string userHandToShow = "rock";
bool shakeHand = false;
RPSLSViewModel pickedToPlay;
RPSLSViewModel[] picks;
bool isTwitterUser = false;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Layout.Initialize(title: "the battle", withHelp: true);
}
}
protected override async Task OnInitializedAsync()
{
if (Game.Challenger == null)
{
NavigationManager.NavigateTo("/challenger");
}
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
Username = state.User.Identity.Name;
isTwitterUser = state.User.Identity.AuthenticationType == "Twitter";
Game.Pick = -1;
picks = new RPSLSViewModel[]
{
new RPSLSViewModel { Text = "Rock", Value = 0, Image = "rock" },
new RPSLSViewModel { Text = "Paper", Value = 1, Image = "paper", BreakAfter = true },
new RPSLSViewModel { Text = "Scissors", Value = 2, Image = "scissors" },
new RPSLSViewModel { Text = "Lizard", Value = 3, Image = "lizard" },
new RPSLSViewModel { Text = "Spock", Value = 4, Image = "spock", BreakAfter = true }
};
}
void SelectPick(RPSLSViewModel pick)
{
pickedToPlay = pick;
Game.Pick = pick.Value;
}
private async Task ShakeHand()
{
battleToBeStarted = true;
shakeHand = true;
await Game.Play(Username, isTwitterUser);
if (!Game.GameResult.IsValid)
{
shakeHand = false;
return;
}
await Task.Delay(2000);
shakeHand = false;
userHandToShow = pickedToPlay.Image;
StateHasChanged();
await Task.Delay(2000);
}
async Task StartBattle()
{
await ShakeHand();
NavigationManager.NavigateTo("/result");
}
}

Просмотреть файл

@ -1,26 +1,35 @@
@layout MainLayout
@page "/"
<div class="index-content">
<div class="login">
<div class="login-section">
<form action="/api/account/login" method="get" autocomplete="off">
<img src='@("/assets/images/png/logo.png")'>
<div class="subtitle-container">
<h2 class="subtitle">Play the geek version of rock-paper-scissors.</h2>
<h2 class="subtitle">Can you defeat our bot?</h2>
</div>
<input name="username" class="user" type="text" placeholder="Type Username" required />
<div class="sign_twitter">or <a href="/api/account/login/twitter">Sign in with Twitter</a></div>
<div class="custom-button">
<button type="submit" class="custom-button-link">Enter Game</button>
</div>
</form>
</div>
</div>
<div class="github">
<a class="github-text" target="_blank" href="https://github.com/microsoft/RockPaperScissorsLizardSpock">Get the code from GitHub</a>
</div>
</div>
@layout MainLayout
@inject IOptions<TwitterOptions> TwitterOptions
@page "/"
<div class="index-content">
<div class="login">
<div class="login-section">
<form action="/api/account/login" method="get" autocomplete="off">
<img src='@("/assets/images/png/logo.png")'>
<div class="subtitle-container">
<h2 class="subtitle">Play the geek version of rock-paper-scissors.</h2>
<h2 class="subtitle">Can you defeat our bot?</h2>
</div>
<input name="username" class="user" type="text" placeholder="Type Username" required />
<div class="sign_twitter">
@if (!string.IsNullOrWhiteSpace(TwitterOptions?.Value?.ConsumerKey) && !string.IsNullOrWhiteSpace(TwitterOptions?.Value?.ConsumerSecret))
{
<span>or <a href="/api/account/login/twitter"> Sign in with Twitter</a></span>
}
</div>
<div class="custom-button">
<button type="submit" class="custom-button-link">Enter Game</button>
</div>
</form>
</div>
</div>
<div class="github">
<a class="github-text" target="_blank" href="https://github.com/microsoft/RockPaperScissorsLizardSpock">Get the code from GitHub</a>
</div>
</div>
<CookiesBanner />

Просмотреть файл

@ -1,172 +1,175 @@
@layout ConsoleLayout
@page "/result"
@attribute [Authorize]
@inject IGameService Game
@inject SvgHelper svgHelper
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager
<div class="result console-screen @resultStyle">
<p class="console-text">@result.User</p>
<div class="user-picks">
<div class="user-picks-container">
<div class="user-picks-items">
<div class="user-hand">
<img src='@("/assets/images/png/hands/user/"+MapPick(result.UserPick)+".png")'>
</div>
<p class="pick-text">@MapPick(result.UserPick)</p>
<p class="pick-text text-result">@resultMessage</p>
@if (userIsWinner || userIsLoser)
{
<p class="pick-text text-message">@CreateMessage(result.UserPick, result.ChallengerPick)</p>
}
</div>
</div>
</div>
<div class="custom-button-container">
<div class="custom-button">
<a class="custom-button-link" href="/battle">play again</a>
</div>
</div>
</div>
<div class="console-vs">
<div class="vs-circle">
<p class="vs-text">VS</p>
</div>
</div>
<div class="result console-screen">
<p class="console-text">@Game.Challenger?.DisplayName</p>
<div class="challenger-picks">
<div class="challenger-result challenger-picks-container">
@if (result.IsValid)
{
<div class="challenger-picks-items">
<div class="opponent-hand">
<img src='@("/assets/images/png/hands/" + result.Challenger + "/" + result.ChallengerPick + ".png")' />
</div>
<p class="pick-text">@MapPick(result.ChallengerPick)</p>
</div>
}
else if (error != null)
{
<div class="opponent-hand-error">
<img src='@("/assets/images/png/" + error.Image)'>
<h2>@error.Text</h2>
</div>
}
</div>
</div>
<div class="custom-button-container">
<div class="custom-button">
<a class="custom-button-link challenger" href="/challenger">choose opponent</a>
</div>
</div>
</div>
@code
{
ResultDto result = new ResultDto();
string resultMessage = null;
bool userIsWinner = false;
bool userIsLoser = false;
string resultStyle = "";
ChallengerErrorViewModel error = null;
ChallengerErrorViewModel[] errors = new ChallengerErrorViewModel[]
{
new ChallengerErrorViewModel() { Name = "python", Text = "how did I get here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "node", Text = "oooops, I have to update the rocket", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "dotnet", Text = "how did I end here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "java", Text = "how did I end here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "php", Text = "how did I end here?", Image = "node-error.png" }
};
[CascadingParameter] ConsoleLayout Layout { get; set; }
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Layout.Initialize(title: "results", withHelp: true, hasToShowGithub: true);
}
}
protected override void OnInitialized()
{
if (Game.GameResult == null)
{
NavigationManager.NavigateTo("/challenger");
return;
}
result.UserPick = Game.Pick;
result = Game.GameResult;
resultMessage = CreateResult(result.Result);
userIsWinner = result.Result == 1;
userIsLoser = result.Result == 2;
resultStyle = GetResultClass(result.Result);
error = errors.FirstOrDefault(c => c.Name == result.Challenger);
}
private string GetResultClass(int result)
{
return result switch
{
1 => "winner",
2 => "loser",
_ => ""
};
}
private string CreateResult(int result)
{
return result switch
{
1 => "you win!!",
2 => "you lose!!",
_ => "tie!!"
};
}
private static string MapPick(int pick)
{
return pick switch
{
0 => "rock",
1 => "paper",
2 => "scissors",
3 => "lizard",
4 => "spock",
_ => "-"
};
}
private static string MapAction(int winner, int loser)
{
return winner switch
{
0 => "crushes",
1 => loser == 0 ? "covers" : "disproves",
2 => loser == 1 ? "cuts" : "decapitates",
3 => loser == 1 ? "eats" : "poisons",
4 => loser == 0 ? "vaporizes" : "smashes",
_ => "ties"
};
}
private string CreateMessage(int userPick, int challengerPick)
{
var userPickText = MapPick(userPick);
var challengerPickText = MapPick(challengerPick);
if(userIsWinner)
{
return $"{userPickText} {MapAction(result.UserPick, result.ChallengerPick)} {challengerPickText}";
}
return $"{challengerPickText} {MapAction(result.ChallengerPick, result.UserPick)} {userPickText}";
}
}
@layout ConsoleLayout
@page "/result"
@attribute [Authorize]
@inject IGameService Game
@inject SvgHelper svgHelper
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager
<div class="result console-screen @resultStyle">
<p class="console-text">@result.User</p>
<div class="user-picks">
<div class="user-picks-container">
<div class="user-picks-items">
<div class="user-hand">
<img src='@("/assets/images/png/hands/user/"+MapPick(result.UserPick)+".png")'>
</div>
<p class="pick-text">@MapPick(result.UserPick)</p>
<p class="pick-text text-result">@resultMessage</p>
@if (userIsWinner || userIsLoser)
{
<p class="pick-text text-message">@CreateMessage(result.UserPick, result.ChallengerPick)</p>
}
</div>
</div>
</div>
<div class="custom-button-container">
<div class="custom-button">
<a class="custom-button-link" href="/battle">play again</a>
</div>
</div>
</div>
<div class="console-vs">
<div class="vs-circle">
<p class="vs-text">VS</p>
</div>
</div>
<div class="result console-screen">
<p class="console-text">@Game.Challenger?.DisplayName</p>
<div class="challenger-picks">
<div class="challenger-result challenger-picks-container">
@if (result.IsValid)
{
<div class="challenger-picks-items">
<div class="opponent-hand">
<img src='@("/assets/images/png/hands/" + result.Challenger + "/" + result.ChallengerPick + ".png")' />
</div>
<p class="pick-text">@MapPick(result.ChallengerPick)</p>
</div>
}
else if (error != null)
{
<div class="opponent-hand-error">
<img src='@("/assets/images/png/" + error.Image)'>
<h2>@error.Text</h2>
</div>
}
</div>
</div>
<div class="custom-button-container">
<div class="custom-button">
<a class="custom-button-link challenger" href="/challenger">choose opponent</a>
</div>
</div>
</div>
@code
{
ResultDto result = new ResultDto();
string resultMessage = string.Empty;
bool userIsWinner = false;
bool userIsLoser = false;
string resultStyle = "";
ChallengerErrorViewModel error = null;
ChallengerErrorViewModel[] errors = new ChallengerErrorViewModel[]
{
new ChallengerErrorViewModel() { Name = "python", Text = "how did I get here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "node", Text = "oooops, I have to update the rocket", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "dotnet", Text = "how did I end here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "java", Text = "how did I end here?", Image = "node-error.png" },
new ChallengerErrorViewModel() { Name = "php", Text = "how did I end here?", Image = "node-error.png" }
};
[CascadingParameter] ConsoleLayout Layout { get; set; }
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Layout.Initialize(title: "results", withHelp: true, hasToShowGithub: true);
}
}
protected override void OnInitialized()
{
if (Game.GameResult == null)
{
NavigationManager.NavigateTo("/challenger");
return;
}
result.UserPick = Game.Pick;
result = Game.GameResult;
if (result.IsValid)
{
resultMessage = CreateResult(result.Result);
userIsWinner = result.Result == 1;
userIsLoser = result.Result == 2;
}
resultStyle = GetResultClass(result.Result);
error = errors.FirstOrDefault(c => c.Name == result.Challenger);
}
private string GetResultClass(int result)
{
return result switch
{
1 => "winner",
2 => "loser",
_ => ""
};
}
private string CreateResult(int result)
{
return result switch
{
1 => "you win!!",
2 => "you lose!!",
_ => "tie!!"
};
}
private static string MapPick(int pick)
{
return pick switch
{
0 => "rock",
1 => "paper",
2 => "scissors",
3 => "lizard",
4 => "spock",
_ => "-"
};
}
private static string MapAction(int winner, int loser)
{
return winner switch
{
0 => "crushes",
1 => loser == 0 ? "covers" : "disproves",
2 => loser == 1 ? "cuts" : "decapitates",
3 => loser == 1 ? "eats" : "poisons",
4 => loser == 0 ? "vaporizes" : "smashes",
_ => "ties"
};
}
private string CreateMessage(int userPick, int challengerPick)
{
var userPickText = MapPick(userPick);
var challengerPickText = MapPick(challengerPick);
if (userIsWinner)
{
return $"{userPickText} {MapAction(result.UserPick, result.ChallengerPick)} {challengerPickText}";
}
return $"{challengerPickText} {MapAction(result.ChallengerPick, result.UserPick)} {userPickText}";
}
}

Просмотреть файл

@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Hosting;
@ -37,6 +38,7 @@ namespace RPSLS.Web
services.AddOptions();
services.Configure<RecognitionSettings>(Configuration);
services.Configure<GoogleAnalyticsSettings>(Configuration);
services.Configure<TwitterOptions>(Configuration.GetSection("Authentication:Twitter"));
services.Configure<GameManagerSettings>(Configuration.GetSection("GameManager"));
if (Configuration.GetValue<bool>("GameManager:Grpc:GrpcOverHttp", false))
{

Просмотреть файл

@ -1,13 +1,15 @@
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using RPSLS.Web
@using RPSLS.Web.Shared
@using RPSLS.Web.Services
@using RPSLS.Web.Models
@using RPSLS.Web.Helpers
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Authentication.Twitter
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.Extensions.Options
@using Microsoft.JSInterop
@using RPSLS.Web
@using RPSLS.Web.Shared
@using RPSLS.Web.Services
@using RPSLS.Web.Models
@using RPSLS.Web.Helpers
@using RPSLS.Web.Clients

Просмотреть файл

@ -15,7 +15,7 @@
flex-direction: column;
display: flex;
width: 100%;
min-height: calc(100vh - 250px);
min-height: calc(100vh - 199px);
background-image: url(../assets/images/svg/screens_panel.svg),
url(../assets/images/svg/platform_opponents.svg),
linear-gradient(

Просмотреть файл

@ -57,7 +57,7 @@ body {
/* Footer */
.footer {
height: 3.3rem;
height: 47px;
background-color: rgba(0, 0, 0, 0.4);
width: 100%;
display: flex;

Просмотреть файл

@ -1,142 +1,142 @@
/* Title */
.game-content-title {
position: relative;
margin: 0;
padding-top: 2.8rem;
margin-bottom: 2.7rem;
height: 75px;
font-family: "Voyager";
font-weight: 300;
font-size: 3.75rem;
text-shadow: 0 2px 2px rgba(0, 0, 0, 0.9);
line-height: 3.75rem;
color: #ffaa44;
text-align: center;
width: 100%;
position: relative;
margin: 0;
padding-top: 40px;
margin-bottom: 37px;
height: 75px;
font-family: "Voyager";
font-weight: 300;
font-size: 75px;
text-shadow: 0 2px 2px rgba(0, 0, 0, 0.9);
line-height: 75px;
color: #ffaa44;
text-align: center;
width: 100%;
}
.info-icon {
width: auto;
vertical-align: bottom;
height: 75px;
cursor: pointer;
width: auto;
vertical-align: bottom;
height: 75px;
cursor: pointer;
}
/* Modal Layout */
.modal {
position: fixed;
display: block;
z-index: 1;
padding-top: 9rem;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
display: block;
z-index: 1;
padding-top: 9rem;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.7);
}
.close {
position: absolute;
right: 0px;
top: 0px;
width: 32px;
height: 32px;
cursor: pointer;
opacity: 0.8;
position: absolute;
right: 0px;
top: 0px;
width: 32px;
height: 32px;
cursor: pointer;
opacity: 0.8;
}
.close:hover {
opacity: 1;
}
.close:hover {
opacity: 1;
}
.close:before,
.close:after {
position: absolute;
left: 15px;
content: " ";
height: 33px;
width: 2px;
background-color: rgb(255, 255, 255);
}
.close:before,
.close:after {
position: absolute;
left: 15px;
content: " ";
height: 33px;
width: 2px;
background-color: rgb(255, 255, 255);
}
.close:before {
transform: rotate(45deg);
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
.close:after {
transform: rotate(-45deg);
}
.modal-content {
position: relative;
background-color: #372369;
margin: auto;
max-width: 630px;
position: relative;
background-color: #372369;
margin: auto;
max-width: 630px;
}
.modal-content > div {
margin: 1.25rem;
}
.modal-content > div {
margin: 1.25rem;
}
.relationship-diagram {
display: flex;
align-items: center;
flex-direction: column;
}
.relationship-diagram h1 {
margin-bottom: 1.25rem;
color: #ffffff;
font-family: Voyager;
font-size: 32px;
margin: 2rem 0;
font-weight: 300;
line-height: 40px;
text-align: center;
}
.relationship-diagram img {
max-width: 430px;
margin-bottom: 100px;
height: auto;
}
@media (max-width: 992px) {
.info-icon {
width: auto;
vertical-align: bottom;
height: 30px;
cursor: pointer;
margin-left: 15px;
}
.game-content-title {
font-size: 2rem;
padding-top: 0;
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: center;
}
flex-direction: column;
}
.modal-content {
width: auto;
height: auto;
}
.relationship-diagram h1 {
margin-bottom: 1.25rem;
color: #ffffff;
font-family: Voyager;
font-size: 32px;
margin: 2rem 0;
font-weight: 300;
line-height: 40px;
text-align: center;
}
.relationship-diagram img {
width: 90%;
height: auto;
}
.relationship-diagram img {
max-width: 430px;
margin-bottom: 100px;
height: auto;
}
@media (max-width: 992px) {
.info-icon {
width: auto;
vertical-align: bottom;
height: 30px;
cursor: pointer;
margin-left: 15px;
}
.game-content-title {
font-size: 2rem;
padding-top: 0;
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
width: auto;
height: auto;
}
.relationship-diagram img {
width: 90%;
height: auto;
}
}
@media screen and (max-width: 576px) {
.mainTitle p.header {
font-size: 1.5rem;
font-weight: 500;
line-height: 3.1rem;
text-align: center;
margin: 0 2rem;
}
.mainTitle p.header {
font-size: 1.5rem;
font-weight: 500;
line-height: 3.1rem;
text-align: center;
margin: 0 2rem;
}
}

Просмотреть файл

@ -5,37 +5,44 @@ services:
ports:
- "5003:5000"
environment:
- PICK_STRATEGY=scissors
- APPLICATION_INSIGHTS_IKEY=
- PICK_STRATEGY=random
- PREDICTOR_URL=
node.player:
ports:
- "5002:3000"
environment:
- PICK_STRATEGY=paper
- APPLICATION_INSIGHTS_IKEY=
- PICK_STRATEGY=random
- PREDICTOR_URL=
dotnet.player:
ports:
- "5001:80"
environment:
- PICK_STRATEGY=rock
- APPINSIGHTS_INSTRUMENTATIONKEY=
- PICK_STRATEGY=random
- PREDICTOR_Url=
php.player:
ports:
- "5004:80"
environment:
- PICK_STRATEGY=lizard
- APPLICATION_INSIGHTS_IKEY=
- PICK_STRATEGY=random
- PREDICTOR_URL=
java.player:
ports:
- "5005:8080"
environment:
- PICK_STRATEGY=spock
- APPLICATION_INSIGHTS_IKEY=
- APPLICATION_INSIGHTS_ENABLED=false
- PICK_STRATEGY=random
- PREDICTOR_URL=
game.api:
ports:
- "5101:80"
- "5102:81"
environment:
- APPINSIGHTS_INSTRUMENTATIONKEY=
- GRPC_PORT=81
- Challengers__0__Url=http://dotnet.player/
- Challengers__1__Url=http://node.player:3000/
@ -46,6 +53,7 @@ services:
ports:
- "5100:80"
environment:
- APPINSIGHTS_INSTRUMENTATIONKEY=
- GameManager__Url=http://game.api:81/
- GameManager__Grpc__GrpcOverHttp=true
- Authentication__Twitter__ConsumerKey=
@ -56,6 +64,7 @@ services:
ports:
- "5110:80"
environment:
- APPINSIGHTS_INSTRUMENTATIONKEY=
- UploadPath=model
volumes:
- model-data:/app/model