Compare commits

...

53 commits

Author SHA1 Message Date
aly
af65a8da13 Add captain-definition 2024-06-11 18:02:28 +10:00
ArcaneDisgea
f16496b285 update deps 2022-10-17 18:30:54 -04:00
ArcaneDisgea
654265c95f
Merge branch 'xivapi:master' into master 2022-10-17 18:19:17 -04:00
ArcaneDisgea
8a5afe38cd index to server because deployment needs it I guess 2022-10-17 18:18:32 -04:00
ArcaneDisgea
a59c513cc6
Merge pull request #36 from ArcaneDisgea/master
bump version 1.5.0
2022-10-17 18:07:26 -04:00
ArcaneDisgea
53f7fa28ff 1.5.0 2022-10-17 18:05:49 -04:00
ArcaneDisgea
d0a88cf4d3
Merge pull request #35 from ArcaneDisgea/master
bump canvas for arm and update job array length
2022-10-17 18:04:44 -04:00
ArcaneDisgea
19e8e37173 bump canvas for arm and update job array length 2022-10-17 18:01:12 -04:00
ArcaneDisgea
c1821fa834
bump version 2022-10-09 14:04:45 -04:00
ArcaneDisgea
a93d4bacf8
Merge pull request #34 from SocMinarch/fix-for-mimo-and-no-gc
Fixes mounts/minions percentages always showing as `N/A%`, and for crashing when a character has no Grand Company
2022-10-09 14:02:04 -04:00
Adam Chance
248bb7365e Fix generating cards for characters with no Grand Company 2022-10-09 17:27:03 +01:00
Adam Chance
56e8d7e030 Fix mounts/minions percentages always showing as N/A% 2022-10-09 17:26:35 +01:00
ArcaneDisgea
25905928e9
Job Backgrounds
This will not resolve the issue with them loading as blu. That is an issue with the xivapi lodestone-parser that will need to be fixed.
2021-12-14 10:48:00 -05:00
arcanedisgea
626d8138ae 1.4.1 2021-12-07 15:42:15 -05:00
arcanedisgea
6d6cfe6df6 fix scholar levels 2021-12-07 15:39:50 -05:00
ArcaneDisgea
69eac7df0c
Merge pull request #28 from xivapi/beginrunner
less pixelated icons
2021-12-03 13:27:19 -05:00
arcanedisgea
0a7d22b441 less pixelated this time 2021-12-03 13:26:19 -05:00
arcanedisgea
d101cfdb0b 1.4.0 2021-12-03 13:14:16 -05:00
ArcaneDisgea
c82fe1e89a
Merge pull request #27 from xivapi/beginrunner
Add Endwalker support
2021-12-03 13:10:54 -05:00
arcanedisgea
805c98ef57 reaper/sage update 2021-12-03 13:09:44 -05:00
arcanedisgea
a39ad7c20b xivapi index update 2021-12-03 10:37:47 -05:00
arcanedisgea
68891ed450 placeholder icons 2021-12-02 09:30:02 -05:00
arcanedisgea
ae7524a85e adjust jobs rect for new jobs 2021-12-02 09:29:26 -05:00
arcanedisgea
f9f98633f3 work around null mimo from xivapi
just until nodestone is used for the cards
2021-12-02 08:38:17 -05:00
arcanedisgea
0429f1d562 add new jobs to classJobs array 2021-12-02 08:00:55 -05:00
ArcaneDisgea
aff43cef4c
Merge pull request #26 from carlomorgenstern/master
rework/enhancement
2021-10-28 19:45:10 -04:00
Carlo Morgenstern
453e5234bb Bumped version to 1.3 2021-10-25 16:48:38 +02:00
Carlo Morgenstern
23b9d6a007 Updated README 2021-10-25 16:48:33 +02:00
Carlo Morgenstern
c049af4c21 Reordered crafters and gatherers to be consistent with game 2021-10-25 16:48:25 +02:00
Carlo Morgenstern
bbc38b6a9c Completely reworked card creation to optimize for data fetching and improve documentation 2021-10-25 16:48:19 +02:00
Carlo Morgenstern
52a8960f71 Reworked getItemLevel to filter all equip slots 2021-10-25 16:48:14 +02:00
Carlo Morgenstern
a677d723cb Reworked createCrest to load all layers at once 2021-10-25 16:48:09 +02:00
Carlo Morgenstern
aa036b169e CardCreator reworked init to load everything in parallel 2021-10-25 16:48:01 +02:00
Carlo Morgenstern
efde0b5ecd Moved copyright year to card creation, so it's always current 2021-10-25 16:47:53 +02:00
Carlo Morgenstern
37def4245e CardCreator: Updated ensureInit to proper singleton 2021-10-25 16:47:48 +02:00
Carlo Morgenstern
3a9e4d7502 Added init complete log to server 2021-10-25 16:47:40 +02:00
Carlo Morgenstern
a13758dcb1 Consistent styling: no var for CardCreator 2021-10-25 16:47:34 +02:00
Carlo Morgenstern
da3dc236fe Consistent styling: all single quotes for CardCreator 2021-10-25 16:47:26 +02:00
Carlo Morgenstern
ad98ec4d74 Added basic language support to CardCreator 2021-10-25 16:47:00 +02:00
Carlo Morgenstern
0a39d21f29 Updated gh-pages to similar styling 2021-10-25 16:42:28 +02:00
Carlo Morgenstern
e304b70e08 Updated createIlvlFilter to include xivApiKey 2021-10-25 16:42:13 +02:00
Carlo Morgenstern
2023697686 Added optional xivApiKey to CardCreator 2021-10-25 16:41:34 +02:00
Carlo Morgenstern
e6d9d10182 Added CardCreator init on server startup 2021-10-25 16:41:10 +02:00
Carlo Morgenstern
3fc98f5d0a Deleted unused resource files 2021-10-25 16:41:03 +02:00
Carlo Morgenstern
867c7895ce Moved resource files into one directory 2021-10-25 16:40:53 +02:00
Carlo Morgenstern
1bbcae6119 Added rate limiter to all XIV API requests 2021-10-25 16:40:39 +02:00
Carlo Morgenstern
3ebbb867b2 Reworked webserver to eliminate redundant code 2021-10-25 16:40:26 +02:00
Carlo Morgenstern
73b396c05e Cleaned up index imports 2021-10-25 16:37:02 +02:00
Carlo Morgenstern
3e17cbd90d Updated dependencies 2021-10-25 16:34:44 +02:00
ArcaneDisgea
77b5cb5e76
Merge pull request #24 from ImVaskel/features/json-errors
make 404 return json instead of text
2021-10-01 14:24:29 -04:00
ImVaskel
3e2f736cb1
make 404 return json instead of text 2021-10-01 14:14:14 -04:00
ArcaneDisgea
b5313a8f2b
Merge pull request #23 from ArcaneDisgea/better-ilvl-calc
iLvl filter
2021-10-01 13:31:23 -04:00
ArcaneDisgea
cf18fb572e
Merge pull request #22 from ArcaneDisgea/master
change const to let to avoid TypeError
2021-08-21 16:45:00 -04:00
102 changed files with 1883 additions and 2481 deletions

