Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • master
2 results

Target

Select target project
  • tmr/ld-simulator
1 result
Select Git revision
  • main
  • master
2 results
Show changes
Showing
with 2975 additions and 0 deletions
<!--
Rewrites requires Microsoft URL Rewrite Module for IIS
Download: https://www.microsoft.com/en-us/download/details.aspx?id=47337
Debug Help: https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-failed-request-tracing-to-trace-rewrite-rules
-->
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^(.*)/$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="/{R:1}" />
</rule>
<rule name="Imported Rule 2" stopProcessing="true">
<match url="^" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
window.Bus = new Vue();
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('population-index', require('./components/population-index.vue').default);
Vue.component('population-show', require('./components/population-show.vue').default);
Vue.component('population-template-show', require('./components/population-template-show.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
});
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.Popper = require('popper.js').default;
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
// import Echo from 'laravel-echo';
// window.Pusher = require('pusher-js');
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: process.env.MIX_PUSHER_APP_KEY,
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
// forceTLS: true
// });
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
<script>
import { Bar, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Bar,
mixins: [reactiveProp],
name: "bar-chart",
props: ['options'],
mounted () {
console.log("chart mounted");
this.renderChart(this.chartData, this.options)
}
}
</script>
<style scoped>
</style>
<script>
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
name: "line-chart",
props: ['options'],
mounted () {
console.log("chart mounted");
this.renderChart(this.chartData, this.options)
}
}
</script>
<style scoped>
</style>
<template>
<div class="modal fade" id="create-population-modal" tabindex="-1" role="dialog" aria-labelledby="create-population-modal-label">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="editOfficeModalLabel">
Add new population
</h4>
</div>
<div class="modal-body">
<div v-if="errorFeedback" class="alert alert-danger">
{{errorFeedback.toString()}}
<button class="float-right btn btn-sm btn-outline-info" @click.prevent="resetErrorFeedback">x</button>
</div>
<form>
<div class="container-fluid">
<div class="row form-group">
<div class="col-md-12 form-inline">
<label for="size_a"
:class="['col-md-6', validationErrors['name'] ? 'text-danger' : '']"
>Name (optional):</label>
<input type="text"
class="form-control col-md-6"
id="name"
v-model="population.name">
<span v-for="val_error in validationErrors['name']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="size_a"
:class="['col-md-6', validationErrors['forgetting_factor'] ? 'text-danger' : '']"
>Forgetting Factor (optional 1-100%):</label>
<input type="number"
class="form-control col-md-6"
id="forgetting_factor"
v-model="population.forgetting_factor">
<span v-for="val_error in validationErrors['forgetting_factor']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="size_a"
:class="['col-md-6', validationErrors['follower_factor'] ? 'text-danger' : '']"
>Follower Factor (optional inc/dec multiplier):</label>
<input type="number"
class="form-control col-md-6"
id="follower_factor"
v-model="population.follower_factor">
<span v-for="val_error in validationErrors['follower_factor']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<hr>
<div>
<i class="text-info">
Size of one group could be set to 0 if homogeneous population required.
</i>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="size_a"
:class="['col-md-6', validationErrors['size_a'] ? 'text-danger' : '']"
>Size A:</label>
<input type="number"
class="form-control col-md-6"
id="size_a"
v-model="population.size_a">
<span v-for="val_error in validationErrors['size_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="size_a"
:class="['col-md-6', validationErrors['size_b'] ? 'text-danger' : '']"
>Size B:</label>
<input type="number"
class="form-control col-md-6"
id="size_b"
v-model="population.size_b">
<span v-for="val_error in validationErrors['size_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div>
<i class="text-info">
Attributes should be in between 1 (worst) to 100 (best).
</i>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="init_expertise_a"
:class="['col-md-6', 'col-form-label', validationErrors['init_expertise_a'] ? 'text-danger' : '']"
>Expertise A (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_expertise_a"
v-model="population.init_expertise_a">
<span v-for="val_error in validationErrors['init_expertise_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="init_expertise_b"
:class="['col-md-6', 'col-form-label', validationErrors['init_expertise_b'] ? 'text-danger' : '']"
>Expertise B (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_expertise_b"
v-model="population.init_expertise_b">
<span v-for="val_error in validationErrors['init_expertise_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="spread_expertise_a"
:class="['col-md-6', 'col-form-label', validationErrors['spread_expertise_a'] ? 'text-danger' : '']"
>Expertise A (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_expertise_a"
v-model="population.spread_expertise_a">
<span v-for="val_error in validationErrors['spread_expertise_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="spread_expertise_b"
:class="['col-md-6', 'col-form-label', validationErrors['spread_expertise_b'] ? 'text-danger' : '']"
>Expertise B (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_expertise_b"
v-model="population.spread_expertise_b">
<span v-for="val_error in validationErrors['spread_expertise_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="init_confidence_a"
:class="['col-md-6', 'col-form-label', validationErrors['init_confidence_a'] ? 'text-danger' : '']"
>Confidence A (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_confidence_a"
v-model="population.init_confidence_a">
<span v-for="val_error in validationErrors['init_confidence_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="init_confidence_b"
:class="['col-md-6', 'col-form-label', validationErrors['init_confidence_b'] ? 'text-danger' : '']"
>Confidence B (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_confidence_b"
v-model="population.init_confidence_b">
<span v-for="val_error in validationErrors['init_confidence_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="spread_confidence_a"
:class="['col-md-6', 'col-form-label', validationErrors['spread_confidence_a'] ? 'text-danger' : '']"
>Confidence A (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_confidence_a"
v-model="population.spread_confidence_a">
<span v-for="val_error in validationErrors['spread_confidence_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="spread_confidence_b"
:class="['col-md-6', 'col-form-label', validationErrors['spread_confidence_b'] ? 'text-danger' : '']"
>Confidence B (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_confidence_b"
v-model="population.spread_confidence_b">
<span v-for="val_error in validationErrors['spread_confidence_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="init_following_a"
:class="['col-md-6', 'col-form-label', validationErrors['init_following_a'] ? 'text-danger' : '']"
>Following A (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_following_a"
v-model="population.init_following_a">
<span v-for="val_error in validationErrors['init_following_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="init_following_b"
:class="['col-md-6', 'col-form-label', validationErrors['init_following_b'] ? 'text-danger' : '']"
>Following B (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_following_b"
v-model="population.init_following_b">
<span v-for="val_error in validationErrors['init_following_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="spread_following_a"
:class="['col-md-6', 'col-form-label', validationErrors['spread_following_a'] ? 'text-danger' : '']"
>Following A (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_following_a"
v-model="population.spread_following_a">
<span v-for="val_error in validationErrors['spread_following_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="spread_following_b"
:class="['col-md-6', 'col-form-label', validationErrors['spread_following_b'] ? 'text-danger' : '']"
>Following B (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_following_b"
v-model="population.spread_following_b">
<span v-for="val_error in validationErrors['spread_following_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="init_leadership_a"
:class="['col-md-6', 'col-form-label', validationErrors['init_leadership_a'] ? 'text-danger' : '']"
>Leadership A (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_leadership_a"
v-model="population.init_leadership_a">
<span v-for="val_error in validationErrors['init_leadership_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="init_leadership_b"
:class="['col-md-6', 'col-form-label', validationErrors['init_leadership_b'] ? 'text-danger' : '']"
>Leadership B (init):</label>
<input type="number"
class="form-control col-md-6"
id="init_leadership_b"
v-model="population.init_leadership_b">
<span v-for="val_error in validationErrors['init_leadership_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
<div class="row form-group">
<div class="col-md-6 form-inline">
<label for="spread_leadership_a"
:class="['col-md-6', 'col-form-label', validationErrors['spread_leadership_a'] ? 'text-danger' : '']"
>Leadership A (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_leadership_a"
v-model="population.spread_leadership_a">
<span v-for="val_error in validationErrors['spread_leadership_a']" class="text-danger">{{ val_error}}</span>
</div>
<div class="col-md-6 form-inline">
<label for="spread_leadership_b"
:class="['col-md-6', 'col-form-label', validationErrors['spread_leadership_b'] ? 'text-danger' : '']"
>Leadership B (spread):</label>
<input type="number"
class="form-control col-md-6"
id="spread_leadership_b"
v-model="population.spread_leadership_b">
<span v-for="val_error in validationErrors['spread_leadership_b']" class="text-danger">{{ val_error}}</span>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" v-on:click.prevent="clearAndClose()">Cancel</button>
<button type="button" class="btn btn-primary" v-on:click.prevent="addNewPopulation()">
Save
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "population-create",
mounted() {
},
data() {
return {
validationErrors: [],
errorFeedback: null,
population: {
name: null,
size_a: 0,
forgetting_factor: 1,
follower_factor: 100,
init_expertise_a: 50,
spread_expertise_a: 0,
init_confidence_a: 50,
spread_confidence_a: 0,
init_following_a: 50,
spread_following_a: 0,
init_leadership_a: 50,
spread_leadership_a: 0,
size_b: 0,
init_expertise_b: 50,
spread_expertise_b: 0,
init_confidence_b: 50,
spread_confidence_b: 0,
init_following_b: 50,
spread_following_b: 0,
init_leadership_b: 50,
spread_leadership_b: 0
}
}
},
methods: {
resetErrorFeedback() {
this.errorFeedback = null;
},
addNewPopulation() {
console.log('add...');
console.log(this.population);
axios.post(route('internal.api.templates.post'), this.population).then((response) => {
console.log(response.data);
Bus.$emit('TemplateCreated', true, response.data.meta);
this.clearAndClose();
}).catch((err) => {
console.log(err.response.data);
this.errorFeedback = err.response.data.message;
if (err.response.data.val_errors) {
this.validationErrors = err.response.data.val_errors;
} else {
this.validationErrors = [];
}
});
},
clearAndClose() {
this.validationErrors = [];
this.errorFeedback = null;
$('#create-population-modal').modal('hide');
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="p-2">
<div class="row">
<div class="col-md-6 col-lg-6 col-sm-6">
<div class="card">
<div class="card-header">Status</div>
<div class="card-body">
<div class="alert alert-info" v-if="feedback">
INFO: {{feedback}}
<button class="float-right btn btn-sm btn-outline-info" @click.prevent="resetFeedback">x</button>
</div>
<div class="alert alert-primary" v-if="creationFeedback">
{{creationFeedback}}
<button class="float-right btn btn-sm btn-outline-info" @click.prevent="resetCreationFeedback">x</button>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Populations</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 col-lg-6">
<button data-target="#create-population-modal" data-toggle="modal">
Add top level template
</button>
</div>
<div class="col-md-6 col-lg-6">
<input type="checkbox" v-model="show_top_level_only">
<label class="text-info">Show only top level templates</label>
</div>
</div>
<hr>
<div>
<i class="text-info">Select population template for details.</i>
</div>
<div class="btn-group-vertical">
<span v-on:click.prevent="selectPopulation(population)"
v-for="population in populations"
class="btn btn-outline-info"
v-bind:class="{'btn-info text-white': (current_population != null && current_population.id == population.id)}"
>
<span class="badge badge-light" v-if="population.parent_id">child</span>
<span class="badge badge-info" v-else>top level</span>
{{population.name}} <i>voters: {{population.voters_stats.no_of_voters}},</i>
<br><i>Number of child-populations: {{population.children_count}}</i>
<br><i>Number of elections run on template: </i>
<br>
<i v-for="election in population.elections_stats">(type-{{election.type}}: # {{election.count}})</i>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-6 col-sm-6">
<div v-if="current_population">
<div class="card">
<div class="card-header">{{current_population.name}}</div>
<div class="card-body">
<div>
Voters' and child-populations details and new elections available in
<a :href="getLink(current_population.id)">Population Template detail view</a>
</div>
<div>
Reputation settings:
<li>Forgetting: {{current_population.forgetting_factor}} % <i class="text-muted">(inc/dec towards 0 after each election)</i></li>
<li>Follower: {{current_population.follower_factor}} <i class="text-muted">(inc/dec multiplier per follower)</i></li>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Child Populations stats</div>
<div v-if="current_population.child_populations_stats" class="card-body">
<p>
Number of child populations locked to election type:
</p>
<table>
<thead>
<th>Type</th>
<th>Description</th>
<th>Total</th>
<th>Learning</th>
<th>Performance</th>
</thead>
<tbody>
<tr v-for="(election_type, key) in current_population.child_populations_stats">
<td>{{key}}</td>
<td>{{election_type.info}}</td>
<td>{{election_type.count}}</td>
<td>{{election_type.learning_stage_count}}</td>
<td>{{election_type.performance_stage_count}}</td>
</tr>
</tbody>
</table>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
<div class="card">
<div class="card-header">Voters stats</div>
<div v-if="current_population.voters_stats" class="card-body">
<bar-chart :chart-data="population_voters_stats_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
min: 0,
max: 100
}
}]
}}"
:styles="{height: 200}"></bar-chart>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
<div class="card">
<div class="card-header">Population Template election stats</div>
<div v-if="current_population.elections_stats" class="card-body">
<bar-chart :chart-data="population_election_stats_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
min: 0,
max: 100
}
}]
}}"
:styles="{height: 200}"></bar-chart>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
</div>
<div v-else>
<i class="text-muted">no population selected</i>
</div>
</div>
</div>
<population-create></population-create>
</div>
</template>
<script>
import PopulationCreate from "./population-create";
import BarChart from "./charts/bar-chart";
export default {
name: "population-index",
components: {PopulationCreate, BarChart},
data() {
return {
show_top_level_only: true,
current_population: null,
feedback: null,
creationFeedback: null,
populations: [],
h_400_chart_styles: {
height: '400px',
width: '100%',
position: 'relative'
}
}
},
mounted() {
this.feedback = 'Fetching population index..';
this.fetchPopulationIndex();
this.feedback = 'Population index fetched (newest first).';
Bus.$on('TemplateCreated', (refresh, data) => {
if (data) {
this.creationFeedback = "Population template created, time: " + data.total_time;
this.fetchPopulationIndex();
}
if (refresh === true) {
this.feedback = 'Population template added reloading index..';
this.fetchPopulationIndex(true);
this.feedback = 'Index reloaded. Newest population template selected.';
}
});
},
computed: {
population_election_stats_chart_data() {
console.log('computing population_election_stats');
let colors = [
'#205702',
'#b7b30e',
'#97510a',
'#b22430',
'#45026a'
];
let color_idx = 0;
let labels = [
'correct (avg #)', 'incorrect (avg #)', 'correct (%)'
];
let datasets = [];
let no_of_voters = this.current_population.voters_stats ? this.current_population.voters_stats.no_of_voters : 0;
this.current_population.elections_stats.forEach(election_type => {
let election_type_set = [];
election_type_set.push(election_type.no_of_correct_average);
election_type_set.push(election_type.no_of_incorrect_average);
election_type_set.push(election_type.percent_correct);
datasets.push({
label: election_type.type + '(#:' + election_type.count + ')',
backgroundColor: colors[color_idx],
data: election_type_set
});
color_idx = color_idx < 4 ? color_idx + 1 : 0;
});
return {
labels: labels,
datasets: datasets
}
},
population_voters_stats_chart_data() {
console.log('computing population_voters_stats_chart_data');
let colors = [
'#205702',
'#b7b30e',
'#97510a',
'#b22430',
'#45026a'
];
let color_idx = 0;
let labels = [
'count', 'Expertise (avg)', 'Confidence (avg)', 'Following (avg)', 'Leadership (avg)'
];
let groups = [];
this.current_population.voters_stats.groups.forEach(voters_group => {
let voters_group_set = [];
voters_group_set.push(voters_group.no_of_voters);
voters_group_set.push(voters_group.expertise_average);
voters_group_set.push(voters_group.confidence_average);
voters_group_set.push(voters_group.following_average);
voters_group_set.push(voters_group.leadership_average);
groups.push({
label: 'group:' + voters_group.name,
backgroundColor: colors[color_idx],
data: voters_group_set,
yAxisID: 'left-y-axis'
});
color_idx = color_idx < 4 ? color_idx + 1 : 0;
});
return {
labels: labels,
datasets: groups
}
},
},
watch: {
show_top_level_only: function() {
this.feedback = this.show_top_level_only ? "Refreshing top level only" : "Refreshing including child populations in performance stage";
this.fetchPopulationIndex();
}
},
methods: {
resetFeedback() {
this.feedback = null;
},
resetCreationFeedback() {
this.creationFeedback = null;
},
selectPopulation(population) {
if (this.current_population && (this.current_population.id == population.id)) {
this.current_population = null;
} else {
this.current_population = population;
}
},
fetchPopulationIndex(selectFirst = false) {
this.populations = [];
axios.get(route('internal.api.templates.index'),
{params: {'top_level_only': this.show_top_level_only ? 1 : 0}}
).then((response) => {
this.populations = response.data;
if(selectFirst && this.populations[0]) {
this.current_population = this.populations[0]
}
}).catch((err) => {
this.feedback = 'population data error';
});
},
getLink(templateId) {
return route('template.show', templateId);
},
addPopulation() {
console.log('add population');
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="p-2">
<div class="row">
<div class="col-md-3 col-lg-3">
<div class="col-md-12">
<div class="card">
<div class="card-header">{{population_name}}</div>
<div class="card-body" >
<div>
<a :href="getTemplateLink(population_stats.parent_id)">Back to parent template</a>
</div>
<hr>
<div v-if="stage_name">
<div v-if="population_stats.stage === 'l'">
<h6>Learning stage</h6>
<h6>{{election_name}}</h6>
<div class="col-md-12 col-lg-12">
<button v-if="population_stats.stage === 'l'" @click.prevent="switchToPerformanceStage()">
Finish Learning stage
</button>
</div>
<h6>Reputation modifiers:</h6>
<div class="col-md-12 col-lg-12">
<ul>
<li class="text-info">Forgetting percent: {{population_stats.forgetting_factor}}</li>
<li class="text-info">Follower multiplier: {{population_stats.follower_factor}}</li>
</ul>
</div>
<h6>Expertise:</h6>
<div class="col-md-12 col-lg-12">
<ul>
<li class="text-info">Maximum: {{population_stats.voters_stats.expertise_max}}</li>
<li class="text-info">Average: {{population_stats.voters_stats.expertise_average}}</li>
</ul>
</div>
<h6>Elections</h6>
<div class="col-md-12 col-lg-12">
<label class="text-info">Number of elections: </label>
<input type="number" min="1" max="100" step="0" v-model="custom_number_elections" style="width:70px">
<button :disabled="running_elections_lock" class="btn btn-sm btn-outline-info" @click.prevent="runElections(population_stats.election_type, custom_number_elections)">
Run {{custom_number_elections}} election<span v-if="custom_number_elections > 1">s</span>
</button>
</div>
</div>
<div v-else-if="population_stats.stage === 'p'">
<h5>Performance stage</h5>
<h5>{{election_name}}</h5>
<div>
<a :href="getTemplateLink(population_id)">Switch to template view</a></div>
<h5>Elections</h5>
<div>
<label class="text-info">Number of elections: </label>
<input type="number" min="1" max="100" step="0" v-model="custom_number_elections" style="width:70px">
<button :disabled="running_elections_lock" class="btn btn-sm btn-outline-info" @click.prevent="runElections('d1', custom_number_elections)">
Run {{custom_number_elections}} election<span v-if="custom_number_elections > 1">s</span>
</button>
</div>
</div>
<div v-else>
<i class="text-warning">Unrecognized stage code.</i>
</div>
<h5>Chart display options</h5>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_population_stats">
<label class="text-info">Show population stats</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_last_election_chart">
<label class="text-info">Show last elections chart</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_voters_graph">
<label class="text-info">Show voters graph</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_timeline_graph">
<label class="text-info">Show timeline graph (results)</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_weights_timeline_graph">
<label class="text-info">Show timeline graph (weights)</label>
</div>
</div>
<div v-else>
<i>Population stage not defined. Cannot run elections.</i>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Voters' attributes charts</div>
<div class="card-body">
<div class="row">
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="auto_fetch_voters">
<label class="text-info">Auto update voters' details after election</label>
</div>
<div class="col-md-12 col-lg-12">
<button class="btn btn-sm btn-outline-info" @click.prevent="fetchPopulationDetails">Fetch Voters Data</button>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Elections timeline (type selector)</div>
<div class="card-body">
<div class="row">
<div class="col-md-12 col-lg-12">
<v-select :options="election_timeline_selector"
id="election_timeline_selector"
v-model="current_election_timeline_key"
placeholder="Choose election type"
label="text">
</v-select>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Elections timeline (results)</div>
<div class="card-body">
<div class="row">
<div class="col-md-12 col-lg-12">
<label class="text-info">Moving average</label>
<input type="number" min="0" step="1" v-model="moving_average" style="width:70px">
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="auto_fetch_elections_timeline">
<label class="text-info">Auto update timeline after election</label>
</div>
<div class="col-md-12 col-lg-12">
<button :disabled="!current_election_timeline_key"
v-on:click.prevent="fetchElectionsTimeline"
v-bind:class="{'btn-primary' : current_election_timeline_key }"
class="btn-xs">
<i v-if="current_election_timeline_key">Fetch {{current_election_timeline_key.text}} results timeline</i>
<i v-else>Select election type</i>
</button>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Elections timeline (weights)</div>
<div class="card-body">
<div class="row">
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="auto_fetch_weights_timeline">
<label class="text-info">Auto update weights timeline after election</label>
</div>
<div class="col-md-12 col-lg-12">
<button :disabled="!current_election_timeline_key"
v-on:click.prevent="fetchWeightsTimeline"
v-bind:class="{'btn-primary' : current_election_timeline_key }"
class="btn-xs">
<i v-if="current_election_timeline_key">Fetch {{current_election_timeline_key.text}} weights timeline</i>
<i v-else>Select election type</i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-9 col-lg-9">
<div class="row mt-1">
<div class="alert alert-info col-md-12 col-lg-12" v-if="feedback">
<button class="btn btn-sm btn-outline-info" @click.prevent="resetFeedback">x</button>
INFO: {{feedback}}
</div>
</div>
<div v-if="population_stats" class="row mt-1">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-header">Last elections status</div>
<div class="card-body">
<div class="row" v-if="last_elections_data">
<div class="col-md-4 col-lg-4 col-sm-4">
Election type: <i>{{last_elections_data.elections_type}}</i>
</div>
<div class="col-md-4 col-lg-4 col-sm-4">
Number of elections: <i>{{last_elections_data.number_of_elections}}</i>
</div>
<div class="col-md-4 col-lg-4 col-sm-4">
Total time: <i>{{last_elections_data.total_time}}</i>
</div>
</div>
<div v-else-if="running_elections_lock"><i class="text-info">Elections in progress....</i></div>
<div v-else><i>N/A (run elections first)</i></div>
</div>
</div>
</div>
</div>
<div v-if="population_stats" class="row mt-1">
<div class="col-md-12">
<div class="card" v-if="show_voters_graph">
<div class="card-header">Voters' attributes charts</div>
<div class="card-body">
<div v-if="voters_fetched">
<div v-if="show_voters_graph">
<line-chart :chart-data="voters_chart_data" :options="voters_chart_options" :styles="h_300_chart_styles"></line-chart>
</div>
<i v-else>select show graph</i>
</div>
<div v-else>
<i>N/A</i>
</div>
</div>
</div>
</div>
</div>
<div v-if="population_stats" class="row mt-1">
<div class="col-md-12 col-lg-12">
<div class="card" v-if="show_timeline_graph">
<div class="card-header">Elections timeline (results)</div>
<div class="card-body">
<div v-if="elections_timeline" >
<hr>
Election type: <i>{{elections_timeline.elections_type}}</i>,
Number of elections: <i>{{elections_timeline.no_of_elections}}</i>,
Number of voters: <i>{{elections_timeline.no_of_voters}}</i>
<div v-if="show_timeline_graph">
<line-chart :chart-data="election_timeline_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [{id: 'left-y-axis',type: 'linear',position: 'left',ticks: {min: 0, max:100}}]
}
}"
:styles="h_500_chart_styles"
></line-chart>
</div>
<div v-else>
<i>select show graph</i>
</div>
</div>
<div v-else-if="!current_election_timeline_key">
<i>N/A use Election Timeline Selector to mark election type</i>
</div>
<div v-else><i>N/A yet. Use "Fetch Timeline Results" or mark "Auto Update" and run elections</i></div>
</div>
</div>
<div class="card" v-if="show_weights_timeline_graph">
<div class="card-header">Elections timeline (weights)</div>
<div class="card-body">
<div v-if="weights_timeline" >
<hr>
Election type: <i>{{weights_timeline.elections_type}}</i>,
Number of elections: <i>{{weights_timeline.no_of_elections}}</i>,
Number of voters: <i>{{weights_timeline.no_of_voters}} (A:{{weights_timeline.no_of_voters_a}}, B:{{weights_timeline.no_of_voters_b}})</i>
<div v-if="show_weights_timeline_graph">
<h5>Timeline for delegation weights</h5>
<line-chart :chart-data="weights_timeline_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [
{id: 'left-y-axis',type: 'linear',position: 'left'},
{id: 'right-y-axis',type: 'linear',position: 'right',ticks: {min: 0, max:100}}
]
}
}"
:styles="h_500_chart_styles"
></line-chart>
</div>
<div v-else>
<i>select show graph</i>
</div>
</div>
<div v-else-if="!current_election_timeline_key">
<i>N/A use Election Timeline Selector to mark election type</i>
</div>
<div v-else><i>N/A yet. Use "Fetch Timeline Weights" or mark "Auto Update" and run elections</i></div>
</div>
</div>
</div>
</div>
<div class="row mt-1">
<div class="col-md-6 col-lg-6 col-sm-6" v-if="show_population_stats">
<div v-if="population_stats" class="row mt-1">
<div class="col-md-6 col-lg-6">
<div class="card">
<div class="card-header">Election stats</div>
<div v-if="population_stats.elections_stats" class="card-body">
<bar-chart :chart-data="population_election_stats_chart_data" :options="{
maintainAspectRatio: true,
scales: {
yAxes: [{id: 'left-y-axis',type: 'linear',position: 'left',ticks: {min: 0,max: 100}}]
}
}"></bar-chart>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
</div>
<div class="col-md-6 col-lg-6">
<div class="card">
<div class="card-header">Voters stats</div>
<div v-if="population_stats.voters_stats" class="card-body">
<bar-chart :chart-data="population_voters_stats_chart_data" :options="{
maintainAspectRatio: true,
scales: {
yAxes: [{id: 'left-y-axis',type: 'linear',position: 'left',ticks: {min: 0,max: 100}}]
}
}"
></bar-chart>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
</div>
</div>
<div class="row mt-1" v-if="show_majority_distribution">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-header">Majority elections distribution</div>
<div class="card-body">
<div>
<label class="text-info">Auto update ME distribution after elections</label>
<input type="checkbox" v-model="auto_fetch_distribution">
</div>
<div v-if="me_distribution_metadata">
<div v-if="majority_elections_distribution">
<div class="row">
<bar-chart :chart-data="me_chart_data" :options="{maintainAspectRatio: true}" class="col-md-6"></bar-chart>
<bar-chart :chart-data="me_chart_data_r_10" :options="{maintainAspectRatio: true}" class="col-md-6"></bar-chart>
</div>
<div>
Number of elections: <i>{{me_distribution_metadata.number_of_elections}}</i>
<br>
Total time: <i>{{me_distribution_metadata.total_time}}</i>
<br>
Distribution of correct choices percentage in {{me_distribution_metadata.number_of_elections}} elections:
<br>
Charts: Majority Elections correct answers distribution (grouped by 1 and 10 percent)
<br>
(by 1): {{majority_elections_distribution}}
<br>
(by 10): {{majority_elections_distribution_r_10}}
</div>
</div>
</div>
<div v-else><i>N/A (fetch distribution first)</i></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-1">
<div class="col-md-12 col-lg-12" v-if="show_last_election_chart">
<div v-if="population_stats" class="row mt-1">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-header">Last elections chart</div>
<div class="card-body">
<div v-if="last_elections_data">
<bar-chart v-if="show_last_election_chart"
:chart-data="last_elections_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [{id: 'left-y-axis',type: 'linear',position: 'left',ticks: {min: 0}}]
}
}"
:styles="{height: 200}"
></bar-chart>
</div>
<div v-else><i>N/A (run elections first)</i></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import LineChart from "./charts/line-chart";
import BarChart from "./charts/bar-chart";
import vSelect from "vue-select";
import 'vue-select/dist/vue-select.css';
export default {
name: "population-show",
components: {LineChart, BarChart, vSelect},
data() {
return {
show_population_stats: false,
show_majority_distribution: false,
show_last_election_chart: false,
show_voters_graph: false,
show_timeline_graph: false,
show_weights_timeline_graph: false,
custom_number_elections: 1,
current_election_timeline_key: null,
election_timeline_selector : [
{
value: 'm',
text: 'Majority (m)'
},
{
value: 'd1',
text: 'Delegation (d1)'
},
{
value: 'd2',
text: 'Delegation (d2)'
},
{
value: 'd3',
text: 'Delegation (d3)'
}
],
elections_timeline: null,
moving_average: 0,
auto_fetch_elections_timeline: false,
weights_timeline: null,
auto_fetch_weights_timeline: false,
running_elections_lock: false,
auto_fetch_voters: false,
auto_fetch_distribution: false,
feedback : null,
population_id: route().params.population_id,
template_id: route().params.template_id,
population_stats: null,
population_name: null,
voters_fetched: false,
voters: [],
last_elections_data: null,
election_feedback: null,
majority_elections_distribution: null,
majority_elections_distribution_r_10: null,
me_distribution_metadata: null,
chart_data_fetched: false,
voters_chart_options: {
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
min: 0,
max: 100
}
}, {
id: 'right-y-axis',
type: 'linear',
position: 'right'/*,
ticks: {
min: -50,
max: 50
}*/
}]
}
},
h_300_chart_styles: {
height: '300px',
width: '100%',
position: 'relative'
},
h_500_chart_styles: {
height: '500px',
width: '100%',
position: 'relative'
}
}
},
mounted() {
if (this.auto_fetch_voters) {
this.fetchPopulationDetails();
}
this.fetchPopulationStats()
},
computed: {
election_name() {
if (this.population_stats) {
return this.election_timeline_selector.filter(election_type => {
return election_type.value === this.population_stats.election_type;
})[0].text;
}
return null;
},
stage_name() {
if (this.population_stats) {
switch (this.population_stats.stage) {
case 'l': return "Learning";
case 'p': return "Performance";
default: return "Unrecognized stage";
}
}
return null;
},
population_election_stats_chart_data() {
console.log('computing population_election_stats');
let colors = [
'#205702',
'#b7b30e',
'#97510a',
'#b22430',
'#45026a'
];
let color_idx = 0;
let labels = [
'correct (avg #)', 'incorrect (avg #)', 'correct (%)'
];
let datasets = [];
let no_of_voters = this.population_stats.voters_stats ? this.population_stats.voters_stats.no_of_voters : 0;
this.population_stats.elections_stats.forEach(election_type => {
let election_type_set = [];
election_type_set.push(election_type.no_of_correct_average);
election_type_set.push(election_type.no_of_incorrect_average);
election_type_set.push(election_type.percent_correct);
datasets.push({
label: election_type.type + '(#:' + election_type.count + ')',
backgroundColor: colors[color_idx],
data: election_type_set,
yAxisID: 'left-y-axis'
});
color_idx = color_idx < 4 ? color_idx + 1 : 0;
});
return {
labels: labels,
datasets: datasets
}
},
population_voters_stats_chart_data() {
console.log('computing population_voters_stats_chart_data');
let colors = [
'#205702',
'#b7b30e',
'#97510a',
'#b22430',
'#45026a'
];
let color_idx = 0;
let labels = [
'Expertise (avg)', 'Confidence (avg)', 'Following (avg)', 'Leadership (avg)'
];
let groups = [];
this.population_stats.voters_stats.groups.forEach(voters_group => {
let voters_group_set = [];
voters_group_set.push(voters_group.expertise_average);
voters_group_set.push(voters_group.confidence_average);
voters_group_set.push(voters_group.following_average);
voters_group_set.push(voters_group.leadership_average);
groups.push({
label: 'group:' + voters_group.name + ' (#' + voters_group.no_of_voters + ')',
backgroundColor: colors[color_idx],
data: voters_group_set,
yAxisID: 'left-y-axis'
});
color_idx = color_idx < 4 ? color_idx + 1 : 0;
});
return {
labels: labels,
datasets: groups
}
},
voters_chart_data() {
console.log('computing voters chart data');
let labels = [];
let expertise = [];
let confidence = [];
let following = [];
let leadership = [];
let reputation = [];
let m_percent_correct = [];
let d1_percent_correct = [];
let d1_as_independent = [];
let d1_as_follower = [];
let d1_as_delegate = [];
let d2_percent_correct = [];
let d2_as_independent = [];
let d2_as_follower = [];
let d2_as_delegate = [];
let diff = [];
this.voters.forEach((value, idx) => {
labels.push(idx);
expertise.push(value.expertise);
confidence.push(value.confidence);
following.push(value.following);
leadership.push(value.leadership);
reputation.push(value.reputation);
m_percent_correct.push(value.majority_votes_stats.percent_correct);
//diff.push(value.majority_votes_stats.percent_correct - value.expertise);
d1_percent_correct.push(value.delegation_one_votes_stats.percent_finals_correct);
d1_as_independent.push(value.delegation_one_votes_stats.as_independent);
d1_as_follower.push(value.delegation_one_votes_stats.as_follower);
d1_as_delegate.push(value.delegation_one_votes_stats.as_delegate);
d2_percent_correct.push(value.delegation_two_votes_stats.percent_finals_correct);
d2_as_independent.push(value.delegation_two_votes_stats.as_independent);
d2_as_follower.push(value.delegation_two_votes_stats.as_follower);
d2_as_delegate.push(value.delegation_two_votes_stats.as_delegate);
});
return {
labels: labels,
datasets: [
{
label: 'expertise',
borderColor: '#039876',
fill: false,
data: expertise,
yAxisID: 'left-y-axis'
},
{
label: 'confidence',
borderColor: '#479c38',
fill: false,
data: confidence,
yAxisID: 'left-y-axis'
},
{
label: 'following',
borderColor: '#029689',
fill: false,
data: following,
yAxisID: 'left-y-axis'
},
{
label: 'leadership',
borderColor: '#2f779b',
fill: false,
data: leadership,
yAxisID: 'left-y-axis'
},
{
label: 'percent correct (M)',
borderColor: '#9a9b69',
fill: false,
data: m_percent_correct,
yAxisID: 'left-y-axis'
},
{
label: 'percent correct (D1)',
borderColor: '#966c44',
fill: false,
data: d1_percent_correct,
yAxisID: 'left-y-axis'
},/*
{
label: 'diff cor-exp (M)',
borderColor: '#51121d',
fill: false,
data: diff,
yAxisID: 'right-y-axis'
},*/
{
label: 'as independent (D1)',
borderColor: '#ebf04b',
fill: false,
data: d1_as_independent,
yAxisID: 'right-y-axis'
},
{
label: 'as follower (D1)',
borderColor: '#ffe136',
fill: false,
data: d1_as_follower,
yAxisID: 'right-y-axis'
},
{
label: 'as delegate (D1)',
borderColor: '#b7b30e',
fill: false,
data: d1_as_delegate,
yAxisID: 'right-y-axis'
},
{
label: 'percent correct (D2)',
borderColor: '#964625',
fill: false,
data: d2_percent_correct,
yAxisID: 'left-y-axis'
},
{
label: 'as independent (D2)',
borderColor: '#f0ba4e',
fill: false,
data: d2_as_independent,
yAxisID: 'right-y-axis'
},
{
label: 'as follower (D2)',
borderColor: '#ff8843',
fill: false,
data: d2_as_follower,
yAxisID: 'right-y-axis'
},
{
label: 'as delegate (with followers) (D2)',
borderColor: '#b75135',
fill: false,
data: d2_as_delegate,
yAxisID: 'right-y-axis'
},
{
label: 'reputation',
borderColor: '#000000',
fill: false,
data: reputation,
yAxisID: 'right-y-axis'
}
]
}
},
me_chart_data() {
console.log('computing me_chart_data');
let labels = [];
let dataset = [];
this.majority_elections_distribution.forEach((value, idx) => {
labels.push(idx);
dataset.push(value);
});
return {
labels: labels,
datasets: [
{
label: 'ME by 1 percent',
backgroundColor: '#0073ff',
data: dataset
}
]
};
},
me_chart_data_r_10() {
console.log('computing me_chart_data rounded to 10');
let labels = ['0-9','11-19','20-29','30-39','40-49','50-59','60-69','70-79','80-89','90-100'];
let dataset = [];
let counter = 0;
this.majority_elections_distribution_r_10.forEach((value) => {
dataset.push(value);
});
return {
labels: labels,
datasets: [
{
label: 'ME by 10 percent',
backgroundColor: '#0073ff',
data: dataset
}
]
};
},
last_elections_chart_data() {
console.log('computing last_elections_chart_data');
let colors = [
'#205702',
'#b7b30e',
'#97510a',
'#b22430',
'#45026a'
];
let color_idx = 0;
let labels;
let datasets = [];
let election_type = this.last_elections_data.elections_type;
switch (election_type) {
case 'd1':
labels = [
'Correct (#)', 'Incorrect (#)', 'Correct (%)',
'Delegates (#)', 'Followers (#)', 'Independent (#)'
];
break;
default:
labels = [
'Correct (#)', 'Incorrect (#)', 'Correct (%)'
];
}
this.last_elections_data.elections.forEach((item, idx) => {
let election_set = [];
election_set.push(item.total_correct_choices);
election_set.push(item.total_incorrect_choices);
election_set.push(item.percent_correct_choices);
switch (election_type) {
case 'd1':
election_set.push(item.as_delegate);
election_set.push(item.as_follower);
election_set.push(item.as_independent);
break;
default:
// basic chart dataset
}
datasets.push({
label: 'election ' + (idx + 1),
backgroundColor: colors[color_idx],
data: election_set,
yAxisID: 'left-y-axis'
});
color_idx = color_idx < 4 ? color_idx + 1 : 0;
});
return {
labels: labels,
datasets: datasets
};
},
election_timeline_chart_data() {
console.log('computing election trend chart data');
let labels = [];
let percent_correct = [];
let expertise = [];
let expertise_max = [];
let avg_expertise = this.population_stats.voters_stats.expertise_average;
let max_expertise = this.population_stats.voters_stats.expertise_max;
this.elections_timeline.elections.forEach((value,idx) => {
labels.push(idx);
percent_correct.push(value);
expertise.push(avg_expertise);
expertise_max.push(max_expertise);
});
return {
labels: labels,
datasets: [
{
label: 'Timeline for percent correct in type-' + this.elections_timeline.elections_type + ' elections',
borderColor: '#479c38',
fill: false,
data: percent_correct,
yAxisID: 'left-y-axis'
},
{
label: 'Average population Expertise',
borderColor: '#666666',
fill: false,
data: expertise,
yAxisID: 'left-y-axis'
},
{
label: 'Max population Expertise',
borderColor: '#666666',
fill: false,
data: expertise_max,
yAxisID: 'left-y-axis'
}
]
}
},
weights_timeline_chart_data() {
console.log('computing weights chart data');
let labels = [];
let avg_weight_a = [];
let avg_weight_b = [];
let reputation_a = [];
let reputation_b = [];
let weight_share_b = [];
this.weights_timeline.weights.forEach((value,idx) => {
labels.push(idx);
avg_weight_a.push(value.avg_weight_a);
avg_weight_b.push(value.avg_weight_b);
reputation_a.push(value.reputation_a);
reputation_b.push(value.reputation_b);
weight_share_b.push(value.weight_share_b);
});
return {
labels: labels,
datasets: [
{
label: 'Group A (avg Weight per voter)',
borderColor: '#6b9c3a',
fill: false,
data: avg_weight_a,
yAxisID: 'left-y-axis'
},
{
label: 'Group B (avg Weight per voter)',
borderColor: '#01439b',
fill: false,
data: avg_weight_b,
yAxisID: 'left-y-axis'
},
{
label: 'Group A - Reputation sum',
borderColor: '#929c84',
fill: false,
data: reputation_a,
yAxisID: 'left-y-axis'
},
{
label: 'Group B - Reputation sum',
borderColor: '#6c739b',
fill: false,
data: reputation_b,
yAxisID: 'left-y-axis'
},
{
label: 'Group B - Weight share: wB/(wA+wB)',
borderColor: '#b77959',
backgroundColor: '#b77959',
fill: true,
data: weight_share_b,
yAxisID: 'right-y-axis'
}
]
}
}
},
methods: {
resetFeedback() {
this.feedback = null;
},
getTemplateLink(templateId) {
return route('template.show', templateId);
},
fetchPopulationDetails() {
this.feedback = 'fetching voters data..';
axios.get(route(
'internal.api.population.get.voters',
{
"template":this.template_id,
"population":this.population_id
}
)).then((response) => {
this.feedback = 'voters data fetched';
this.voters = response.data;
this.voters_fetched = true;
}).catch((err) => {
this.feedback = 'voters data fetching error';
});
},
fetchPopulationStats() {
this.feedback = 'fetching population stats..';
axios.get(route(
'internal.api.population.get',
{
"template":this.template_id,
"population":this.population_id
}
)).then((response) => {
this.feedback = 'population stats fetched';
this.population_stats = response.data;
this.population_name = response.data.name;
if (this.auto_fetch_voters) {
this.fetchPopulationDetails();
}
if (this.auto_fetch_distribution) {
this.fetchMajorityElectionsDistribution();
}
if (this.auto_fetch_elections_timeline) {
this.fetchElectionsTimeline();
}
if (this.auto_fetch_weights_timeline) {
this.fetchWeightsTimeline();
}
}).catch((err) => {
this.feedback = 'population stats fetching error';
});
},
runElections(type, multi) {
if (this.running_elections_lock) {
this.feedback = 'already running elections, please wait...';
} else {
this.running_elections_lock = true;
this.feedback = 'running ' + type + '-type elections: (' + multi + ')...';
this.last_elections_data = null;
axios.post(
route(
'internal.api.elections.run',
{
"template":this.template_id,
"population":this.population_id
}),
{
type: type,
number:multi
}).then((response) => {
this.feedback = 'voting done, fetching updated population stats..';
console.log(this);
this.fetchPopulationStats();
this.last_elections_data = response.data;
this.running_elections_lock = false;
}).catch((err) => {
this.feedback = 'election error';
this.running_elections_lock = false;
});
}
},
switchToPerformanceStage() {
axios.post(route(
'internal.api.population.stage.update',
{
"template":this.template_id,
"population":this.population_id
}
)).then((response) => {
this.population_stats.stage = 'p';
this.feedback = "Changed population stage. Only elections that do not alter attributes are available.";
}).catch((err) => {
this.feedback = "Error while changing stage.";
});
},
fetchMajorityElectionsDistribution() {
this.feedback = 'fetching majority distribution...';
this.me_distribution_metadata = null;
axios.get(
route(
'internal.api.majority.distribution.get',
{
"template":this.template_id,
"population":this.population_id
}
)).then((response) => {
this.feedback = 'majority distribution fetched';
this.majority_elections_distribution = response.data.distribution;
this.majority_elections_distribution_r_10 = response.data.distribution_r_10;
this.me_distribution_metadata = response.data.metadata;
}).catch((err) => {
this.feedback = 'majority distribution fetching error';
});
},
fetchElectionsTimeline() {
axios.get(
route(
'internal.api.population.get.elections.timeline',
{
"template":this.template_id,
"population":this.population_id
}
), {
params: {
'type': this.current_election_timeline_key.value,
'moving_average': this.moving_average
}
}).then((response) => {
this.elections_timeline = response.data;
this.feedback = 'election timeline fetched';
}).catch((err) => {
this.feedback = 'election timeline fetching error';
});
},
fetchWeightsTimeline() {
console.log(this.current_election_timeline_key);
axios.get(
route(
'internal.api.population.get.weights.timeline',
{
"template":this.template_id,
"population":this.population_id
}
), {
params: {
'type': this.current_election_timeline_key.value,
'moving_average': this.moving_average
}
}).then((response) => {
this.weights_timeline = response.data;
this.feedback = 'weights timeline fetched';
}).catch((err) => {
this.feedback = 'weights timeline fetching error';
});
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="p-2">
<div class="row">
<div class="col-md-3 col-lg-3">
<div class="col-md-12" v-if="current_template">
<div class="card" >
<div class="card-header">{{current_template.name}}</div>
<div class="card-body">
<div>
<div v-if="current_template.parent_id">
<a :href="getTemplateLink(current_template.parent_id)">Back to parent template</a>
</div>
<hr>
<h6>Reputation modifiers:</h6>
<div class="col-md-12 col-lg-12">
<ul>
<li class="text-info">Forgetting percent: {{current_template.forgetting_factor}}</li>
<li class="text-info">Follower multiplier: {{current_template.follower_factor}}</li>
</ul>
</div>
<h6>Expertise:</h6>
<div class="col-md-12 col-lg-12">
<ul>
<li class="text-info">Maximum: {{current_template.voters_stats.expertise_max}}</li>
<li class="text-info">Average: {{current_template.voters_stats.expertise_average}}</li>
</ul>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">Display options</div>
<div class="card-body">
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_child_populations_details">
<label class="text-info">Show child population details</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_child_populations_in_main">
<label class="text-info">Show stats in main frame</label>
</div>
<div class="col-md-12 col-lg-12">
<input type="checkbox" v-model="show_analytics_weights">
<label class="text-info">Show weights analytics</label>
</div>
</div>
</div>
<div class="card" v-if="!show_child_populations_in_main">
<div class="card-header">Child Populations stats</div>
<div v-if="current_template.child_populations_stats" class="card-body">
<h5>
Number of child populations locked to election type
</h5>
<table class="table table-striped table-borderless">
<thead>
<th>Action</th>
<th>Type</th>
<th>Description</th>
<th>L</th>
<th>P</th>
</thead>
<tbody>
<tr v-for="(election_type, key) in current_template.child_populations_stats">
<td>
<button class="btn btn-success btn-sm" @click.prevent="addChildPopulation(key)">
Add +
</button>
</td>
<td>{{key}}</td>
<td>{{election_type.info}}</td>
<td>{{election_type.learning_stage_count}}</td>
<td>{{election_type.performance_stage_count}}</td>
</tr>
</tbody>
</table>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
</div>
<div v-else><i>Template not loaded</i></div>
</div>
<div class="col-md-9 col-lg-9">
<div class="row">
<div class="alert alert-info col-md-12 col-lg-12" v-if="feedback">
INFO: {{feedback}}
<button class="float-right btn btn-sm btn-outline-info" @click.prevent="resetFeedback">x</button>
</div>
</div>
<div v-if="current_template">
<div class="row">
<div class="col-md-12 col-lg-12">
<div class="card" v-if="show_child_populations_in_main">
<div class="card-header">Child Populations stats</div>
<div v-if="current_template.child_populations_stats" class="card-body">
<p>
Number of child populations locked to election type:
</p>
<table class="table table-striped table-borderless">
<thead>
<th>Action</th>
<th>Type</th>
<th>Description</th>
<th>Total</th>
<th>Learning</th>
<th>Performance</th>
</thead>
<tbody>
<tr v-for="(election_type, key) in current_template.child_populations_stats">
<td>
<button @click.prevent="addChildPopulation(key)">
Add child population
</button>
</td>
<td>{{key}}</td>
<td>{{election_type.info}}</td>
<td>{{election_type.count}}</td>
<td>{{election_type.learning_stage_count}}</td>
<td>{{election_type.performance_stage_count}}</td>
</tr>
</tbody>
</table>
</div>
<div v-else class="card-body"><i>N/A</i></div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12" >
<div class="card" v-if="show_analytics_weights">
<div class="card-header">Analytics. Elections timeline (weights)</div>
<div class="card-body">
<div class="row">
<div class="col-md-4 col-lg-4">
<v-select :options="election_type_selector"
id="election_timeline_selector"
v-model="current_election_timeline_key"
placeholder="Choose election type"
label="text">
</v-select>
</div>
<div class="col-md-4 col-lg-4">
<button :disabled="!current_election_timeline_key"
v-on:click.prevent="fetchWeightsTimeline"
v-bind:class="{'btn-primary' : current_election_timeline_key }"
class="btn-xs">
<i v-if="current_election_timeline_key">Fetch {{current_election_timeline_key.text}} weights timeline</i>
<i v-else>Select election type</i>
</button>
</div>
<div class="col-md-4 col-lg-4">
<input type="checkbox" v-model="auto_fetch_weights_timeline">
<label class="text-info">Auto update weights timeline after election</label>
</div>
</div>
<hr>
<div class="row" v-if="analytics_weights_timeline" >
<div class="col-md-12 col-lg-12">
<h5>Timeline for delegation weights</h5>
Number of child populations: <strong>{{analytics_weights_timeline.no_of_child_populations}}</strong> locked to election type - <strong>{{analytics_weights_timeline.report_metadata.election_type}}</strong>,
<br>
Number of voters: <strong>(A:{{analytics_weights_timeline.no_of_voters_a}}, B:{{analytics_weights_timeline.no_of_voters_b}})</strong>
<br>
Number of elections: <strong>{{analytics_weights_timeline.min_election_count}}</strong>
<i>(maximum number in a single child population: {{analytics_weights_timeline.max_election_count}}</i>)
<line-chart :chart-data="weights_timeline_chart_data"
:options="{
maintainAspectRatio: false,
scales: {
yAxes: [
{id: 'left-y-axis',type: 'linear',position: 'left'},
{id: 'right-y-axis',type: 'linear',position: 'right',ticks: {min: 0, max:1}}
]
}
}"
:styles="h_500_chart_styles"
></line-chart>
</div>
</div>
<div v-else-if="!current_election_timeline_key">
<i>N/A use Election Timeline Selector to mark election type</i>
</div>
<div v-else><i>N/A yet. Use "Fetch Timeline Weights" or mark "Auto Update" and run elections</i></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 col-lg-12">
<div class="card" v-if="show_child_populations_details">
<div class="card-header">Child Populations</div>
<div class="card-body">
<div class="col-md-12 col-lg-12">
<h5>Run quick elections of population primary type for selected child population</h5>
<div class="row">
<div class="col-md-12 col-lg-12">
<h6>Summary results of performance mode delegation voting</h6>
<div v-if="performance_mode_results">
<ul>
<li>
d2:
<i v-if="performance_mode_results.d2" class="text-primary">
Elections: {{performance_mode_results.d2.election_count}}
, Correct percent: {{performance_mode_results.d2.percent_correct}}
</i>
<span v-else>N/A</span>
</li>
<li>
d3:
<i v-if="performance_mode_results.d3" class="text-primary">
Elections: {{performance_mode_results.d3.election_count}}
, Correct percent: {{performance_mode_results.d3.percent_correct}}
</i>
<span v-else>N/A</span>
</li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="col-md-9 col-lg-9">
<h6>Last elections status: </h6>
<div v-if="last_elections_data" class="text-info">
[DONE]
Population: ({{last_elections_data.population_name}}),
Election type: ({{last_elections_data.elections_type}}),
Number of elections: ({{last_elections_data.number_of_elections}}),
Time: ({{last_elections_data.total_time}})
</div>
<div v-else-if="running_elections_lock">
<i class="text-info">
Running {{custom_number_elections}} election<span v-if="custom_number_elections > 1">s ...</span>
</i>
</div>
<div v-else><i class="text-muted">N/A (run elections first)</i></div>
</div>
<div class="col-md-3 col-lg-3">
<label class="text-info">Number of elections: </label>
<input type="number" min="1" max="100" step="0" v-model="custom_number_elections" style="width:70px">
</div>
</div>
</div>
<table class="table table-striped">
<thead>
<th>Type</th>
<th>Name</th>
<th>Stage</th>
<th v-for="election_type in election_type_selector">
{{election_type.text}}
</th>
<th>Run elections</th>
</thead>
<tbody>
<tr v-bind:class="{'bg-info': (current_child_population != null && current_child_population.id == child_population.id)}"
v-for="(child_population, key) in current_template.child_populations">
<td v-on:click.prevent="childPopulationRowClicked(child_population)"
>{{child_population.election_type}}</td>
<td>
<a class="btn btn-primary" :href="getChildPopulationLink(child_population.id)">{{child_population.name}}</a>
</td>
<td>
<strong>{{child_population.stage}}</strong>
<button v-if="child_population.stage === 'l'" class="btn btn-sm btn-warning" @click.prevent="switchToPerformanceStage(key)">
>> P
</button>
</td>
<td v-on:click.prevent="childPopulationRowClicked(child_population)"
v-for="election_type in child_population.elections_stats">
<span v-if="election_type.count > 0">Count: {{election_type.count}} (avg corr: {{election_type.percent_correct.toFixed(2)}})</span>
<i v-else>N/A</i>
</td>
<td>
<button :disabled="running_elections_lock" class="btn btn-sm btn-success" @click.prevent="runElections(key, custom_number_elections)">
Run {{custom_number_elections}} ({{child_population.stage === 'p' ? 'd1' : child_population.election_type}}) election<span v-if="custom_number_elections > 1">s</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div v-else><i>N/A Template not loaded</i></div>
</div>
</div>
</div>
</template>
<script>
import LineChart from "./charts/line-chart";
import vSelect from "vue-select";
import 'vue-select/dist/vue-select.css';
export default {
name: "population-template-show",
components: {LineChart, vSelect},
data() {
return {
current_election_timeline_key: null,
auto_fetch_weights_timeline: false,
analytics_weights_timeline: null,
show_child_populations_details: true,
show_child_populations_in_main: false,
show_analytics_weights: false,
current_child_population: null,
custom_number_elections: 1,
running_elections_lock: false,
last_elections_data: null,
performance_mode_results: null,
election_type_selector : [
{
value: 'm',
text: 'Majority (m)',
info: 'Majority election, check expertise only'
},
{
value: 'd1',
text: 'Delegation (d1)',
info: 'Delegation voting, no adjustments (performance stage)'
},
{
value: 'd2',
text: 'Delegation (d2)',
info: 'Delegation voting, include reputation adjustments (learning stage)'
},
{
value: 'd3',
text: 'Delegation (d3)',
info: 'Delegation voting, include reputation and voters attributes adjustments (learning stage)'
}
],
current_template: null,
feedback: null,
template_id: route().params.template_id,
template_name: null,
h_500_chart_styles: {
height: '500px',
width: '100%',
position: 'relative'
}
}
},
computed: {
weights_timeline_chart_data() {
console.log('computing weights chart data');
let labels = [];
let avg_sum_weight_a = [];
let min_sum_weight_a = [];
let max_sum_weight_a = [];
let avg_sum_weight_b = [];
let min_sum_weight_b = [];
let max_sum_weight_b = [];
let share_sum_weight_b = [];
let min_share_sum_weight_b = [];
let max_share_sum_weight_b = [];
let diff_share_sum_weight_b = [];
this.analytics_weights_timeline.weights.forEach((value,idx) => {
labels.push(idx);
avg_sum_weight_a.push(value.avg_sum_weight_a);
min_sum_weight_a.push(value.min_sum_weight_a);
max_sum_weight_a.push(value.max_sum_weight_a);
avg_sum_weight_b.push(value.avg_sum_weight_b);
min_sum_weight_b.push(value.min_sum_weight_b);
max_sum_weight_b.push(value.max_sum_weight_b);
share_sum_weight_b.push(value.share_sum_weight_b);
min_share_sum_weight_b.push(value.min_share_sum_weight_b);
max_share_sum_weight_b.push(value.max_share_sum_weight_b);
diff_share_sum_weight_b.push(value.diff_share_sum_weight_b);
});
return {
labels: labels,
datasets: [
{
label: 'Group A (avg sum Weight)',
borderColor: '#169c03',
fill: false,
data: avg_sum_weight_a,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group A (min sum Weight)',
borderColor: '#819c67',
fill: false,
data: min_sum_weight_a,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group A (max sum Weight)',
borderColor: '#819c67',
fill: false,
data: max_sum_weight_a,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group B (avg sum Weight)',
borderColor: '#00259b',
fill: false,
data: avg_sum_weight_b,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group B (min sum Weight)',
borderColor: '#517e9b',
fill: false,
data: min_sum_weight_b,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group B (max sum Weight)',
borderColor: '#517e9b',
fill: false,
data: max_sum_weight_b,
yAxisID: 'left-y-axis',
hidden: true
},
{
label: 'Group B - Weight share',
borderColor: '#b73c33',
fill: false,
data: share_sum_weight_b,
yAxisID: 'right-y-axis'
},
{
label: 'Group B - min Weight share',
borderColor: '#b78365',
fill: false,
data: min_share_sum_weight_b,
yAxisID: 'right-y-axis',
hidden: true
},
{
label: 'Group B - max Weight share',
borderColor: '#b78365',
fill: false,
data: max_share_sum_weight_b,
yAxisID: 'right-y-axis',
hidden: true
},
{
label: 'Group B - DIFF Weight share',
borderColor: '#b75d02',
fill: false,
data: diff_share_sum_weight_b,
yAxisID: 'left-y-axis'
}
]
}
}
},
mounted() {
this.fetchPopulationTemplate();
},
methods: {
childPopulationRowClicked(childPopulation) {
if (this.current_child_population != null && childPopulation.id == this.current_child_population.id) {
this.current_child_population = null;
} else {
this.current_child_population = childPopulation;
}
},
resetFeedback() {
this.feedback = null;
},
getTemplateLink(templateId) {
return route('template.show', templateId);
},
fetchPopulationTemplate() {
this.feedback = 'fetching population template details..';
axios.get(route('internal.api.template.get', this.template_id)).then((response) => {
this.feedback = 'population template details fetched';
this.current_template = response.data;
this.updateTotalSums();
}).catch((err) => {
this.feedback = 'population template fetching error';
})
},
addChildPopulation(key) {
this.feedback = 'Adding child population, binding ' + key;
axios.post(
route('internal.api.populations.post', this.current_template.id),
{"election_type":key}
).then((response) => {
this.feedback = 'Child population added';
this.fetchPopulationTemplate();
}).catch((err) => {
this.feedback = 'Adding child population error';
})
},
getChildPopulationLink(populationId) {
return route('population.show', {"template_id":this.current_template.id, "population_id":populationId});
},
runElections(key, multi) {
let population = this.current_template.child_populations[key];
if (this.running_elections_lock) {
this.feedback = 'already running elections, please wait...';
} else {
this.running_elections_lock = true;
this.feedback = 'running ' + population.election_type + '-type elections: (' + multi + ')...';
this.last_elections_data = null;
this.current_child_population = population;
axios.post(
route(
'internal.api.elections.run',
{
"template" : population.parent_id,
"population" : population.id,
"omit_details" : 1
}),
{
type: population.election_type,
number:multi
}).then((response) => {
this.feedback = 'voting done, fetching updated population stats..';
this.last_elections_data = response.data;
this.last_elections_data.population_name = population.name;
this.updateChildPopulationStats(key);
console.log(this.auto_fetch_weights_timeline);
console.log(this.show_analytics_weights);
console.log(this.current_election_timeline_key);
console.log(population.election_type)
console.log(this.current_election_timeline_key == population.election_type);
if(this.auto_fetch_weights_timeline && this.show_analytics_weights && this.current_election_timeline_key.value == population.election_type) {
console.log("OK");
this.fetchWeightsTimeline();
}
this.running_elections_lock = false;
}).catch((err) => {
this.feedback = 'election error';
this.running_elections_lock = false;
});
}
},
updateChildPopulationStats(key) {
let population = this.current_template.child_populations[key];
this.feedback = 'updating child population stats..';
axios.get(route(
'internal.api.population.get',
{
"template":population.parent_id,
"population":population.id
}
), {
params: {'omit_voters': 1}
}).then((response) => {
this.feedback = 'child population stats updated';
this.current_template.child_populations[key] = response.data;
this.updateTotalSums();
}).catch((err) => {
this.feedback = 'population stats fetching error';
});
},
updateTotalSums() {
axios.get(
route(
'internal.api.template.analytics.performance',
{
"template":this.current_template.id
}
)).then((response) => {
this.performance_mode_results = response.data.results;
this.feedback = 'performance mode results fetched';
}).catch((err) => {
this.feedback = 'performance mode results fetching error';
});
},
fetchWeightsTimeline() {
axios.get(
route(
'internal.api.template.analytics.weights',
{
"template":this.current_template.id
}
), {
params: {
'election_type': this.current_election_timeline_key.value
}
}).then((response) => {
this.analytics_weights_timeline = response.data;
this.feedback = 'weights timeline fetched';
}).catch((err) => {
this.feedback = 'weights timeline fetching error';
});
},
switchToPerformanceStage(key) {
let population = this.current_template.child_populations[key];
axios.post(route(
'internal.api.population.stage.update',
{
"template":population.parent_id,
"population":population.id
}
)).then((response) => {
this.fetchPopulationTemplate();
this.feedback = "Changed child population stage. Only elections that do not alter attributes are available.";
}).catch((err) => {
this.feedback = "Error while changing stage.";
});
}
}
}
</script>
<style scoped>
</style>
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'reset' => 'Your password has been reset!',
'sent' => 'We have emailed your password reset link!',
'throttled' => 'Please wait before retrying.',
'token' => 'This password reset token is invalid.',
'user' => "We can't find a user with that email address.",
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'numeric' => 'The :attribute must be greater than :value.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'string' => 'The :attribute must be greater than :value characters.',
'array' => 'The :attribute must have more than :value items.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
],
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => 'The password is incorrect.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute format is invalid.',
'uuid' => 'The :attribute must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];
// Body
$body-bg: #f8fafc;
// Typography
$font-family-sans-serif: 'Nunito', sans-serif;
$font-size-base: 0.9rem;
$line-height-base: 1.6;
// Colors
$blue: #3490dc;
$indigo: #6574cd;
$purple: #9561e2;
$pink: #f66d9b;
$red: #e3342f;
$orange: #f6993f;
$yellow: #ffed4a;
$green: #38c172;
$teal: #4dc0b5;
$cyan: #6cb2eb;
// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');
// Variables
@import 'variables';
// Bootstrap
@import '~bootstrap/scss/bootstrap';
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('login') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Confirm Password') }}</div>
<div class="card-body">
{{ __('Please confirm your password before continuing.') }}
<form method="POST" action="{{ route('password.confirm') }}">
@csrf
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Confirm Password') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('password.email') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection