Merge pull request #1928 from mempool/nymkappa/feature/hashrate-resolution
Add resolution scaling to hashrate and difficulty chart
This commit is contained in:
		
						commit
						dcf48dac85
					
				@ -9,6 +9,7 @@ import loadingIndicators from './loading-indicators';
 | 
				
			|||||||
import { escape } from 'mysql2';
 | 
					import { escape } from 'mysql2';
 | 
				
			||||||
import indexer from '../indexer';
 | 
					import indexer from '../indexer';
 | 
				
			||||||
import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository';
 | 
					import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository';
 | 
				
			||||||
 | 
					import config from '../config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Mining {
 | 
					class Mining {
 | 
				
			||||||
  constructor() {
 | 
					  constructor() {
 | 
				
			||||||
@ -304,7 +305,7 @@ class Mining {
 | 
				
			|||||||
      while (toTimestamp > genesisTimestamp) {
 | 
					      while (toTimestamp > genesisTimestamp) {
 | 
				
			||||||
        const fromTimestamp = toTimestamp - 86400000;
 | 
					        const fromTimestamp = toTimestamp - 86400000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Skip already indexed weeks
 | 
					        // Skip already indexed days
 | 
				
			||||||
        if (indexedTimestamp.includes(toTimestamp / 1000)) {
 | 
					        if (indexedTimestamp.includes(toTimestamp / 1000)) {
 | 
				
			||||||
          toTimestamp -= 86400000;
 | 
					          toTimestamp -= 86400000;
 | 
				
			||||||
          ++totalIndexed;
 | 
					          ++totalIndexed;
 | 
				
			||||||
@ -315,7 +316,7 @@ class Mining {
 | 
				
			|||||||
        // we are currently indexing has complete data)
 | 
					        // we are currently indexing has complete data)
 | 
				
			||||||
        const blockStatsPreviousDay: any = await BlocksRepository.$blockCountBetweenTimestamp(
 | 
					        const blockStatsPreviousDay: any = await BlocksRepository.$blockCountBetweenTimestamp(
 | 
				
			||||||
          null, (fromTimestamp - 86400000) / 1000, (toTimestamp - 86400000) / 1000);
 | 
					          null, (fromTimestamp - 86400000) / 1000, (toTimestamp - 86400000) / 1000);
 | 
				
			||||||
        if (blockStatsPreviousDay.blockCount === 0) { // We are done indexing
 | 
					        if (blockStatsPreviousDay.blockCount === 0 && config.MEMPOOL.NETWORK === 'mainnet') { // We are done indexing
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -359,9 +360,10 @@ class Mining {
 | 
				
			|||||||
      // Add genesis block manually
 | 
					      // Add genesis block manually
 | 
				
			||||||
      if (toTimestamp <= genesisTimestamp && !indexedTimestamp.includes(genesisTimestamp)) {
 | 
					      if (toTimestamp <= genesisTimestamp && !indexedTimestamp.includes(genesisTimestamp)) {
 | 
				
			||||||
        hashrates.push({
 | 
					        hashrates.push({
 | 
				
			||||||
          hashrateTimestamp: genesisTimestamp,
 | 
					          hashrateTimestamp: genesisTimestamp / 1000,
 | 
				
			||||||
          avgHashrate: await bitcoinClient.getNetworkHashPs(1, 1),
 | 
					          avgHashrate: await bitcoinClient.getNetworkHashPs(1, 1),
 | 
				
			||||||
          poolId: null,
 | 
					          poolId: 0,
 | 
				
			||||||
 | 
					          share: 1,
 | 
				
			||||||
          type: 'daily',
 | 
					          type: 'daily',
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -396,6 +398,15 @@ class Mining {
 | 
				
			|||||||
    let currentDifficulty = 0;
 | 
					    let currentDifficulty = 0;
 | 
				
			||||||
    let totalIndexed = 0;
 | 
					    let totalIndexed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (indexedHeights[0] === false) {
 | 
				
			||||||
 | 
					      await DifficultyAdjustmentsRepository.$saveAdjustments({
 | 
				
			||||||
 | 
					        time: 1231006505,
 | 
				
			||||||
 | 
					        height: 0,
 | 
				
			||||||
 | 
					        difficulty: 1.0,
 | 
				
			||||||
 | 
					        adjustment: 0.0,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const block of blocks) {
 | 
					    for (const block of blocks) {
 | 
				
			||||||
      if (block.difficulty !== currentDifficulty) {
 | 
					      if (block.difficulty !== currentDifficulty) {
 | 
				
			||||||
        if (block.height === 0 || indexedHeights[block.height] === true) { // Already indexed
 | 
					        if (block.height === 0 || indexedHeights[block.height] === true) { // Already indexed
 | 
				
			||||||
 | 
				
			|||||||
@ -285,6 +285,7 @@ class Server {
 | 
				
			|||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug', routes.$getPool)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug', routes.$getPool)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools/:interval', routes.$getPoolsHistoricalHashrate)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools/:interval', routes.$getPoolsHistoricalHashrate)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/:interval', routes.$getHistoricalHashrate)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/:interval', routes.$getHistoricalHashrate)
 | 
				
			||||||
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments', routes.$getDifficultyAdjustments)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/reward-stats/:blockCount', routes.$getRewardStats)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/reward-stats/:blockCount', routes.$getRewardStats)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees/:interval', routes.$getHistoricalBlockFees)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees/:interval', routes.$getHistoricalBlockFees)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/rewards/:interval', routes.$getHistoricalBlockRewards)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/rewards/:interval', routes.$getHistoricalBlockRewards)
 | 
				
			||||||
 | 
				
			|||||||
@ -436,7 +436,7 @@ class BlocksRepository {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) {
 | 
					        if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) {
 | 
				
			||||||
          logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}, re-indexing newer blocks and hashrates`);
 | 
					          logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}`);
 | 
				
			||||||
          await this.$deleteBlocksFrom(blocks[idx - 1].height);
 | 
					          await this.$deleteBlocksFrom(blocks[idx - 1].height);
 | 
				
			||||||
          await BlocksSummariesRepository.$deleteBlocksFrom(blocks[idx - 1].height);
 | 
					          await BlocksSummariesRepository.$deleteBlocksFrom(blocks[idx - 1].height);
 | 
				
			||||||
          await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800);
 | 
					          await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import { Common } from '../api/common';
 | 
					import { Common } from '../api/common';
 | 
				
			||||||
 | 
					import config from '../config';
 | 
				
			||||||
import DB from '../database';
 | 
					import DB from '../database';
 | 
				
			||||||
import logger from '../logger';
 | 
					import logger from '../logger';
 | 
				
			||||||
import { IndexedDifficultyAdjustment } from '../mempool.interfaces';
 | 
					import { IndexedDifficultyAdjustment } from '../mempool.interfaces';
 | 
				
			||||||
@ -31,13 +32,19 @@ class DifficultyAdjustmentsRepository {
 | 
				
			|||||||
  public async $getAdjustments(interval: string | null, descOrder: boolean = false): Promise<IndexedDifficultyAdjustment[]> {
 | 
					  public async $getAdjustments(interval: string | null, descOrder: boolean = false): Promise<IndexedDifficultyAdjustment[]> {
 | 
				
			||||||
    interval = Common.getSqlInterval(interval);
 | 
					    interval = Common.getSqlInterval(interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let query = `SELECT UNIX_TIMESTAMP(time) as time, height, difficulty, adjustment
 | 
					    let query = `SELECT 
 | 
				
			||||||
 | 
					      CAST(AVG(UNIX_TIMESTAMP(time)) as INT) as time,
 | 
				
			||||||
 | 
					      CAST(AVG(height) AS INT) as height,
 | 
				
			||||||
 | 
					      CAST(AVG(difficulty) as DOUBLE) as difficulty,
 | 
				
			||||||
 | 
					      CAST(AVG(adjustment) as DOUBLE) as adjustment
 | 
				
			||||||
      FROM difficulty_adjustments`;
 | 
					      FROM difficulty_adjustments`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (interval) {
 | 
					    if (interval) {
 | 
				
			||||||
      query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
 | 
					      query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    query += ` GROUP BY UNIX_TIMESTAMP(time) DIV ${86400}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (descOrder === true) {
 | 
					    if (descOrder === true) {
 | 
				
			||||||
      query += ` ORDER BY time DESC`;
 | 
					      query += ` ORDER BY time DESC`;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import { escape } from 'mysql2';
 | 
					import { escape } from 'mysql2';
 | 
				
			||||||
import { Common } from '../api/common';
 | 
					import { Common } from '../api/common';
 | 
				
			||||||
 | 
					import config from '../config';
 | 
				
			||||||
import DB from '../database';
 | 
					import DB from '../database';
 | 
				
			||||||
import logger from '../logger';
 | 
					import logger from '../logger';
 | 
				
			||||||
import PoolsRepository from './PoolsRepository';
 | 
					import PoolsRepository from './PoolsRepository';
 | 
				
			||||||
@ -32,7 +33,9 @@ class HashratesRepository {
 | 
				
			|||||||
  public async $getNetworkDailyHashrate(interval: string | null): Promise<any[]> {
 | 
					  public async $getNetworkDailyHashrate(interval: string | null): Promise<any[]> {
 | 
				
			||||||
    interval = Common.getSqlInterval(interval);
 | 
					    interval = Common.getSqlInterval(interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate
 | 
					    let query = `SELECT
 | 
				
			||||||
 | 
					      CAST(AVG(UNIX_TIMESTAMP(hashrate_timestamp)) as INT) as timestamp,
 | 
				
			||||||
 | 
					      CAST(AVG(avg_hashrate) as DOUBLE) as avgHashrate
 | 
				
			||||||
      FROM hashrates`;
 | 
					      FROM hashrates`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (interval) {
 | 
					    if (interval) {
 | 
				
			||||||
@ -42,6 +45,7 @@ class HashratesRepository {
 | 
				
			|||||||
      query += ` WHERE hashrates.type = 'daily'`;
 | 
					      query += ` WHERE hashrates.type = 'daily'`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    query += ` GROUP BY UNIX_TIMESTAMP(hashrate_timestamp) DIV ${86400}`;
 | 
				
			||||||
    query += ` ORDER by hashrate_timestamp`;
 | 
					    query += ` ORDER by hashrate_timestamp`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import { StorageService } from 'src/app/services/storage.service';
 | 
				
			|||||||
import { MiningService } from 'src/app/services/mining.service';
 | 
					import { MiningService } from 'src/app/services/mining.service';
 | 
				
			||||||
import { download } from 'src/app/shared/graphs.utils';
 | 
					import { download } from 'src/app/shared/graphs.utils';
 | 
				
			||||||
import { ActivatedRoute } from '@angular/router';
 | 
					import { ActivatedRoute } from '@angular/router';
 | 
				
			||||||
 | 
					import { StateService } from 'src/app/services/state.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-hashrate-chart',
 | 
					  selector: 'app-hashrate-chart',
 | 
				
			||||||
@ -47,7 +48,7 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
  formatNumber = formatNumber;
 | 
					  formatNumber = formatNumber;
 | 
				
			||||||
  timespan = '';
 | 
					  timespan = '';
 | 
				
			||||||
  chartInstance: any = undefined;
 | 
					  chartInstance: any = undefined;
 | 
				
			||||||
  maResolution: number =  30;
 | 
					  network = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    @Inject(LOCALE_ID) public locale: string,
 | 
					    @Inject(LOCALE_ID) public locale: string,
 | 
				
			||||||
@ -57,10 +58,13 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
    private storageService: StorageService,
 | 
					    private storageService: StorageService,
 | 
				
			||||||
    private miningService: MiningService,
 | 
					    private miningService: MiningService,
 | 
				
			||||||
    private route: ActivatedRoute,
 | 
					    private route: ActivatedRoute,
 | 
				
			||||||
 | 
					    private stateService: StateService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.stateService.networkChanged$.subscribe((network) => this.network = network);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let firstRun = true;
 | 
					    let firstRun = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this.widget) {
 | 
					    if (this.widget) {
 | 
				
			||||||
@ -124,17 +128,14 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
                  ++diffIndex;
 | 
					                  ++diffIndex;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.maResolution = 30;
 | 
					                let maResolution = 15;
 | 
				
			||||||
                if (["3m", "6m"].includes(this.timespan)) {
 | 
					 | 
				
			||||||
                  this.maResolution = 7;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const hashrateMa = [];
 | 
					                const hashrateMa = [];
 | 
				
			||||||
                for (let i = this.maResolution - 1; i < data.hashrates.length; ++i) {
 | 
					                for (let i = maResolution - 1; i < data.hashrates.length; ++i) {
 | 
				
			||||||
                  let avg = 0;
 | 
					                  let avg = 0;
 | 
				
			||||||
                  for (let y = this.maResolution - 1; y >= 0; --y) {
 | 
					                  for (let y = maResolution - 1; y >= 0; --y) {
 | 
				
			||||||
                    avg += data.hashrates[i - y].avgHashrate;
 | 
					                    avg += data.hashrates[i - y].avgHashrate;
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                  avg /= this.maResolution;
 | 
					                  avg /= maResolution;
 | 
				
			||||||
                  hashrateMa.push([data.hashrates[i].timestamp * 1000, avg]);
 | 
					                  hashrateMa.push([data.hashrates[i].timestamp * 1000, avg]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -276,17 +277,17 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            name: $localize`::Difficulty`,
 | 
					            name: $localize`:@@25148835d92465353fc5fe8897c27d5369978e5a:Difficulty`,
 | 
				
			||||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
					            inactiveColor: 'rgb(110, 112, 121)',
 | 
				
			||||||
            textStyle: {  
 | 
					            textStyle: {
 | 
				
			||||||
              color: 'white',
 | 
					              color: 'white',
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            icon: 'roundRect',
 | 
					            icon: 'roundRect',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            name: $localize`Hashrate` + ` (MA${this.maResolution})`,
 | 
					            name: $localize`Hashrate (MA)`,
 | 
				
			||||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
					            inactiveColor: 'rgb(110, 112, 121)',
 | 
				
			||||||
            textStyle: {  
 | 
					            textStyle: {
 | 
				
			||||||
              color: 'white',
 | 
					              color: 'white',
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            icon: 'roundRect',
 | 
					            icon: 'roundRect',
 | 
				
			||||||
@ -295,11 +296,18 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					        selected: JSON.parse(this.storageService.getValue('hashrate_difficulty_legend')) ?? {
 | 
				
			||||||
 | 
					          '$localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`': true,
 | 
				
			||||||
 | 
					          '$localize`::Difficulty`': this.network === '',
 | 
				
			||||||
 | 
					          '$localize`Hashrate (MA)`': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      yAxis: data.hashrates.length === 0 ? undefined : [
 | 
					      yAxis: data.hashrates.length === 0 ? undefined : [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          min: (value) => {
 | 
					          min: (value) => {
 | 
				
			||||||
            return value.min * 0.9;
 | 
					            const selectedPowerOfTen: any = selectPowerOfTen(value.min);
 | 
				
			||||||
 | 
					            const newMin = Math.floor(value.min / selectedPowerOfTen.divider / 10);
 | 
				
			||||||
 | 
					            return newMin * selectedPowerOfTen.divider * 10;
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          type: 'value',
 | 
					          type: 'value',
 | 
				
			||||||
          axisLabel: {
 | 
					          axisLabel: {
 | 
				
			||||||
@ -363,7 +371,7 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          zlevel: 2,
 | 
					          zlevel: 2,
 | 
				
			||||||
          name: $localize`Hashrate` + ` (MA${this.maResolution})`,
 | 
					          name: $localize`Hashrate (MA)`,
 | 
				
			||||||
          showSymbol: false,
 | 
					          showSymbol: false,
 | 
				
			||||||
          symbol: 'none',
 | 
					          symbol: 'none',
 | 
				
			||||||
          data: data.hashrateMa,
 | 
					          data: data.hashrateMa,
 | 
				
			||||||
@ -404,6 +412,10 @@ export class HashrateChartComponent implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  onChartInit(ec) {
 | 
					  onChartInit(ec) {
 | 
				
			||||||
    this.chartInstance = ec;
 | 
					    this.chartInstance = ec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.chartInstance.on('legendselectchanged', (e) => {
 | 
				
			||||||
 | 
					      this.storageService.setValue('hashrate_difficulty_legend', JSON.stringify(e.selected));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  isMobile() {
 | 
					  isMobile() {
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,7 @@
 | 
				
			|||||||
      <div class="card">
 | 
					      <div class="card">
 | 
				
			||||||
        <div class="card-body pl-lg-3 pr-lg-3 pl-2 pr-2">
 | 
					        <div class="card-body pl-lg-3 pr-lg-3 pl-2 pr-2">
 | 
				
			||||||
          <app-hashrate-chart [widget]="true"></app-hashrate-chart>
 | 
					          <app-hashrate-chart [widget]="true"></app-hashrate-chart>
 | 
				
			||||||
          <div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
 | 
					          <div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" fragment="1y" i18n="dashboard.view-more">View more »</a></div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user