View file

@ -1,4 +1,4 @@
index.js
server.js
docs/
gh-pages.js
.github/

10
captain-definition Normal file
View file

@ -0,0 +1,10 @@
{
"schemaVersion": 2,
"dockerfileLines": [
"FROM node as build",
"COPY . /app",
"WORKDIR /app",
"RUN npm i",
"CMD npm run start"
]
}

BIN
chara.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

File diff suppressed because it is too large Load diff

33
create-ilvl-filter.js Normal file
View file

@ -0,0 +1,33 @@
const fetch = require('node-fetch');
const itemUICategory = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 84, 87, 88, 89, 96, 97, 98, 99, 105, 106, 107,
];
// Returns a list of item IDs that, when equipped, increase the iLvl by 1
async function createIlvlFilter(xivApiKey = undefined) {
const itemIds = [];
// Fetch for each category one after another to prevent rate limiting
// This should only by needed on startup, so a longer caching time is ok
for (const category of itemUICategory) {
const url = new URL('https://xivapi.com/search');
url.searchParams.set('indexes', 'item');
url.searchParams.set('filters', `IsIndisposable=1,ItemUICategoryTargetID=${category}`);
if (typeof xivApiKey === 'string' && xivApiKey !== '') url.searchParams.set('private_key', xivApiKey);
const response = await fetch(url.toString());
const data = await response.json();
if (data != null && Array.isArray(data.Results)) {
for (const item of data.Results) {
itemIds.push(item.ID);
}
}
}
return itemIds;
}
module.exports = createIlvlFilter

