Merge pull request #108 from NicolasConstant/develop

0.9.1
This commit is contained in:
Nicolas Constant 2019-06-01 18:32:50 -04:00 committed by GitHub
commit dd03ea0e3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
816 changed files with 430 additions and 150 deletions

7
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "sengi",
"version": "0.7.0",
"version": "0.9.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -6327,11 +6327,6 @@
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
"dev": true
},
"ionicons": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-4.5.5.tgz",
"integrity": "sha512-dIGI73XG6Fg2Ps77ry5Ywe36Pq7wUGkDkl0pBhC4uhsiyoW+oXe+pplmarXEnKEcB5fmlkRrBOxYYzZaoRiUGw=="
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "sengi",
"version": "0.9.0",
"version": "0.9.1",
"license": "AGPL-3.0-or-later",
"main": "main-electron.js",
"description": "A multi-account desktop client for Mastodon and Pleroma",
@ -15,6 +15,7 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"start-mem": "node --max_old_space_size=5048 ./node_modules/@angular/cli/bin/ng serve",
"build": "ng build --prod",
"test": "ng test",
"test-nowatch": "ng test --watch=false",
@ -44,8 +45,7 @@
"@ngxs/store": "^3.2.0",
"bootstrap": "^4.1.3",
"core-js": "^2.5.4",
"emojione": "^4.5.0",
"ionicons": "^4.4.3",
"emojione": "~4.5.0",
"rxjs": "^6.4.0",
"tslib": "^1.9.0",
"zone.js": "^0.8.29"

View File

@ -3,7 +3,7 @@
<form (ngSubmit)="onSubmit()">
<label>Please provide your account:</label>
<input type="text" class="form-control form-control-sm" [(ngModel)]="mastodonFullHandle" name="mastodonFullHandle"
<input type="text" class="form-control form-control-sm form-color" [(ngModel)]="mastodonFullHandle" name="mastodonFullHandle"
placeholder="@nickname@mastodon.social" />
<br />
<button type="submit" class="btn btn-success btn-sm">Submit</button>

View File

@ -1,2 +1,14 @@
@import "variables";
@import "panel";
@import "panel";
.form-color {
background-color: $column-color;
border-color: $button-border-color;
color: #fff;
font-size: $default-font-size;
&:focus {
box-shadow: none;
}
height: 29px;
padding: 0 5px 0 5px;
}

View File

@ -13,6 +13,8 @@ import { NotificationService } from '../../../services/notification.service';
styleUrls: ['./add-new-account.component.scss']
})
export class AddNewAccountComponent implements OnInit {
private blockList = ['gab.com', 'gab.ai'];
@Input() mastodonFullHandle: string;
constructor(
@ -29,6 +31,8 @@ export class AddNewAccountComponent implements OnInit {
const username = fullHandle[0];
const instance = fullHandle[1];
this.checkBlockList(instance);
this.checkAndCreateApplication(instance)
.then((appData: AppData) => {
this.redirectToInstanceAuthPage(username, instance, appData);
@ -36,7 +40,7 @@ export class AddNewAccountComponent implements OnInit {
.catch((err: HttpErrorResponse) => {
if (err instanceof HttpErrorResponse) {
this.notificationService.notifyHttpError(err);
} else if ((<Error>err).message === 'CORS'){
} else if ((<Error>err).message === 'CORS') {
this.notificationService.notify('Connection Error. It\'s usually a CORS issue with the server you\'re connecting to. Please check in the console and if so, contact your administrator with those informations.', true);
} else {
this.notificationService.notify('Unkown error', true);
@ -46,6 +50,20 @@ export class AddNewAccountComponent implements OnInit {
return false;
}
private checkBlockList(instance: string){
let cleanInstance = instance.replace('http://', '').replace('https://', '').toLowerCase();
for (let b of this.blockList) {
if (cleanInstance == b || cleanInstance.includes(`.${b}`)) {
let content = '<div style="width:100%; height:100%; background-color: black;"><iframe style="pointer-events: none;" width="100%" height="100%" src="https://www.youtube.com/embed/dQw4w9WgXcQ?rel=0&autoplay=1&showinfo=0&controls=0" allow="autoplay; fullscreen"></div>';
document.open();
document.write(content);
document.close();
throw Error('Oh Noz!');
}
}
}
private checkAndCreateApplication(instance: string): Promise<AppData> {
const alreadyRegisteredApps = this.getAllSavedApps();
const instanceApps = alreadyRegisteredApps.filter(x => x.instance === instance);

View File

@ -21,7 +21,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
isLoading = false;
isThread = false;
hasContentWarnings = false;
@Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@ -32,9 +32,9 @@ export class MentionsComponent implements OnInit, OnDestroy {
this.loadMentions();
}
get account(): AccountWrapper {
return this._account;
return this._account;
}
@ViewChild('statusstream') public statustream: ElementRef;
private maxReached = false;
@ -45,41 +45,48 @@ export class MentionsComponent implements OnInit, OnDestroy {
constructor(
private readonly notificationService: NotificationService,
private readonly userNotificationService: UserNotificationService,
private readonly mastodonService: MastodonService) {
}
private readonly mastodonService: MastodonService) {
}
ngOnInit() {
}
ngOnDestroy(): void {
if(this.userNotificationServiceSub){
if (this.userNotificationServiceSub) {
this.userNotificationServiceSub.unsubscribe();
}
}
private loadMentions(){
if(this.userNotificationServiceSub){
private loadMentions() {
if (this.userNotificationServiceSub) {
this.userNotificationServiceSub.unsubscribe();
}
this.statuses.length = 0;
this.userNotificationService.markMentionsAsRead(this.account.info);
this.userNotificationService.markMentionsAsRead(this.account.info);
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
this.statuses.length = 0; //TODO: don't reset, only add the new ones
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
if(userNotification && userNotification.mentions){
userNotification.mentions.forEach((mention: Status) => {
const statusWrapper = new StatusWrapper(mention, this.account.info);
this.statuses.push(statusWrapper);
});
}
this.lastId = userNotification.lastId;
this.userNotificationService.markMentionsAsRead(this.account.info);
this.processNewMentions(userNotifications);
if(this.statuses.length < 20) this.scrolledToBottom();
});
}
private processNewMentions(userNotifications: UserNotification[]) {
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
if (userNotification && userNotification.mentions) {
let orderedMentions = [...userNotification.mentions].reverse();
for (let m of orderedMentions) {
if (!this.statuses.find(x => x.status.id === m.id)) {
const statusWrapper = new StatusWrapper(m, this.account.info);
this.statuses.unshift(statusWrapper);
}
}
}
this.lastId = userNotification.lastId;
this.userNotificationService.markMentionsAsRead(this.account.info);
}
onScroll() {
var element = this.statustream.nativeElement as HTMLElement;
const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 1000;
@ -102,7 +109,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
this.maxReached = true;
return;
}
for (const s of statuses) {
const wrapper = new StatusWrapper(s, this.account.info);
this.statuses.push(wrapper);
@ -117,7 +124,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
this.isLoading = false;
});
}
browseAccount(accountName: string): void {
this.browseAccountEvent.next(accountName);
}

View File

@ -68,19 +68,26 @@ export class NotificationsComponent implements OnInit, OnDestroy {
this.userNotificationService.markNotificationAsRead(this.account.info);
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
this.notifications.length = 0; //TODO: don't reset, only add the new ones
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
if(userNotification && userNotification.notifications){
userNotification.notifications.forEach((notification: Notification) => {
const notificationWrapper = new NotificationWrapper(notification, this.account.info);
this.notifications.push(notificationWrapper);
});
}
this.lastId = userNotification.lastId;
this.userNotificationService.markNotificationAsRead(this.account.info);
this.processNewNotifications(userNotifications);
if(this.notifications.length < 20) this.scrolledToBottom();
});
}
private processNewNotifications(userNotifications: UserNotification[]) {
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
if (userNotification && userNotification.notifications) {
let orderedNotifications = [...userNotification.notifications].reverse();
for (let n of orderedNotifications) {
const notificationWrapper = new NotificationWrapper(n, this.account.info);
if (!this.notifications.find(x => x.wrapperId === notificationWrapper.wrapperId)) {
this.notifications.unshift(notificationWrapper);
}
}
}
this.lastId = userNotification.lastId;
this.userNotificationService.markNotificationAsRead(this.account.info);
}
onScroll() {
var element = this.statustream.nativeElement as HTMLElement;
@ -150,9 +157,11 @@ class NotificationWrapper {
this.status= new StatusWrapper(notification.status, provider);
break;
}
this.account = notification.account;
this.account = notification.account;
this.wrapperId = `${this.type}-${notification.id}`;
}
wrapperId: string;
account: Account;
status: StatusWrapper;
type: 'mention' | 'reblog' | 'favourite' | 'follow';

View File

@ -1,22 +1,26 @@
<div class="left-bar">
<a class="left-bar-button left-bar-button--status left-bar-link" href title="write new message" (click)="createNewStatus()" (contextmenu)="createNewStatus()" *ngIf="hasAccounts">
<a class="left-bar-button left-bar-button--status left-bar-link" href title="write new message"
(click)="createNewStatus()" (contextmenu)="createNewStatus()" *ngIf="hasAccounts">
<fa-icon [icon]="faCommentAlt"></fa-icon>
<!-- <ion-icon name="md-send"></ion-icon> -->
</a>
<a class="left-bar-button left-bar-button--search left-bar-link" href title="search" (click)="openSearch()" (contextmenu)="openSearch()" *ngIf="hasAccounts">
<ion-icon name="md-search"></ion-icon>
<a class="left-bar-button left-bar-button--search left-bar-link" href title="search" (click)="openSearch()"
(contextmenu)="openSearch()" *ngIf="hasAccounts">
<fa-icon [icon]="faSearch"></fa-icon>
</a>
<div *ngFor="let account of accounts">
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)" (openMenuNotify)="onOpenMenuNotify($event)">
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)"
(openMenuNotify)="onOpenMenuNotify($event)">
</app-account-icon>
</div>
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }" href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
<ion-icon name="md-add"></ion-icon>
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }"
href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
<fa-icon [icon]="faPlus"></fa-icon>
</a>
<a class="left-bar-button left-bar-button--cog left-bar-link" href title="settings" (click)="openSettings()" (contextmenu)="openSettings()" *ngIf="hasAccounts">
<ion-icon name="md-cog"></ion-icon>
<a class="left-bar-button left-bar-button--cog left-bar-link" href title="settings" (click)="openSettings()"
(contextmenu)="openSettings()" *ngIf="hasAccounts">
<fa-icon [icon]="faCog"></fa-icon>
</a>
</div>

View File

@ -35,15 +35,16 @@ $height-button: 40px;
&--search {
// font-size: 28px;
// font-size: 22px;
font-size: 24px;
padding: 5px 0 0 12px;
font-size: 16px;
padding: 5px 0 0 16px;
}
&--add {
padding: 5px 0 5px 13px;
font-size: 22px;
padding: 2px 0 5px 18px;
font-size: 14px;
}
&--cog {
padding: 2px 0 0 9px;
font-size: 24px;
padding: 5px 0 0 12px;
position: absolute;
bottom: 7px;
opacity: .3;

View File

@ -2,6 +2,7 @@ import { Component, OnInit, OnDestroy } from "@angular/core";
import { HttpErrorResponse } from "@angular/common/http";
import { Subscription, Observable } from "rxjs";
import { Store } from "@ngxs/store";
import { faPlus, faCog, faSearch } from "@fortawesome/free-solid-svg-icons";
import { faCommentAlt } from "@fortawesome/free-regular-svg-icons";
import { Account } from "../../services/models/mastodon.interfaces";
@ -19,6 +20,10 @@ import { UserNotificationService, UserNotification } from '../../services/user-n
})
export class LeftSideBarComponent implements OnInit, OnDestroy {
faCommentAlt = faCommentAlt;
faSearch = faSearch;
faPlus = faPlus;
faCog = faCog;
accounts: AccountWithNotificationWrapper[] = [];
hasAccounts: boolean;

View File

@ -1,41 +1,33 @@
<div class="action-bar">
<a *ngIf="!isLocked" href class="action-bar__link" title="Reply" (click)="reply()">
<ion-icon name="ios-undo"></ion-icon>
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--reply" title="Reply" (click)="reply()">
<fa-icon [icon]="faReply"></fa-icon>
</a>
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
<a *ngIf="!(isBoostLocked || isLocked)" href class="action-bar__link" title="Boost"
[class.boosted]="isBoosted"
[class.boosting]="boostIsLoading"
(click)="boost()">
<ion-icon name="md-swap"></ion-icon>
<a *ngIf="!(isBoostLocked || isLocked)" href class="action-bar__link action-bar__link--boost" title="Boost" [class.boosted]="isBoosted"
[class.boosting]="boostIsLoading" (click)="boost()">
<fa-icon [icon]="faRetweet"></fa-icon>
</a>
<ion-icon *ngIf="isBoostLocked && !isLocked" class="action-bar__lock" name="lock"
title="This post cannot be boosted"></ion-icon>
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
<fa-icon *ngIf="isBoostLocked && !isLocked" class="action-bar__lock" title="This post cannot be boosted"
[icon]="faLock"></fa-icon>
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
<a *ngIf="!isLocked" href class="action-bar__link" title="Favourite"
[class.favorited]="isFavorited"
[class.favoriting]="favoriteIsLoading"
(click)="favorite()">
<ion-icon name="md-star"></ion-icon>
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--fav" title="Favourite" [class.favorited]="isFavorited"
[class.favoriting]="favoriteIsLoading" (click)="favorite()">
<fa-icon [icon]="faStar"></fa-icon>
</a>
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
<a href class="action-bar__link action-bar__link--cw"
title="show content" (click)="showContent()"
<a href class="action-bar__link action-bar__link--cw" title="show content" (click)="showContent()"
*ngIf="isContentWarningActive">
<fa-icon class="action-bar__cw" [icon]="faWindowClose"></fa-icon>
<fa-icon [icon]="faWindowClose"></fa-icon>
</a>
<a href class="action-bar__link action-bar__link--cw"
title="hide content" (click)="hideContent()"
<a href class="action-bar__link action-bar__link--cw" title="hide content" (click)="hideContent()"
*ngIf="!isContentWarningActive">
<fa-icon class="action-bar__cw" [icon]="faWindowCloseRegular"></fa-icon>
<fa-icon [icon]="faWindowCloseRegular"></fa-icon>
</a>
<a href class="action-bar__link action-bar__link--more" title="More" (click)="more()">
<ion-icon name="ios-more"></ion-icon>
</a>
<!-- <a href class="action-bar__link action-bar__link--more" title="More" (click)="more()">
<fa-icon [icon]="faEllipsisH"></fa-icon>
</a> -->
</div>

View File

@ -4,9 +4,10 @@
// outline: 1px solid greenyellow; // height: 20px;
margin: 5px 10px 5px $avatar-column-space;
padding: 0;
font-size: 24px;
font-size: 18px;
height: 30px;
position: relative;
// transform: rotate(0.03deg);
&__link {
color: $status-secondary-color;
@ -19,36 +20,45 @@
margin-right: 15px;
}
&--reply {
font-size: 20px;
}
&--boost {
position: relative;
bottom: -1px;
// font-size: 22px;
}
&--fav {
font-size: 17px;
}
&--cw {
position: absolute;
position: relative;
bottom: -2px;
font-size: 22px;
}
&--more {
position: absolute;
left: 155px;
bottom: -6px;
}
// &--more {
// position: absolute;
// left: 155px;
// bottom: -6px;
// }
}
&__lock {
color: $status-secondary-color;
width: 24px;
width: 22px;
&:not(:last-child) {
margin-right: 15px;
}
}
// &_cw {
// // width: 18px;
// font-size: 10px;
// &:not(:last-child) {
// margin-right: 15px;
// }
// }
}
.boosted {

View File

@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angu
import { HttpErrorResponse } from '@angular/common/http';
import { Store } from '@ngxs/store';
import { Observable, Subscription } from 'rxjs';
import { faWindowClose, faReply, faRetweet, faStar } from "@fortawesome/free-solid-svg-icons";
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock } from "@fortawesome/free-solid-svg-icons";
import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular-svg-icons";
import { MastodonService } from '../../../../services/mastodon.service';
@ -23,6 +23,8 @@ export class ActionBarComponent implements OnInit, OnDestroy {
faRetweet = faRetweet;
faStar = faStar;
faWindowCloseRegular = faWindowCloseRegular;
faEllipsisH = faEllipsisH;
faLock = faLock;
@Input() statusWrapper: StatusWrapper;
@Output() replyEvent = new EventEmitter();

220
src/app/tools/emoji-one.ts Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,54 +1,62 @@
import { Emoji } from "../services/models/mastodon.interfaces";
import * as EmojiOne from "emojione";
// import { EmojiOne } from "./emoji-one";
import * as EmojiOne from 'emojione';
export class EmojiConverter {
applyEmojis(emojis: Emoji[], text: string, type: EmojiTypeEnum): string {
//const instanceUrl = 'https://' + url.split('https://')[1].split('/')[0];
if(!text) return text;
// private emojiOne = new EmojiOne();
let className = "emoji-small";
if (type === EmojiTypeEnum.medium) {
className = "emoji-medium";
applyEmojis(emojis: Emoji[], text: string, type: EmojiTypeEnum): string {
if (!text) return text;
let className = "emoji-small";
if (type === EmojiTypeEnum.medium) {
className = "emoji-medium";
}
if (emojis) {
emojis.forEach(emoji => {
try {
text = this.replaceAll(text, `:${emoji.shortcode}:`, `<img class="${className}" src="${emoji.url}" title=":${
emoji.shortcode}:" alt=":${emoji.shortcode}:" />`);
} catch (err) {}
});
}
text = this.applyEmojiOne(className, text);
// try {
// text = this.emojiOne.toImage(text, className);
// } catch (err) {}
return text;
}
if (emojis) {
emojis.forEach(emoji => {
text = text.replace(
`:${emoji.shortcode}:`,
`<img class="${className}" src="${emoji.url}" title=":${
emoji.shortcode
}:" alt=":${emoji.shortcode}:" />`
);
});
private applyEmojiOne(className: string, text: string): string{
text = EmojiOne.toImage(text);
while (text.includes('class="emojione"')) {
text = text.replace('class="emojione"', `class="emojione ${className}"`);
}
while (
text.includes("https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/")
) {
text = text.replace(
"https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/",
"assets/emoji/72x72/"
);
// text = text.replace('.png', '.svg');
}
return text;
}
text = EmojiOne.toImage(text);
while (text.includes('class="emojione"')) {
text = text.replace('class="emojione"', `class="emojione ${className}"`);
private replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
//FIXME: clean up this mess...
// while (text.includes('https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/')) {
// text = text.replace('https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/', instanceUrl + '/emoji/');
// text = text.replace('.png', '.svg');
// }
while (
text.includes("https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/")
) {
text = text.replace(
"https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/",
"assets/emoji/72x72/"
);
// text = text.replace('.png', '.svg');
}
return text;
}
}
export enum EmojiTypeEnum {
small,
medium
small,
medium
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show More