View file

@ -1,27 +0,0 @@
const fetch = require("node-fetch");
const itemUICategory = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 84, 87, 88, 89, 96, 97, 98, 99,
105, 106, 107,
];
async function createilvlfilter() {
let results = [];
for (const category of itemUICategory) {
let url = `https://xivapi.com/search?indexes=item&filters=IsIndisposable=1,ItemUICategoryTargetID=${category}`;
const response = await fetch(url);
const data = response.json();
data.then((payload) => {
if (payload.Pagination.Results === 0) {
return;
}
for (const item of payload.Results) {
let part = item.ID
results.push(part);
}
});
}
return results;
}
module.exports = createilvlfilter

View file

@ -1,6 +1,3 @@
const ghpages = require("gh-pages");
ghpages.publish("docs/", (err) => {
if (err) {
console.error(err);
}
});
const ghpages = require('gh-pages');
ghpages.publish('docs/', error => { if (error) console.error(error) });

152
index.js
View file

@ -1,152 +0,0 @@
const fetch = require("node-fetch");
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
const { CardCreator } = require('./create-card');
const creator = new CardCreator();
// node cachemanager
var cacheManager = require('cache-manager');
// storage for the cachemanager
var fsStore = require('cache-manager-fs-binary');
// initialize caching on disk
var diskCache = cacheManager.caching({
store: fsStore,
options: {
reviveBuffers: true,
binaryAsStream: false,
ttl: 60 * 60 * 4 /* seconds */,
maxsize: 1000 * 1000 * 1000 /* max size in bytes on disk */,
path: 'diskcache',
preventfill: true
}
});
async function getCharIdByName(world, name, retries = 1) {
if (retries === -1) return undefined;
const response = await fetch(`https://xivapi.com/character/search?name=${name}&server=${world}`);
const data = await response.json();
if (data.Results[0] === undefined)
return getCharIdByName(world, name, --retries);
return data.Results[0].ID;
}
app.get('/prepare/id/:charaId', async (req, res) => {
var cacheKey = `img:${req.params.charaId}`;
var ttl = 60 * 60 * 4; // 4 hours
diskCache.wrap(cacheKey,
// called if the cache misses in order to generate the value to cache
function (cb) {
creator.ensureInit().then(() => creator.createCard(req.params.charaId), (reason) => cb('Init failed: ' + reason, null)).then(image => cb(null, {
binary: {
image: image,
}
})).catch((reason) => cb('createCard failed: ' + reason, null));
},
// Options, see node-cache-manager for more examples
{ ttl: ttl },
function (err, result) {
if (err !== null) {
console.error(err);
res.status(500).send({status: "error", reason: err});
return;
}
res.status(200).send({status: "ok", url: `/characters/id/${req.params.charaId}.png`});
}
);
})
app.get('/prepare/name/:world/:charName', async (req, res) => {
var id = await getCharIdByName(req.params.world, req.params.charName);
if (id === undefined) {
res.status(404).send("Character not found.");
return;
}
res.redirect(`/prepare/id/${id}`);
})
app.get('/characters/id/:charaId.png', async (req, res) => {
var cacheKey = `img:${req.params.charaId}`;
var ttl = 60 * 60 * 4; // 4 hours
diskCache.wrap(cacheKey,
// called if the cache misses in order to generate the value to cache
function (cb) {
creator.ensureInit().then(() => creator.createCard(req.params.charaId), (reason) => cb('Init failed: ' + reason, null)).then(image => cb(null, {
binary: {
image: image,
}
})).catch((reason) => cb('createCard failed: ' + reason, null));
},
// Options, see node-cache-manager for more examples
{ ttl: ttl },
function (err, result) {
if (err !== null) {
console.error(err);
res.status(500).send({status: "error", reason: err});
return;
}
var image = result.binary.image;
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': image.length,
'Cache-Control': 'public, max-age=14400'
});
res.end(image, 'binary');
var usedStreams = ['image'];
// you have to do the work to close the unused files
// to prevent file descriptors leak
for (var key in result.binary) {
if (!result.binary.hasOwnProperty(key)) continue;
if (usedStreams.indexOf(key) < 0
&& result.binary[key] instanceof Stream.Readable) {
if (typeof result.binary[key].close === 'function') {
result.binary[key].close(); // close the stream (fs has it)
} else {
result.binary[key].resume(); // resume to the end and close
}
}
}
}
);
})
app.get('/characters/id/:charaId', async (req, res) => {
res.redirect(`/characters/id/${req.params.charaId}.png`);
})
app.get('/characters/name/:world/:charName.png', async (req, res) => {
var id = await getCharIdByName(req.params.world, req.params.charName);
if (id === undefined) {
res.status(404).send("Character not found.");
return;
}
res.redirect(`/characters/id/${id}.png`);
})
app.get('/characters/name/:world/:charName', async (req, res) => {
res.redirect(`/characters/name/${req.params.world}/${req.params.charName}.png`);
})
app.get('/', async (req, res) => {
res.redirect('https://github.com/ArcaneDisgea/XIV-Character-Cards');
})
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
})

View file

@ -1,7 +1,7 @@
{
"name": "xiv-character-cards",
"description": "API to create fancy cards for FFXIV characters based on their Lodestone data, hosted at https://ffxiv-character-cards.herokuapp.com.",
"version": "1.2.1",
"version": "1.5.0",
"main": "create-card.js",
"repository": "https://github.com/xivapi/XIV-Character-Cards.git",
"license": "AGPL-3.0-only",
@ -10,21 +10,22 @@
"xivapi"
],
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"start": "node server.js",
"dev": "nodemon server.js",
"docs:generate": "jsdoc create-card.js -d docs -R readme.md",
"docs:deploy": "npm run docs:generate && node gh-pages.js"
},
"dependencies": {
"cache-manager-fs": "^1.0.8",
"cache-manager": "^3.4.4",
"cache-manager-fs-binary": "^1.0.4",
"canvas": "^2.6.1",
"canvas": "2.9.0",
"express": "^4.17.1",
"node-fetch": "^2.6.1"
"express-rate-limit": "^5.5.0",
"node-fetch": "^2.6.5"
},
"devDependencies": {
"gh-pages": "^3.2.0",
"gh-pages": "^3.2.3",
"jsdoc": "^3.6.7",
"nodemon": "^2.0.7"
"nodemon": "^2.0.14"
}
}

View file

@ -1,78 +1,76 @@
# XIV Character Cards
![npm Version](https://img.shields.io/npm/v/xiv-character-cards)
[![Documentation](https://img.shields.io/badge/docs-JSDoc-orange)](https://xivapi.github.io/XIV-Character-Cards/)
API to create fancy cards for FFXIV characters based on their Lodestone data, hosted at https://ffxiv-character-cards.herokuapp.com.
Library and API to create fancy cards for FFXIV characters based on their Lodestone data, powered by [xivapi.com](https://xivapi.com/) and hosted at [https://ffxiv-character-cards.herokuapp.com](https://ffxiv-character-cards.herokuapp.com).
![Demo image](https://ffxiv-character-cards.herokuapp.com/characters/id/9575452.png)
## Endpoints
## API
### Getting images
All API calls support the `lang` query parameter to create a character card with information in the specified language. The supported languages are the same as [xivapi.com](https://xivapi.com/docs/Common-Features#language), which are English (en), Japanese (ja), German (de) and French (fr).
``https://ffxiv-character-cards.herokuapp.com/characters/id/<LODESTONE ID>.png``
<br>Get the PNG for a character by its Lodestone ID.
E.g. a request for a german character card would look like this: ``https://ffxiv-character-cards.herokuapp.com/characters/id/<LODESTONE ID>.png?lang=de``
### Getting a card for a character by its Lodestone ID
``GET https://ffxiv-character-cards.herokuapp.com/characters/id/<LODESTONE ID>.png``
### Getting card for a character by its world and name
``GET https://ffxiv-character-cards.herokuapp.com/characters/name/<WORLD>/<CHARACTER NAME>.png``
<br>**Note:** This is considerably slower than the creation by ID, since the character has to be looked up in the Lodestone first.
<br>
``https://ffxiv-character-cards.herokuapp.com/characters/name/<WORLD>/<CHARACTER NAME>.png``
<br>Get the PNG for a character by its world and name.
### Requesting images to be cached
If you are using this API together with an application that requires the API to respond very quickly, like Discord, you need to ask it to "prepare" the image for a character beforehand.
``https://ffxiv-character-cards.herokuapp.com/prepare/id/<LODESTONE ID>``
<br>Request a character image to be cached by its Lodestone ID.
<br>
``https://ffxiv-character-cards.herokuapp.com/prepare/name/<WORLD>/<CHARACTER NAME>``
<br>Request a character image to be cached by its world and name.
The API will reply with its status, and in case of success, the URL to the final image.
If you are using this API together with an application that requires the API to respond very quickly, like Discord, you may need to ask it to "prepare" the card image for a character beforehand. The API will reply with its status, and in case of success, the URL to the final image.
``{"status":"ok","url":"/characters/id/123456789.png"}``
## Using in your application
### Requesting a card to be cached for a character by its Lodestone ID
```
``GET https://ffxiv-character-cards.herokuapp.com/prepare/id/<LODESTONE ID>``
### Requesting a card to be cached for a character by its world and name
``GET https://ffxiv-character-cards.herokuapp.com/prepare/name/<WORLD>/<CHARACTER NAME>``
## Library
To use the card creator as a library in your Node.JS application, first install it as a dependency with:
```sh
yarn add xiv-character-cards
# or
npm i xiv-character-cards
```
You will receive a PNG-buffer for you to use in your bot or application.<br>Check ``index.js`` for other usage examples.
You can then instantiate the class `CardCreator` from the library, call the asynchronous `insureInit()` function to make sure all resources are loaded and then use the asynchronous `createCard()` function with your characters Lodestone ID. You will receive a promise that resolves to a `Buffer` of the PNG image of your card, that you can use in your bot or application.
### Example
Check the [library documentation](https://xivapi.github.io/XIV-Character-Cards/) for more details.
> **Note:** The API server is not published as an NPM package, so if you want to host it yourself, clone the [Github repository](https://github.com/xivapi/XIV-Character-Cards) and put the Express.JS webserver defined in the `server.js` file behind a reverse proxy.
### Library example
```js
const { CardCreator } = require("xiv-character-cards");
const fs = require("fs");
const { writeFileSync } = require("fs");
const card = new CardCreator();
const lodestoneid = "13821878";
const creator = new CardCreator();
const lodestoneId = "13821878";
function example(cb) {
card.ensureInit()
.then(
() => card.createCard(lodestoneid),
(reason) => cb("Init failed: " + reason, null)
)
.then((image) =>
cb(null, {
binary: {
image: image,
},
})
)
.catch((reason) => cb("createCard failed: " + reason, null));
async function example() {
await creator.ensureInit();
return creator.createCard(lodestoneId);
}
example((err, response) => {
const buffer = response.binary.image;
fs.writeFileSync(`./${lodestoneid}.png`, response.binary.image, (err) => {
if (err) {
console.log(err);
}
example()
.then(card => {
writeFileSync(`./${lodestoneId}.png`, card);
})
.catch(error => {
console.error('Creator initialization or card creation failed!');
console.error(error);
});
});
```

View file

Before

Width:  |  Height:  |  Size: 596 KiB

After

Width:  |  Height:  |  Size: 596 KiB

View file

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

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