Merge branch 'react'

This commit is contained in:
Colin McLeod
2016-02-24 12:21:58 -08:00
251 changed files with 13118 additions and 9046 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["es2015", "react", "stage-0"]
}

61
.eslintrc Normal file
View File

@@ -0,0 +1,61 @@
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
"jsx": true,
"classes": true,
"modules": true
},
},
"env": {
"browser": true,
"node": true
},
"plugins": [
"react"
],
"extends": "plugin:react/recommended",
"settings": {
"react": {
"pragma": "React"
}
},
"rules": {
"strict": 0,
"no-underscore-dangle": 0,
"valid-jsdoc": [2, {
"requireReturn": false
}],
"require-jsdoc": [2, {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true
}
}],
"no-console": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"comma-style": [2, "last"],
"indent": [2, 2, { "SwitchCase": 1, "VariableDeclarator": 2 }],
"quotes": [2, "single"],
"no-spaced-func": 2,
"operator-linebreak": [2, "after"],
"padded-blocks": [2, "never"],
"semi": [2, "always"],
"no-undef": 2,
"semi-spacing": [2, { "before": false, "after": true }],
"space-before-blocks": [2, "always"],
"space-before-function-paren": [2, "never"],
"object-curly-spacing": [2, "always"],
"array-bracket-spacing": [2, "never"],
"computed-property-spacing": [2, "never"],
"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"spaced-comment": [2, "always"],
"no-var": 2,
"object-shorthand": [2, "always"],
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2
}
}

5
.gitignore vendored
View File

@@ -1,10 +1,5 @@
node_modules
bower_components
bower_components/*
build
.DS_Store
*.log
app/js/db.js
app/db.json
nginx.pid
template_cache.js

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "data"]
path = data
url = https://github.com/cmmcleod/coriolis-data.git

View File

@@ -3,17 +3,13 @@ notifications:
email: false
sudo: false
node_js:
- "0.12"
- "4.2.6"
cache:
directories:
- node_modules
- bower_components
before_script:
- npm install -g gulp
- npm install -g bower
- bower install
script:
- gulp lint
- gulp build-prod
- gulp test
- npm run lint
- npm test

View File

@@ -1,5 +1,4 @@
[![Build Status](https://travis-ci.org/cmmcleod/coriolis.svg?branch=master)](https://travis-ci.org/cmmcleod/coriolis) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis)
![Latest Release](https://img.shields.io/github/release/cmmcleod/coriolis.svg) [![Build Status](https://travis-ci.org/cmmcleod/coriolis.svg?branch=master)](https://travis-ci.org/cmmcleod/coriolis) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis) [![Chat to us on HipChat](https://img.shields.io/badge/HipChat-Coriolis-white.svg?style=social)](https://www.hipchat.com/gfYQiZcmy)
## About
@@ -14,6 +13,8 @@ Please [submit issues](https://github.com/cmmcleod/coriolis/issues), or better y
### Feature Requests, Suggestions & Bugs
Chat to us on [HipChat](https://www.hipchat.com/gfYQiZcmy)!
All such requests are managed and tracked through [issues](https://github.com/cmmcleod/coriolis/issues). An overview of these can be found [here](https://waffle.io/cmmcleod/coriolis).
## Development
@@ -21,7 +22,7 @@ All such requests are managed and tracked through [issues](https://github.com/cm
See the [Developer's Guide](https://github.com/cmmcleod/coriolis/wiki/Developer's-Guide) in the wiki.
### Ship and Component Database
### Ship and Module Database
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.

View File

@@ -1,12 +1,12 @@
{
"$schema": "http://cdn.coriolis.io/schemas/ship-loadout/2.json#",
"name": "Test",
"$schema": "http://cdn.coriolis.io/schemas/ship-loadout/3.json#",
"name": "Test My Ship",
"ship": "Anaconda",
"references": [
{
"name": "Coriolis.io",
"url": "http://localhost:3300/outfit/anaconda/48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18QDBNA%3D%3D%3D.AwhMJBGaei%2BJCyyiA%3D%3D%3D?bn=Test",
"code": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18QDBNA===.AwhMJBGaei+JCyyiA===",
"url": "http://localhost:3300/outfit/anaconda/48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA?bn=Test%20My%20Ship",
"code": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA",
"shipId": "anaconda"
}
],
@@ -263,8 +263,7 @@
"hullMass": 400,
"masslock": 23,
"pipSpeed": 0.14,
"shipCostMultiplier": 1,
"componentCostMultiplier": 1,
"moduleCostMultiplier": 1,
"fuelCapacity": 32,
"cargoCapacity": 128,
"ladenMass": 1339.2,
@@ -281,8 +280,8 @@
"unladenRange": 18.49,
"fullTankRange": 18.12,
"ladenRange": 16.39,
"unladenTotalRange": 73.21,
"ladenTotalRange": 66.15,
"unladenFastestRange": 73.21,
"ladenFastestRange": 66.15,
"maxJumpCount": 4,
"shieldStrength": 833
}

View File

@@ -16,7 +16,7 @@
"Miner": "25A5A5A4D4A5A5C0s0s24242l2l---04054a1q02022o27"
},
"cobra_mk_iii": {
"Example": "24A4A4A3D3A3A4C0s0s2d2d0m0445032b2o2753.AwRj4yKA.CwBhEYyrKhmMQ===",
"Example": "24A4A4A3D3A3A4C0s0s2d2d0m0445032b2o2753.AwRj4yKA.CwBhEYyrKhmMQ==="
},
"imperial_clipper": {
"Cargo": "03A5D5A5D4D5D4C--0s0s----0605450302020101",

View File

@@ -117,8 +117,8 @@
"unladenRange": 32.48,
"fullTankRange": 30.27,
"ladenRange": 19.61,
"unladenTotalRange": 176.71,
"ladenTotalRange": 112.92,
"unladenFastestRange": 176.71,
"ladenFastestRange": 112.92,
"maxJumpCount": 6,
"shieldStrength": 86.49
}
@@ -251,8 +251,8 @@
"unladenRange": 30.24,
"fullTankRange": 28.32,
"ladenRange": 19.8,
"unladenTotalRange": 164.89,
"ladenTotalRange": 114.03,
"unladenFastestRange": 164.89,
"ladenFastestRange": 114.03,
"maxJumpCount": 6,
"shieldStrength": 149.2
}
@@ -381,8 +381,8 @@
"unladenRange": 31.71,
"fullTankRange": 29.61,
"ladenRange": 23.58,
"unladenTotalRange": 172.68,
"ladenTotalRange": 136.46,
"unladenFastestRange": 172.68,
"ladenFastestRange": 136.46,
"maxJumpCount": 6,
"shieldStrength": 86.49
}
@@ -513,8 +513,8 @@
"unladenRange": 26.41,
"fullTankRange": 24.97,
"ladenRange": 17.36,
"unladenTotalRange": 172.04,
"ladenTotalRange": 118.55,
"unladenFastestRange": 172.04,
"ladenFastestRange": 118.55,
"maxJumpCount": 7,
"shieldStrength": 89.07
}
@@ -655,8 +655,8 @@
"unladenRange": 25.77,
"fullTankRange": 24.39,
"ladenRange": 17.98,
"unladenTotalRange": 167.93,
"ladenTotalRange": 122.84,
"unladenFastestRange": 167.93,
"ladenFastestRange": 122.84,
"maxJumpCount": 7,
"shieldStrength": 125.07
}
@@ -793,8 +793,8 @@
"unladenRange": 19.27,
"fullTankRange": 18.95,
"ladenRange": 15.43,
"unladenTotalRange": 67.34,
"ladenTotalRange": 54.75,
"unladenFastestRange": 67.34,
"ladenFastestRange": 54.75,
"maxJumpCount": 4,
"shieldStrength": 111.07
}
@@ -956,8 +956,8 @@
"unladenRange": 27.1,
"fullTankRange": 25.58,
"ladenRange": 21.94,
"unladenTotalRange": 176.39,
"ladenTotalRange": 150.58,
"unladenFastestRange": 176.39,
"ladenFastestRange": 150.58,
"maxJumpCount": 7,
"shieldStrength": 253.58
}
@@ -1098,8 +1098,8 @@
"unladenRange": 26.01,
"fullTankRange": 25.42,
"ladenRange": 17.19,
"unladenTotalRange": 90.67,
"ladenTotalRange": 61.04,
"unladenFastestRange": 90.67,
"ladenFastestRange": 61.04,
"maxJumpCount": 4,
"shieldStrength": 191.82
}
@@ -1262,8 +1262,8 @@
"unladenRange": 15.19,
"fullTankRange": 14.99,
"ladenRange": 14.99,
"unladenTotalRange": 53.15,
"ladenTotalRange": 53.15,
"unladenFastestRange": 53.15,
"ladenFastestRange": 53.15,
"maxJumpCount": 4,
"shieldStrength": 489.6
}
@@ -1362,8 +1362,8 @@
"unladenRange": 24.25,
"fullTankRange": 23.73,
"ladenRange": 23.73,
"unladenTotalRange": 84.56,
"ladenTotalRange": 84.56,
"unladenFastestRange": 84.56,
"ladenFastestRange": 84.56,
"maxJumpCount": 4,
"shieldStrength": 0
}
@@ -1501,8 +1501,8 @@
"unladenRange": 19.51,
"fullTankRange": 18.58,
"ladenRange": 13.09,
"unladenTotalRange": 152.32,
"ladenTotalRange": 106.49,
"unladenFastestRange": 152.32,
"ladenFastestRange": 106.49,
"maxJumpCount": 8,
"shieldStrength": 170.57
}
@@ -1639,8 +1639,8 @@
"unladenRange": 28.25,
"fullTankRange": 26.6,
"ladenRange": 16.67,
"unladenTotalRange": 183.67,
"ladenTotalRange": 113.69,
"unladenFastestRange": 183.67,
"ladenFastestRange": 113.69,
"maxJumpCount": 7,
"shieldStrength": 214.26
}
@@ -1810,8 +1810,8 @@
"unladenRange": 20.32,
"fullTankRange": 19.46,
"ladenRange": 14.65,
"unladenTotalRange": 133.17,
"ladenTotalRange": 99.65,
"unladenFastestRange": 133.17,
"ladenFastestRange": 99.65,
"maxJumpCount": 7,
"shieldStrength": 486.35
}
@@ -1989,8 +1989,8 @@
"unladenRange": 14.32,
"fullTankRange": 13.89,
"ladenRange": 13.46,
"unladenTotalRange": 94.42,
"ladenTotalRange": 91.49,
"unladenFastestRange": 94.42,
"ladenFastestRange": 91.49,
"maxJumpCount": 7,
"shieldStrength": 645.57
}
@@ -2219,8 +2219,8 @@
"unladenRange": 16.99,
"fullTankRange": 16.68,
"ladenRange": 15.91,
"unladenTotalRange": 67.35,
"ladenTotalRange": 64.2,
"unladenFastestRange": 67.35,
"ladenFastestRange": 64.2,
"maxJumpCount": 4,
"shieldStrength": 952
}
@@ -2374,8 +2374,8 @@
"unladenRange": 39.26,
"fullTankRange": 37.65,
"ladenRange": 21.21,
"unladenTotalRange": 153.79,
"ladenTotalRange": 85.82,
"unladenFastestRange": 153.79,
"ladenFastestRange": 85.82,
"maxJumpCount": 4,
"shieldStrength": 372.98
}
@@ -2530,8 +2530,8 @@
"unladenRange": 38.44,
"fullTankRange": 36.89,
"ladenRange": 21.04,
"unladenTotalRange": 150.62,
"ladenTotalRange": 85.16,
"unladenFastestRange": 150.62,
"ladenFastestRange": 85.16,
"maxJumpCount": 4,
"shieldStrength": 372.98
}
@@ -2698,8 +2698,8 @@
"unladenRange": 38.04,
"fullTankRange": 30.11,
"ladenRange": 23.03,
"unladenTotalRange": 675.7,
"ladenTotalRange": 501.97,
"unladenFastestRange": 675.7,
"ladenFastestRange": 501.97,
"maxJumpCount": 20,
"shieldStrength": 372.98
}
@@ -2916,8 +2916,8 @@
"unladenRange": 18.49,
"fullTankRange": 18.12,
"ladenRange": 16.39,
"unladenTotalRange": 73.21,
"ladenTotalRange": 66.15,
"unladenFastestRange": 73.21,
"ladenFastestRange": 66.15,
"maxJumpCount": 4,
"shieldStrength": 833
}
@@ -3044,8 +3044,8 @@
"unladenRange": 35.99,
"fullTankRange": 33.36,
"ladenRange": 33.36,
"unladenTotalRange": 232.28,
"ladenTotalRange": 232.28,
"unladenFastestRange": 232.28,
"ladenFastestRange": 232.28,
"maxJumpCount": 7,
"shieldStrength": 92.25
}
@@ -3181,8 +3181,8 @@
"unladenRange": 15.06,
"fullTankRange": 14.86,
"ladenRange": 14.86,
"unladenTotalRange": 42.5,
"ladenTotalRange": 42.5,
"unladenFastestRange": 42.5,
"ladenFastestRange": 42.5,
"maxJumpCount": 3,
"shieldStrength": 548.74
}
@@ -3335,8 +3335,8 @@
"unladenRange": 12.51,
"fullTankRange": 12.38,
"ladenRange": 12.38,
"unladenTotalRange": 35.35,
"ladenTotalRange": 35.35,
"unladenFastestRange": 35.35,
"ladenFastestRange": 35.35,
"maxJumpCount": 3,
"shieldStrength": 760.16
}
@@ -3454,8 +3454,8 @@
"unladenRange": 17.12,
"fullTankRange": 16.71,
"ladenRange": 16.71,
"unladenTotalRange": 42.4,
"ladenTotalRange": 42.4,
"unladenFastestRange": 42.4,
"ladenFastestRange": 42.4,
"maxJumpCount": 3,
"shieldStrength": 102
}
@@ -3612,8 +3612,8 @@
"unladenRange": 8.43,
"fullTankRange": 8.09,
"ladenRange": 7.25,
"unladenTotalRange": 81.5,
"ladenTotalRange": 72.9,
"unladenFastestRange": 81.5,
"ladenFastestRange": 72.9,
"maxJumpCount": 10,
"shieldStrength": 299.48
}

226
__tests__/test-import.js Normal file
View File

@@ -0,0 +1,226 @@
jest.dontMock('../src/app/stores/Persist');
jest.dontMock('../src/app/components/TranslatedComponent');
jest.dontMock('../src/app/components/ModalImport');
import React from 'react';
import ReactDOM from 'react-dom';
import TU from 'react-testutils-additions';
import Utils from './testUtils';
import { getLanguage } from '../src/app/i18n/Language';
describe('Import Modal', function() {
let MockRouter = require('../src/app/Router');
const Persist = require('../src/app/stores/Persist').default;
const ModalImport = require('../src/app/components/ModalImport').default;
const mockContext = {
language: getLanguage('en'),
sizeRatio: 1,
openMenu: jest.genMockFunction(),
closeMenu: jest.genMockFunction(),
showModal: jest.genMockFunction(),
hideModal: jest.genMockFunction(),
tooltip: jest.genMockFunction(),
termtip: jest.genMockFunction(),
onWindowResize: jest.genMockFunction()
};
MockRouter.go = jest.genMockFunction();
let modal, render, ContextProvider = Utils.createContextProvider(mockContext);
/**
* Clear saved builds, and reset React DOM
*/
function reset() {
MockRouter.go.mockClear();
Persist.deleteAll();
render = TU.renderIntoDocument(<ContextProvider><ModalImport /></ContextProvider>);
modal = TU.findRenderedComponentWithType(render, ModalImport);
}
/**
* Simulate user import text entry / paste
* @param {string} text Import text / raw data
*/
function pasteText(text) {
let textarea = TU.findRenderedDOMComponentWithTag(render, 'textarea');
TU.Simulate.change(textarea, { target: { value: text } });
}
/**
* Simulate click on Proceed button
*/
function clickProceed() {
let proceedButton = TU.findRenderedDOMComponentWithId(render, 'proceed');
TU.Simulate.click(proceedButton);
}
/**
* Simulate click on Import button
*/
function clickImport() {
let importButton = TU.findRenderedDOMComponentWithId(render, 'import');
TU.Simulate.click(importButton);
}
describe('Import Backup', function() {
beforeEach(reset);
it('imports a valid backup', function() {
let importData = require('./fixtures/valid-backup');
let importString = JSON.stringify(importData);
expect(modal.state.importValid).toEqual(false);
expect(modal.state.errorMsg).toEqual(null);
pasteText(importString);
expect(modal.state.importValid).toBe(true);
expect(modal.state.errorMsg).toEqual(null);
expect(modal.state.builds).toEqual(importData.builds);
expect(modal.state.comparisons).toEqual(importData.comparisons);
expect(modal.state.shipDiscount).toEqual(importData.discounts[0]);
expect(modal.state.moduleDiscount).toEqual(importData.discounts[1]);
expect(modal.state.insurance).toBe(importData.insurance.toLowerCase());
clickProceed();
expect(modal.state.processed).toBe(true);
expect(modal.state.errorMsg).toEqual(null);
clickImport();
expect(Persist.getBuilds()).toEqual(importData.builds);
expect(Persist.getComparisons()).toEqual(importData.comparisons);
expect(Persist.getInsurance()).toEqual(importData.insurance.toLowerCase());
expect(Persist.getShipDiscount()).toEqual(importData.discounts[0]);
expect(Persist.getModuleDiscount()).toEqual(importData.discounts[1]);
});
it('imports an old valid backup', function() {
const importData = require('./fixtures/old-valid-export');
const importStr = JSON.stringify(importData);
pasteText(importStr);
expect(modal.state.builds).toEqual(importData.builds);
expect(modal.state.importValid).toBe(true);
expect(modal.state.errorMsg).toEqual(null);
clickProceed();
expect(modal.state.processed).toBeTruthy();
clickImport();
expect(Persist.getBuilds()).toEqual(importData.builds);
});
it('catches an invalid backup', function() {
const importData = require('./fixtures/valid-backup');
let invalidImportData = Object.assign({}, importData);
invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison
pasteText('"this is not valid"');
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('Must be an object or array!');
pasteText('{ "builds": "Should not be a string" }');
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('builds must be an object!');
pasteText(JSON.stringify(importData).replace('anaconda', 'invalid_ship'));
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!');
pasteText(JSON.stringify(importData).replace('Dream', ''));
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 1 character long!');
pasteText(JSON.stringify(invalidImportData));
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('asp build "Miner" data is missing!');
});
});
describe('Import Detailed Build', function() {
beforeEach(reset);
it('imports a valid v3 build', function() {
const importData = require('./fixtures/anaconda-test-detailed-export-v3');
pasteText(JSON.stringify(importData));
expect(modal.state.importValid).toBeTruthy();
expect(modal.state.errorMsg).toEqual(null);
clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda/48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA?bn=Test%20My%20Ship');
});
it('catches an invalid build', function() {
const importData = require('./fixtures/anaconda-test-detailed-export-v3');
pasteText(JSON.stringify(importData).replace('components', 'comps'));
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual('Anaconda Build "Test My Ship": Invalid data');
});
});
describe('Import Detaild Builds Array', function() {
beforeEach(reset);
it('imports all builds', function() {
const importData = require('./fixtures/valid-detailed-export');
const expectedBuilds = require('./fixtures/expected-builds');
pasteText(JSON.stringify(importData));
expect(modal.state.importValid).toBeTruthy();
expect(modal.state.errorMsg).toEqual(null);
clickProceed();
expect(modal.state.processed).toBeTruthy();
clickImport();
let builds = Persist.getBuilds();
for (let s in builds) {
for (let b in builds[s]) {
expect(builds[s][b]).toEqual(expectedBuilds[s][b]);
}
}
});
});
describe('Import E:D Shipyard Builds', function() {
it('imports a valid builds', function() {
const imports = require('./fixtures/ed-shipyard-import-valid');
for (let i = 0; i < imports.length; i++ ) {
reset();
let fixture = imports[i];
pasteText(fixture.buildText);
expect(modal.state.importValid).toBeTruthy();
expect(modal.state.errorMsg).toEqual(null);
clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/' + fixture.shipId + '/' + fixture.buildCode + '?bn=' + encodeURIComponent(fixture.buildName));
}
});
it('catches invalid builds', function() {
const imports = require('./fixtures/ed-shipyard-import-invalid');
for (let i = 0; i < imports.length; i++ ) {
reset();
pasteText(imports[i].buildText);
expect(modal.state.importValid).toBeFalsy();
expect(modal.state.errorMsg).toEqual(imports[i].errorMsg);
}
});
});
describe('Imports from a Comparison', function() {
it('imports a valid comparison', function() {
const importBuilds = require('./fixtures/valid-backup').builds;
Persist.deleteAll();
render = TU.renderIntoDocument(<ContextProvider><ModalImport builds={importBuilds} /></ContextProvider>);
modal = TU.findRenderedComponentWithType(render, ModalImport);
expect(modal.state.processed).toBe(true);
expect(modal.state.errorMsg).toEqual(null);
clickImport();
expect(Persist.getBuilds()).toEqual(importBuilds);
});
});
});

143
__tests__/test-persist.js Normal file
View File

@@ -0,0 +1,143 @@
jest.dontMock('../src/app/stores/Persist');
import React from 'react';
import ReactDOM from 'react-dom';
import TU from 'react-testutils-additions';
let origAddEventListener = window.addEventListener;
let storageListener;
let ls = {};
// Implment mock localStorage
let localStorage = {
getItem: function(key) {
return ls[key];
},
setItem: function(key, value) {
ls[key] = value;
},
removeItem: function(key) {
delete ls[key];
},
clear: function() {
ls = {};
}
}
window.addEventListener = function(eventName, listener) {
if(eventName == 'storage') {
storageListener = listener; // Keep track of latest storage listener
} else {
origAddEventListener.apply(arguments);
}
}
describe('Persist', function() {
const Persist = require('../src/app/stores/Persist').Persist;
describe('Multi tab/window', function() {
it("syncs builds", function() {
window.localStorage = localStorage;
ls = {};
let p = new Persist();
let newBuilds = {
anaconda: { test: '1234' }
};
storageListener({ key: 'builds', newValue: JSON.stringify(newBuilds) });
expect(p.getBuild('anaconda', 'test')).toBe('1234');
});
});
describe('General and Settings', function() {
it("has defaults", function() {
window.localStorage = localStorage;
ls = {};
let p = new Persist();
expect(p.getLangCode()).toBe('en');
expect(p.showTooltips()).toBe(true);
expect(p.getInsurance()).toBe('standard');
expect(p.getShipDiscount()).toBe(0);
expect(p.getModuleDiscount()).toBe(0);
expect(p.getSizeRatio()).toBe(1);
});
it("loads from localStorage correctly", function() {
window.localStorage = localStorage;
let savedData = require('./fixtures/valid-backup');
ls = {};
ls.builds = JSON.stringify(savedData.builds);
ls.NG_TRANSLATE_LANG_KEY = 'de';
ls.insurance = 'Standard';
ls.shipDiscount = 0.25;
ls.moduleDiscount = 0.15;
let p = new Persist();
expect(p.getInsurance()).toBe('standard');
expect(p.getShipDiscount()).toBe(0.25);
expect(p.getModuleDiscount()).toBe(0.15);
expect(p.getLangCode()).toEqual('de');
expect(p.getBuilds('anaconda')).toEqual(savedData.builds.anaconda);
expect(p.getBuilds('python')).toEqual(savedData.builds.python);
expect(p.getBuildsNamesFor('imperial_clipper')).toEqual(['Cargo', 'Current', 'Dream', 'Multi-purpose']);
expect(p.getBuild('type_7_transport', 'Cargo')).toEqual('02A5D5A4D3D3D5C--------0505040403480101');
});
it("uses defaults from a corrupted localStorage", function() {
window.localStorage = localStorage;
ls = {};
ls.builds = "not valid json";
ls.comparisons = "1, 3, 4";
ls.insurance = 'this insurance does not exist';
ls.shipDiscount = 'this is not a number';
ls.moduleDiscount = 10; // Way to big
let p = new Persist();
expect(p.getLangCode()).toBe('en');
expect(p.showTooltips()).toBe(true);
expect(p.getInsurance()).toBe('standard');
expect(p.getShipDiscount()).toBe(0);
expect(p.getModuleDiscount()).toBe(0);
expect(p.getBuilds()).toEqual({});
expect(p.getComparisons()).toEqual({});
});
it("works without localStorage", function() {
window.localStorage = null;
let p = new Persist();
expect(p.getLangCode()).toBe('en');
expect(p.showTooltips()).toBe(true);
expect(p.getInsurance()).toBe('standard');
expect(p.getShipDiscount()).toBe(0);
expect(p.getModuleDiscount()).toBe(0);
expect(p.getSizeRatio()).toBe(1);
p.saveBuild('anaconda', 'test', '12345');
expect(p.getBuild('anaconda', 'test')).toBe('12345');
p.deleteBuild('anaconda', 'test');
expect(p.hasBuilds()).toBe(false);
});
it("generates the backup", function() {
window.localStorage = localStorage;
let savedData = require('./fixtures/valid-backup');
ls = {};
ls.builds = JSON.stringify(savedData.builds);
ls.insurance = 'Beta';
ls.shipDiscount = 0.25;
ls.moduleDiscount = 0.15;
let p = new Persist();
let backup = p.getAll();
expect(backup.insurance).toBe('beta');
expect(backup.shipDiscount).toBe(0.25);
expect(backup.moduleDiscount).toBe(0.15);
expect(backup.builds).toEqual(savedData.builds);
expect(backup.comparisons).toEqual({});
});
});
})

View File

@@ -0,0 +1,63 @@
import Ship from '../src/app/shipyard/Ship';
import { Ships } from 'coriolis-data/dist';
import * as Serializer from '../src/app/shipyard/Serializer';
import jsen from 'jsen';
describe("Serializer", function() {
const anacondaTestExport = require.requireActual('./fixtures/anaconda-test-detailed-export-v3');
const code = anacondaTestExport.references[0].code;
const anaconda = Ships.anaconda;
const validate = jsen(require('../src/schemas/ship-loadout/3'));
describe("To Detailed Build", function() {
let testBuild = new Ship('anaconda', anaconda.properties, anaconda.slots).buildFrom(code);
let exportData = Serializer.toDetailedBuild('Test My Ship', testBuild);
it("conforms to the v3 ship-loadout schema", function() {
expect(validate(exportData)).toBe(true);
});
it("contains the correct components and stats", function() {
expect(exportData.components).toEqual(anacondaTestExport.components);
expect(exportData.stats).toEqual(anacondaTestExport.stats);
expect(exportData.ship).toEqual(anacondaTestExport.ship);
expect(exportData.name).toEqual(anacondaTestExport.name);
});
});
describe("Export Detailed Builds", function() {
const expectedExport = require('./fixtures/valid-detailed-export');
const builds = require('./fixtures/expected-builds');
const exportData = Serializer.toDetailedExport(builds);
it("conforms to the v3 ship-loadout schema", function() {
expect(exportData instanceof Array).toBe(true);
for (let detailedBuild of exportData) {
expect(validate(detailedBuild)).toBe(true);
}
});
});
describe("From Detailed Build", function() {
it("builds the ship correctly", function() {
let testBuildA = new Ship('anaconda', anaconda.properties, anaconda.slots);
testBuildA.buildFrom(code);
let testBuildB = Serializer.fromDetailedBuild(anacondaTestExport);
for(var p in testBuildB) {
if (p == 'availCS') {
continue;
}
expect(testBuildB[p]).toEqual(testBuildA[p], p + ' does not match');
}
});
});
});

View File

@@ -1,20 +1,15 @@
import Ship from '../src/app/shipyard/Ship';
import { Ships } from 'coriolis-data/dist';
import * as ModuleUtils from '../src/app/shipyard/ModuleUtils';
describe("Ship Factory", function() {
var Ship;
var Components;
beforeEach(module('shipyard'));
beforeEach(inject(['Ship', 'Components', function (_Ship_, _Components_) {
Ship = _Ship_;
Components = _Components_;
}]));
it("can build all ships", function() {
for (var s in DB.ships) {
var shipData = DB.ships[s];
var ship = new Ship(s, shipData.properties, shipData.slots);
for (let s in Ships) {
let shipData = Ships[s];
let ship = new Ship(s, shipData.properties, shipData.slots);
for (p in shipData.properties) {
for (let p in shipData.properties) {
expect(ship[p]).toEqual(shipData.properties[p], s + ' property [' + p + '] does not match when built');
}
@@ -27,8 +22,8 @@ describe("Ship Factory", function() {
expect(ship.unladenRange).toBeGreaterThan(0, s + ' unladenRange');
expect(ship.ladenRange).toBeGreaterThan(0, s + ' ladenRange');
expect(ship.fuelCapacity).toBeGreaterThan(0, s + ' fuelCapacity');
expect(ship.unladenTotalRange).toBeGreaterThan(0, s + ' unladenTotalRange');
expect(ship.ladenTotalRange).toBeGreaterThan(0, s + ' ladenTotalRange');
expect(ship.unladenFastestRange).toBeGreaterThan(0, s + ' unladenFastestRange');
expect(ship.ladenFastestRange).toBeGreaterThan(0, s + ' ladenFastestRange');
expect(ship.shieldStrength).toBeGreaterThan(0, s + ' shieldStrength');
expect(ship.armour).toBeGreaterThan(0, s + ' armour');
expect(ship.topSpeed).toBeGreaterThan(0, s + ' topSpeed');
@@ -37,7 +32,7 @@ describe("Ship Factory", function() {
it("resets and rebuilds properly", function() {
var id = 'cobra_mk_iii';
var cobra = DB.ships[id];
var cobra = Ships[id];
var shipA = new Ship(id, cobra.properties, cobra.slots);
var shipB = new Ship(id, cobra.properties, cobra.slots);
var testShip = new Ship(id, cobra.properties, cobra.slots);
@@ -81,84 +76,84 @@ describe("Ship Factory", function() {
it("discounts hull and components properly", function() {
var id = 'cobra_mk_iii';
var cobra = DB.ships[id];
var cobra = Ships[id];
var testShip = new Ship(id, cobra.properties, cobra.slots);
testShip.buildWith(cobra.defaults);
var originalHullCost = testShip.hullCost;
var originalTotalCost = testShip.totalCost;
var discount = 0.9;
var discount = 0.1;
expect(testShip.c.discountedCost).toEqual(originalHullCost, 'Hull cost does not match');
expect(testShip.m.discountedCost).toEqual(originalHullCost, 'Hull cost does not match');
testShip.applyDiscounts(discount, discount);
// Floating point errors cause miniscule decimal places which are handled in the app by rounding/formatting
expect(Math.floor(testShip.c.discountedCost)).toEqual(Math.floor(originalHullCost * discount), 'Discounted Hull cost does not match');
expect(Math.floor(testShip.totalCost)).toEqual(Math.floor(originalTotalCost * discount), 'Discounted Total cost does not match');
expect(Math.floor(testShip.m.discountedCost)).toEqual(Math.floor(originalHullCost * (1 - discount)), 'Discounted Hull cost does not match');
expect(Math.floor(testShip.totalCost)).toEqual(Math.floor(originalTotalCost * (1 - discount)), 'Discounted Total cost does not match');
testShip.applyDiscounts(1, 1); // No discount, 100% of cost
testShip.applyDiscounts(0, 0); // No discount, 100% of cost
expect(testShip.c.discountedCost).toEqual(originalHullCost, 'Hull cost does not match');
expect(testShip.m.discountedCost).toEqual(originalHullCost, 'Hull cost does not match');
expect(testShip.totalCost).toEqual(originalTotalCost, 'Total cost does not match');
testShip.applyDiscounts(discount, 1); // Only discount hull
testShip.applyDiscounts(discount, 0); // Only discount hull
expect(Math.floor(testShip.c.discountedCost)).toEqual(Math.round(originalHullCost * discount), 'Discounted Hull cost does not match');
expect(testShip.totalCost).toEqual(originalTotalCost - originalHullCost + testShip.c.discountedCost, 'Total cost does not match');
expect(Math.floor(testShip.m.discountedCost)).toEqual(Math.round(originalHullCost * (1 - discount)), 'Discounted Hull cost does not match');
expect(testShip.totalCost).toEqual(originalTotalCost - originalHullCost + testShip.m.discountedCost, 'Total cost does not match');
});
it("enforces a single shield generator", function() {
var id = 'anaconda';
var anacondaData = DB.ships[id];
var anacondaData = Ships[id];
var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots);
anaconda.buildWith(anacondaData.defaults);
expect(anaconda.internal[2].c.grp).toEqual('sg', 'Anaconda default shield generator slot');
expect(anaconda.internal[2].m.grp).toEqual('sg', 'Anaconda default shield generator slot');
anaconda.use(anaconda.internal[1], '4j', Components.internal('4j')); // 6E Shield Generator
anaconda.use(anaconda.internal[1], ModuleUtils.internal('4j')); // 6E Shield Generator
expect(anaconda.internal[2].c).toEqual(null, 'Anaconda default shield generator slot is empty');
expect(anaconda.internal[2].id).toEqual(null, 'Anaconda default shield generator slot id is null');
expect(anaconda.internal[1].id).toEqual('4j', 'Slot 1 should have SG 4j in it');
expect(anaconda.internal[1].c.grp).toEqual('sg','Slot 1 should have SG 4j in it');
expect(anaconda.internal[2].m).toEqual(null, 'Anaconda default shield generator slot id is null');
expect(anaconda.internal[1].m.id).toEqual('4j', 'Slot 1 should have SG 4j in it');
expect(anaconda.internal[1].m.grp).toEqual('sg','Slot 1 should have SG 4j in it');
});
it("enforces a single shield fuel scoop", function() {
var id = 'anaconda';
var anacondaData = DB.ships[id];
var anacondaData = Ships[id];
var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots);
anaconda.buildWith(anacondaData.defaults);
anaconda.use(anaconda.internal[4], '32', Components.internal('32')); // 4A Fuel Scoop
expect(anaconda.internal[4].c.grp).toEqual('fs', 'Anaconda fuel scoop slot');
anaconda.use(anaconda.internal[4], ModuleUtils.internal('32')); // 4A Fuel Scoop
expect(anaconda.internal[4].m.grp).toEqual('fs', 'Anaconda fuel scoop slot');
anaconda.use(anaconda.internal[3], '32', Components.internal('32'));
anaconda.use(anaconda.internal[3], ModuleUtils.internal('32'));
expect(anaconda.internal[4].c).toEqual(null, 'Anaconda original fuel scoop slot is empty');
expect(anaconda.internal[4].id).toEqual(null, 'Anaconda original fuel scoop slot id is null');
expect(anaconda.internal[3].id).toEqual('32', 'Slot 1 should have FS 32 in it');
expect(anaconda.internal[3].c.grp).toEqual('fs','Slot 1 should have FS 32 in it');
expect(anaconda.internal[4].m).toEqual(null, 'Anaconda original fuel scoop slot id is null');
expect(anaconda.internal[3].m.id).toEqual('32', 'Slot 1 should have FS 32 in it');
expect(anaconda.internal[3].m.grp).toEqual('fs','Slot 1 should have FS 32 in it');
});
it("enforces a single refinery", function() {
var id = 'anaconda';
var anacondaData = DB.ships[id];
var anacondaData = Ships[id];
var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots);
anaconda.buildWith(anacondaData.defaults);
anaconda.use(anaconda.internal[4], '23', Components.internal('23')); // 4E Refinery
expect(anaconda.internal[4].c.grp).toEqual('rf', 'Anaconda refinery slot');
anaconda.use(anaconda.internal[4], ModuleUtils.internal('23')); // 4E Refinery
expect(anaconda.internal[4].m.grp).toEqual('rf', 'Anaconda refinery slot');
anaconda.use(anaconda.internal[3], '23', Components.internal('23'));
anaconda.use(anaconda.internal[3], ModuleUtils.internal('23'));
expect(anaconda.internal[4].c).toEqual(null, 'Anaconda original refinery slot is empty');
expect(anaconda.internal[4].id).toEqual(null, 'Anaconda original refinery slot id is null');
expect(anaconda.internal[3].id).toEqual('23', 'Slot 1 should have RF 23 in it');
expect(anaconda.internal[3].c.grp).toEqual('rf','Slot 1 should have RF 23 in it');
expect(anaconda.internal[4].m).toEqual(null, 'Anaconda original refinery slot id is null');
expect(anaconda.internal[3].m.id).toEqual('23', 'Slot 1 should have RF 23 in it');
expect(anaconda.internal[3].m.grp).toEqual('rf','Slot 1 should have RF 23 in it');
});
});

24
__tests__/testUtils.js Normal file
View File

@@ -0,0 +1,24 @@
import React from 'react';
const TestUtils = {
createContextProvider: function(context) {
var _contextTypes = {};
Object.keys(context).forEach(function(key) {
_contextTypes[key] = React.PropTypes.any;
});
return React.createClass({
displayName: 'ContextProvider',
childContextTypes: _contextTypes,
getChildContext() { return context; },
render() {
return React.Children.only(this.props.children);
}
});
}
};
export default TestUtils;

View File

@@ -1,397 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata></metadata>
<defs>
<font id="orbitronregular" horiz-adv-x="1695" >
<font-face units-per-em="2048" ascent="1536" descent="-512" />
<missing-glyph horiz-adv-x="557" />
<glyph horiz-adv-x="0" />
<glyph unicode="&#xd;" horiz-adv-x="681" />
<glyph unicode=" " horiz-adv-x="557" />
<glyph unicode="&#x09;" horiz-adv-x="557" />
<glyph unicode="&#xa0;" horiz-adv-x="557" />
<glyph unicode="!" horiz-adv-x="450" d="M119 0v168h168v-168h-168zM119 416v1059h168v-1059h-168z" />
<glyph unicode="&#x22;" horiz-adv-x="761" d="M121 1188v287h168v-287h-168zM438 1188v287h168v-287h-168z" />
<glyph unicode="#" horiz-adv-x="1632" d="M66 350v168h260l145 451h-340v168h393l115 336h166l-117 -336h535l114 336h166l-117 -336h197v-168h-248l-145 -451h326v-168h-379l-109 -350h-168l111 350h-533l-108 -350h-168l110 350h-206zM494 518h530l145 451h-532z" />
<glyph unicode="$" horiz-adv-x="1613" d="M70 248v59h168v-59q0 -33 23.5 -56.5t55.5 -23.5h414v487h-414q-102 0 -174.5 72t-72.5 176v324q0 104 72.5 177t174.5 73h414v233h168v-233h412q104 0 177 -73t73 -177v-58h-170v58q0 33 -24 56.5t-56 23.5h-412v-484h412q104 0 177 -72.5t73 -175.5v-327 q0 -102 -73 -175t-177 -73h-412v-233h-168v233h-414q-102 0 -174.5 72.5t-72.5 175.5zM238 903q0 -33 23.5 -56.5t55.5 -23.5h414v484h-414q-33 0 -56 -23.5t-23 -56.5v-324zM899 168h412q33 0 56.5 23.5t23.5 56.5v327q0 33 -23.5 56.5t-56.5 23.5h-412v-487z" />
<glyph unicode="%" horiz-adv-x="1978" d="M98 1053v172q0 104 73 177t177 73h193q104 0 177 -73t73 -177v-172q0 -102 -73 -175t-177 -73h-193q-104 0 -177 72.5t-73 175.5zM223 1010q0 -33 23.5 -56.5t56.5 -23.5h283q33 0 56.5 23.5t23.5 56.5v258q0 33 -24 56.5t-56 23.5h-283q-33 0 -56.5 -24t-23.5 -56v-258z M281 0v221l1491 1256v-220zM1219 246v174q0 102 71.5 175t175.5 73h195q102 0 175 -73t73 -175v-174q0 -102 -73 -175t-175 -73h-195q-104 0 -175.5 72.5t-71.5 175.5zM1343 203q0 -33 23.5 -56.5t56.5 -23.5h281q33 0 56.5 23.5t23.5 56.5v260q0 33 -23.5 56.5t-56.5 23.5 h-281q-33 0 -56.5 -23.5t-23.5 -56.5v-260z" />
<glyph unicode="&#x26;" horiz-adv-x="1921" d="M109 248v440q0 45 55 89t147 44q-117 88 -116 197v205q0 104 72.5 177t174.5 73h842q84 0 154.5 -62.5t95.5 -146.5v-113h-170v70q0 33 -23.5 56t-56.5 23h-842q-33 0 -56.5 -23.5t-23.5 -55.5v-285l1068 -539v285h167v-340l275 -162v-147l-281 157q-35 -86 -99.5 -138 t-141.5 -52h-994q-102 0 -174.5 72.5t-72.5 175.5zM276 248q0 -33 23.5 -56.5t56.5 -23.5h994q23 0 45 20.5t37 53.5l-1045 526h-31q-33 0 -56.5 -23.5t-23.5 -56.5v-440z" />
<glyph unicode="'" horiz-adv-x="458" d="M121 1188v287h168v-287h-168z" />
<glyph unicode="(" horiz-adv-x="567" d="M106 248v977q0 104 73 177t175 73h60v-170h-60q-33 0 -56.5 -24t-23.5 -56v-977q0 -33 23.5 -56.5t56.5 -23.5h60v-168h-60q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode=")" horiz-adv-x="569" d="M115 0v168h57q33 0 56.5 23.5t23.5 56.5v977q0 33 -23.5 56.5t-56.5 23.5h-57v170h57q102 0 176 -73t74 -177v-977q0 -102 -74 -175t-176 -73h-57z" />
<glyph unicode="*" horiz-adv-x="1005" d="M51 1096l49 161l301 -100v316h168v-314l297 98l56 -161l-299 -97l184 -256q-25 -18 -67 -48.5t-68 -49.5l-187 252l-184 -252q-31 23 -74 52.5t-63 43.5l184 258z" />
<glyph unicode="+" horiz-adv-x="886" d="M35 522v168h311v314h168v-314h320v-168h-320v-317h-168v317h-311z" />
<glyph unicode="," horiz-adv-x="395" d="M111 168h168v-201q0 -82 -47.5 -146.5t-120.5 -88.5v436z" />
<glyph unicode="-" horiz-adv-x="1058" d="M121 522v168h799v-168h-799z" />
<glyph unicode="." horiz-adv-x="438" d="M111 0v168h168v-168h-168z" />
<glyph unicode="/" horiz-adv-x="1067" d="M12 0v217l1037 1258v-213z" />
<glyph unicode="0" horiz-adv-x="1708" d="M117 248v977q0 104 72 177t176 73h993q102 0 175 -73t73 -177v-977q0 -102 -73 -175t-175 -73h-993q-104 0 -176 72.5t-72 175.5zM285 371l1130 934h-1050q-33 0 -56.5 -24t-23.5 -56v-854zM305 168h1053q33 0 56.5 23.5t23.5 56.5v854z" />
<glyph unicode="1" horiz-adv-x="800" d="M2 1014l387 461h229v-1475h-169v1286q-29 -37 -114 -137t-114 -135h-219z" />
<glyph unicode="2" horiz-adv-x="1699" d="M117 0v553q0 104 71.5 176t176.5 72h993q33 0 56.5 23.5t23.5 56.5v346q0 33 -23.5 56.5t-56.5 23.5h-993q-33 0 -56.5 -23.5t-23.5 -56.5v-58h-168v58q0 104 72 177t176 73h993q102 0 175 -73t73 -177v-346q0 -102 -73 -175t-175 -73h-993q-33 0 -56.5 -23.5 t-23.5 -56.5v-305q0 -33 23.5 -56.5t56.5 -23.5h1241v-168h-1489z" />
<glyph unicode="3" horiz-adv-x="1691" d="M109 248v33h170v-33q0 -33 23.5 -56.5t55.5 -23.5h994q33 0 56.5 23.5t23.5 56.5v342q0 33 -24 56.5t-56 23.5h-961v168h895q33 0 56.5 23.5t23.5 56.5v309q0 33 -23.5 56.5t-56.5 23.5h-928q-33 0 -56 -23.5t-23 -56.5v-53h-170v53q0 104 72.5 177t176.5 73h928 q104 0 176 -73t72 -177v-309q0 -54 -25 -107l9 -37q82 -76 81 -184v-342q0 -102 -72.5 -175t-174.5 -73h-994q-104 0 -176.5 72.5t-72.5 175.5z" />
<glyph unicode="4" horiz-adv-x="1495" d="M12 381v188l1008 908h188v-928h230v-168h-230v-381h-168v381h-1028zM227 549h813v659z" />
<glyph unicode="5" horiz-adv-x="1699" d="M117 248v59h168v-59q0 -33 23.5 -56.5t56.5 -23.5h993q33 0 56.5 23.5t23.5 56.5v348q0 33 -23.5 56.5t-56.5 23.5h-1241v801h1489v-170h-1241q-33 0 -56.5 -23.5t-23.5 -56.5v-301q0 -33 23.5 -57.5t56.5 -24.5h993q102 0 175 -72t73 -176v-348q0 -102 -73 -175 t-175 -73h-993q-104 0 -176 72.5t-72 175.5z" />
<glyph unicode="6" horiz-adv-x="1679" d="M117 248v979q0 104 71.5 177t176.5 73h983v-170h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-295q0 -33 23.5 -57.5t56.5 -24.5h993q102 0 175 -71.5t73 -176.5v-354q0 -102 -73 -175t-175 -73h-993q-104 0 -176 72.5t-72 175.5zM285 248q0 -33 23.5 -56.5t56.5 -23.5h993 q33 0 56.5 23.5t23.5 56.5v354q0 33 -23.5 56.5t-56.5 23.5h-1073v-434z" />
<glyph unicode="7" horiz-adv-x="1351" d="M6 1307v170h983q102 0 175 -73t73 -177v-1227h-168v1227q0 33 -23.5 56.5t-56.5 23.5h-983z" />
<glyph unicode="8" horiz-adv-x="1708" d="M117 248v348q0 84 61 164q-61 84 -61 166v301q0 104 71.5 177t176.5 73h993q82 0 152.5 -62.5t95.5 -146.5v-342q0 -82 -62 -166q61 -80 62 -164v-348q0 -102 -73 -175t-175 -73h-993q-104 0 -176 72.5t-72 175.5zM285 248q0 -33 23.5 -56.5t56.5 -23.5h993 q33 0 56.5 23.5t23.5 56.5v348q0 33 -23.5 56.5t-56.5 23.5h-993q-33 0 -56.5 -23.5t-23.5 -56.5v-348zM285 901q0 -33 23.5 -56.5t56.5 -23.5h993q33 0 56.5 23.5t23.5 56.5v324q0 33 -23.5 56.5t-56.5 23.5h-993q-33 0 -56.5 -24t-23.5 -56v-324z" />
<glyph unicode="9" d="M104 872v355q0 104 73 177t177 73h994q102 0 174.5 -73t72.5 -177v-979q0 -102 -72.5 -175t-174.5 -73h-994q-80 0 -145.5 47t-89.5 121h1229q33 0 56 23.5t23 56.5v297q0 33 -23 56.5t-56 23.5h-994q-104 0 -177 72.5t-73 174.5zM274 872q0 -33 24 -56t56 -23h1073v434 q0 33 -23.5 56.5t-55.5 23.5h-994q-33 0 -56.5 -23.5t-23.5 -56.5v-355z" />
<glyph unicode=":" horiz-adv-x="438" d="M111 0v168h168v-168h-168zM111 1036v168h168v-168h-168z" />
<glyph unicode=";" horiz-adv-x="395" d="M104 168h168v-201q0 -82 -47 -146.5t-121 -88.5v436zM104 1036v168h168v-168h-168z" />
<glyph unicode="&#x3c;" horiz-adv-x="968" d="M10 508v199l824 473v-195l-656 -379l656 -379v-194z" />
<glyph unicode="=" horiz-adv-x="1306" d="M121 309v168h1059v-168h-1059zM121 719v168h1059v-168h-1059z" />
<glyph unicode="&#x3e;" horiz-adv-x="972" d="M121 29v194l655 379l-655 379v195l823 -474v-198z" />
<glyph unicode="?" horiz-adv-x="1388" d="M63 1303v172l1059 -2q102 0 175 -73t73 -177v-398q0 -102 -72.5 -174.5t-175.5 -72.5h-561q-33 0 -56.5 -24t-23.5 -56v-86h-168v86q0 104 73 175.5t175 71.5h561q33 0 56.5 24t23.5 56v398q0 33 -23.5 56.5t-56.5 23.5h-1059zM313 0v168h168v-168h-168z" />
<glyph unicode="@" horiz-adv-x="1701" d="M117 248v977q0 104 71.5 177t176.5 73h993q102 0 175 -73t73 -177v-832h-842q-104 0 -176 73t-72 177v172q0 102 72 175t176 73h194q102 0 175 -72.5t73 -175.5v-295h232v705q0 33 -23.5 56.5t-56.5 23.5h-993q-33 0 -56.5 -24t-23.5 -56v-977q0 -33 23.5 -56.5 t56.5 -23.5h1241v-168h-1241q-104 0 -176 72.5t-72 175.5zM641 600q0 -33 23.5 -56.5t56.5 -23.5h360v338q0 33 -23.5 56.5t-56.5 23.5h-280q-33 0 -56.5 -23.5t-23.5 -56.5v-258z" />
<glyph unicode="A" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524z" />
<glyph unicode="B" horiz-adv-x="1703" d="M121 0v1475h1165q102 0 174 -72t72 -174v-314q0 -55 -27 -108l8 -35q82 -76 82 -182v-344q0 -102 -71.5 -174t-173.5 -72h-1229zM287 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v344q0 33 -24 56.5t-56 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5 v-344zM287 915q0 -33 23.5 -56t56.5 -23h919q33 0 55.5 23.5t22.5 55.5v314q0 33 -22.5 56.5t-55.5 23.5h-919q-33 0 -56.5 -23.5t-23.5 -56.5v-314z" />
<glyph unicode="C" horiz-adv-x="1683" d="M115 246v983q0 102 71.5 174t173.5 72h1225v-166h-1225q-33 0 -56 -23.5t-23 -56.5v-983q0 -33 23.5 -56.5t55.5 -23.5h1225v-166h-1225q-102 0 -173.5 71.5t-71.5 174.5z" />
<glyph unicode="D" horiz-adv-x="1708" d="M119 0v1475h1229q102 0 173.5 -72t71.5 -174v-983q0 -102 -71.5 -174t-173.5 -72h-1229zM285 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56 23.5t23 56.5v983q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-983z" />
<glyph unicode="E" horiz-adv-x="1568" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-487h1179v-166h-1345z" />
<glyph unicode="F" horiz-adv-x="1480" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-653h-166z" />
<glyph unicode="G" horiz-adv-x="1699" d="M115 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-60h-166v60q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56 -23.5t-23 -56.5v-983q0 -33 23.5 -56.5t55.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v364h-364v168h530v-532q0 -102 -71.5 -174t-174.5 -72h-983 q-102 0 -173.5 71.5t-71.5 174.5z" />
<glyph unicode="H" horiz-adv-x="1742" d="M117 0v1475h166v-654h1177v654h168v-1475h-168v653h-1177v-653h-166z" />
<glyph unicode="I" horiz-adv-x="450" d="M117 0v1475h166v-1475h-166z" />
<glyph unicode="J" horiz-adv-x="1597" d="M8 246v116h166v-116q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -72 -174t-174 -72h-983q-102 0 -174 71.5t-72 174.5z" />
<glyph unicode="K" horiz-adv-x="1632" d="M117 0v1475h168v-654h475l549 654h213l-617 -738l619 -737h-215l-549 653h-475v-653h-168z" />
<glyph unicode="L" horiz-adv-x="1595" d="M117 0v1477h166v-1311h1308v-166h-1474z" />
<glyph unicode="M" horiz-adv-x="1900" d="M115 0v1475h227l612 -730l613 730h227v-1475h-166v1286l-674 -801l-673 801v-1286h-166z" />
<glyph unicode="N" horiz-adv-x="1703" d="M115 0v1475h227l1081 -1287v1287h166v-1475h-227l-1081 1286v-1286h-166z" />
<glyph unicode="O" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983z" />
<glyph unicode="P" horiz-adv-x="1619" d="M115 0v1473h1228q102 0 174 -72t72 -174v-432q0 -102 -71.5 -174t-174.5 -72h-983q-18 0 -79 8v-557h-166zM281 795q0 -33 23.5 -55.5t55.5 -22.5h983q33 0 56.5 22.5t23.5 55.5v432q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56 -23.5t-23 -56.5v-432z" />
<glyph unicode="Q" horiz-adv-x="1810" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -19 -8 -80h201v-166h-1422q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56.5 -23.5 t-23.5 -56.5v-983z" />
<glyph unicode="R" horiz-adv-x="1689" d="M113 0v1473h1228q102 0 174 -72t72 -174v-432q0 -102 -71.5 -174t-174.5 -72h-225l463 -549h-219l-461 549h-541q-18 0 -79 8v-557h-166zM279 795q0 -33 23 -55.5t56 -22.5h983q33 0 55.5 22.5t22.5 55.5v432q0 33 -22.5 56.5t-55.5 23.5h-983q-33 0 -56 -23.5t-23 -56.5 v-432z" />
<glyph unicode="S" horiz-adv-x="1683" d="M104 246v57h166v-57q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v329q0 33 -23.5 55.5t-56.5 22.5h-983q-102 0 -174 72t-72 174v330q0 102 72 174t174 72h983q102 0 174 -72t72 -174v-58h-166v58q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56.5 -23.5 t-23.5 -56.5v-330q0 -33 23.5 -55.5t56.5 -22.5h983q102 0 174 -71.5t72 -174.5v-329q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -174 71.5t-72 174.5z" />
<glyph unicode="T" horiz-adv-x="1554" d="M41 1309v166h1475v-166h-654v-1309h-166v1309h-655z" />
<glyph unicode="U" d="M111 246v1229h165v-1229q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5z" />
<glyph unicode="V" horiz-adv-x="2054" d="M72 1475h194l756 -1313l754 1313h194l-852 -1475h-192z" />
<glyph unicode="W" horiz-adv-x="2414" d="M72 1475h176l432 -1184l430 1184h201l432 -1184l428 1184h180l-536 -1475h-146l-459 1260l-458 -1260h-144z" />
<glyph unicode="X" horiz-adv-x="1662" d="M94 0l619 737l-619 738h213l514 -609l512 609h213l-618 -738l620 -737h-215l-512 608l-514 -608h-213z" />
<glyph unicode="Y" horiz-adv-x="1650" d="M35 1475h190l572 -721l565 721h194l-677 -920v-555h-166v555z" />
<glyph unicode="Z" horiz-adv-x="1681" d="M104 0v227l1287 1082h-1287v166h1475v-228l-1286 -1081h1286v-166h-1475z" />
<glyph unicode="[" horiz-adv-x="563" d="M111 0v1477h307v-170h-139v-1139h139v-168h-307z" />
<glyph unicode="\" horiz-adv-x="1064" d="M10 1272v213l1037 -1266v-217z" />
<glyph unicode="]" horiz-adv-x="565" d="M104 0v168h138v1139h-138v170h308v-1477h-308z" />
<glyph unicode="_" d="M111 0h1491v-168h-1491v168z" />
<glyph unicode="`" horiz-adv-x="436" d="M66 2071h165l70 -285h-164z" />
<glyph unicode="a" horiz-adv-x="1421" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262z" />
<glyph unicode="b" horiz-adv-x="1366" d="M111 0v1577h168v-389h794q102 0 175 -73t73 -175v-692q0 -102 -72.5 -175t-175.5 -73h-962zM279 248q0 -33 24.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -57 -23.5t-24 -56.5v-692z" />
<glyph unicode="c" horiz-adv-x="1423" d="M104 248v692q0 102 73 175t175 73h959v-168h-959q-33 0 -56.5 -23.5t-23.5 -56.5v-692q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode="d" horiz-adv-x="1366" d="M47 248v692q0 102 73 175t177 73h793v389h167v-1577h-960q-104 0 -177 72.5t-73 175.5zM217 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -24 56.5t-56 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-692z" />
<glyph unicode="e" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-430h-1043v-262q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5zM272 678h873v262q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-262z" />
<glyph unicode="f" horiz-adv-x="833" d="M109 0v1329q0 104 71.5 176t175.5 72h435v-168h-435q-33 0 -56.5 -23.5t-23.5 -56.5v-141h515v-168h-515v-1020h-167z" />
<glyph unicode="g" horiz-adv-x="1398" d="M84 248v692q0 102 72.5 175t175.5 73h712q104 0 176 -73t72 -175v-1159q0 -104 -71.5 -177t-176.5 -73h-741v170h741q33 0 56.5 23.5t23.5 56.5v219h-792q-102 0 -175 72.5t-73 175.5zM252 248q0 -33 23.5 -56.5t56.5 -23.5h712q33 0 56.5 23.5t23.5 56.5v692 q0 33 -23.5 56.5t-56.5 23.5h-712q-33 0 -56.5 -23.5t-23.5 -56.5v-692z" />
<glyph unicode="h" horiz-adv-x="1368" d="M111 0v1577h168v-389h794q102 0 175 -73t73 -175v-940h-168v940q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -57 -23.5t-24 -56.5v-940h-168z" />
<glyph unicode="i" horiz-adv-x="425" d="M106 0v1188h168v-1188h-168zM106 1409v168h168v-168h-168z" />
<glyph unicode="j" horiz-adv-x="489" d="M-383 -328h502q33 0 56.5 23.5t23.5 56.5v1436h170v-1436q0 -104 -73 -177t-177 -73h-502v170zM199 1409v168h170v-168h-170z" />
<glyph unicode="k" horiz-adv-x="1323" d="M111 0v1577h168v-899h327l467 510h221l-538 -594l536 -594h-219l-467 510h-327v-510h-168z" />
<glyph unicode="l" horiz-adv-x="618" d="M106 248v1329h168v-1329q0 -33 24 -56.5t56 -23.5h201v-168h-201q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode="m" horiz-adv-x="2002" d="M111 0v1188h1568q104 0 176 -73t72 -175v-940h-166v940q0 33 -24.5 56.5t-57.5 23.5h-493q-33 0 -56.5 -23.5t-23.5 -56.5v-940h-170v940q0 33 -23.5 56.5t-56.5 23.5h-496q-33 0 -56 -23.5t-23 -56.5v-940h-170z" />
<glyph unicode="n" horiz-adv-x="1425" d="M111 0v1188h962q102 0 175 -73t73 -175v-940h-168v940q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -57 -23.5t-24 -56.5v-940h-168z" />
<glyph unicode="o" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692z" />
<glyph unicode="p" horiz-adv-x="1359" d="M111 -471v1659h962q102 0 175 -73t73 -175v-692q0 -102 -72.5 -175t-175.5 -73h-794v-471h-168zM279 248q0 -33 24.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -57 -23.5t-24 -56.5v-692z" />
<glyph unicode="q" horiz-adv-x="1359" d="M41 248v692q0 102 72.5 175t177.5 73h960v-1659h-168v471h-792q-104 0 -177 72.5t-73 175.5zM211 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56 23.5t23 56.5v692q0 33 -23.5 56.5t-55.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-692z" />
<glyph unicode="r" horiz-adv-x="1048" d="M106 0v940q0 102 73 175t175 73h668v-168h-668q-33 0 -56.5 -23.5t-23.5 -56.5v-940h-168z" />
<glyph unicode="s" horiz-adv-x="1404" d="M98 248v16h168v-16q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v182q0 33 -23.5 56.5t-56.5 23.5h-713q-102 0 -175 72.5t-73 175.5v182q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-16h-170v16q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-182q0 -33 23.5 -56.5t56.5 -23.5h713q104 0 177 -73t73 -175v-182q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode="t" horiz-adv-x="839" d="M109 248v1329h167v-389h515v-168h-515v-772q0 -33 24 -56.5t56 -23.5h435v-168h-435q-104 0 -175.5 72.5t-71.5 175.5z" />
<glyph unicode="u" horiz-adv-x="1423" d="M109 248v940h167v-940q0 -33 24 -56.5t56 -23.5h713q33 0 57.5 23.5t24.5 56.5v940h168v-940q0 -102 -72.5 -175t-177.5 -73h-713q-102 0 -174.5 72.5t-72.5 175.5z" />
<glyph unicode="v" horiz-adv-x="1617" d="M43 1188h197l557 -1024l557 1024h196l-657 -1188h-195z" />
<glyph unicode="w" horiz-adv-x="2193" d="M72 1188h180l360 -885l383 885h222l407 -883l336 883h182l-448 -1188h-146l-442 981l-420 -981h-147z" />
<glyph unicode="x" horiz-adv-x="1417" d="M94 0l496 604l-496 584h221l385 -451l387 451h220l-496 -584l498 -604h-222l-387 475l-385 -475h-221z" />
<glyph unicode="y" horiz-adv-x="1402" d="M86 248v936h168v-936q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56 23.5t23 56.5v936h168v-1405q0 -104 -71.5 -177t-175.5 -73h-742v170h742q33 0 56 23.5t23 56.5v221h-792q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode="z" horiz-adv-x="1429" d="M111 0v229l1026 791h-1026v168h1210v-230l-1026 -790h1026v-168h-1210z" />
<glyph unicode="{" horiz-adv-x="591" d="M47 641v197l96 51v336q0 104 73 177t175 73h60v-170h-60q-33 0 -56.5 -24t-23.5 -56v-351l-172 -137l172 -141v-348q0 -33 23.5 -56.5t56.5 -23.5h60v-168h-60q-102 0 -175 72.5t-73 175.5v334q-12 8 -47 29.5t-49 29.5z" />
<glyph unicode="|" horiz-adv-x="438" d="M111 -236v1960h168v-1960h-168z" />
<glyph unicode="}" horiz-adv-x="591" d="M104 0v168h60q33 0 56.5 23.5t23.5 56.5v346l172 141l-172 135v355q0 33 -23.5 56.5t-56.5 23.5h-60v170h60q102 0 175 -73t73 -177v-336q16 -8 51 -29.5t43 -25.5v-195l-94 -59v-332q0 -102 -73 -175t-175 -73h-60z" />
<glyph unicode="~" horiz-adv-x="827" d="M49 631v76q55 18 127 18q82 0 219 -68.5t209 -76.5h4q66 0 135 32v-84q-72 -27 -135 -26q-72 0 -209 72.5t-223 72.5q-80 0 -127 -16z" />
<glyph unicode="&#xa1;" horiz-adv-x="430" d="M109 0v1059h167v-1059h-167zM109 1321v170h167v-170h-167z" />
<glyph unicode="&#xa2;" horiz-adv-x="1302" d="M68 248v713q0 104 71.5 176.5t175.5 72.5h273v277h168v-277h516v-170h-516v-872h516v-168h-516v-236h-168v236h-273q-104 0 -175.5 72.5t-71.5 175.5zM236 248q0 -33 23.5 -56.5t55.5 -23.5h273v872h-273q-33 0 -56 -23.5t-23 -55.5v-713z" />
<glyph unicode="&#xa3;" horiz-adv-x="1503" d="M80 0v168h215v494h-215v167h215v396q0 104 72.5 177t177.5 73h620q104 0 177 -73t73 -177v-31h-170v31q0 33 -23.5 56.5t-56.5 23.5h-620q-33 0 -56.5 -24t-23.5 -56v-396h721v-167h-721v-494h950v-168h-1335z" />
<glyph unicode="&#xa8;" horiz-adv-x="788" d="M111 1786v168h170v-168h-170zM479 1786v168h168v-168h-168z" />
<glyph unicode="&#xad;" horiz-adv-x="1058" d="M121 522v168h799v-168h-799z" />
<glyph unicode="&#xb0;" horiz-adv-x="899" d="M92 1069v172q0 104 73 177t177 73h193q104 0 176.5 -72.5t72.5 -177.5v-172q0 -102 -72.5 -175t-176.5 -73h-193q-104 0 -177 73t-73 175zM217 1026q0 -33 23.5 -56.5t56.5 -23.5h283q33 0 56 23.5t23 56.5v258q0 33 -23.5 56.5t-55.5 23.5h-283q-33 0 -56.5 -23.5 t-23.5 -56.5v-258z" />
<glyph unicode="&#xb4;" horiz-adv-x="436" d="M68 1786l71 285h162l-70 -285h-163z" />
<glyph unicode="&#xb6;" horiz-adv-x="1705" d="M115 803v436q0 104 71.5 177t175.5 73h1242v-1489h-168v555h-283v-555h-168v555h-623q-104 0 -175.5 72.5t-71.5 175.5zM283 803q0 -33 23.5 -56.5t55.5 -23.5h623v596h-623q-33 0 -56 -23.5t-23 -56.5v-436zM1153 723h283v596h-283v-596z" />
<glyph unicode="&#xb8;" horiz-adv-x="436" d="M68 -350l71 284h162l-70 -284h-163z" />
<glyph unicode="&#xbf;" horiz-adv-x="1382" d="M39 248v397q0 104 71.5 177t176.5 73h559q33 0 56.5 23.5t23.5 56.5v98h168v-98q0 -104 -72 -177t-176 -73h-559q-33 0 -56.5 -23.5t-23.5 -56.5v-397q0 -33 23.5 -56.5t56.5 -23.5h1040q0 -59 4 -105.5t8 -62.5l4 -16l-1056 16q-104 0 -176 72.5t-72 175.5zM926 1321 v170h168v-170h-168z" />
<glyph unicode="&#xc0;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM705 2056h165l70 -284h-164z" />
<glyph unicode="&#xc1;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM705 1769l71 285h162l-70 -285h-163z" />
<glyph unicode="&#xc2;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM606 1769l146 240h120l146 -240h-86l-119 175l-123 -175h-84z" />
<glyph unicode="&#xc3;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM496 1911v96q55 18 127 18q82 0 219 -68.5t209 -78.5h4q61 0 135 35v-105 q-78 -29 -135 -28q-72 0 -209 73.5t-223 73.5q-80 0 -127 -16z" />
<glyph unicode="&#xc4;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM571 1751v168h170v-168h-170zM940 1751v168h168v-168h-168z" />
<glyph unicode="&#xc5;" horiz-adv-x="1712" d="M119 0v1229q0 102 72 174t174 72h983q102 0 173.5 -72t71.5 -174v-1229h-166v539h-1142v-539h-166zM285 705h1142v524q0 33 -23.5 56.5t-55.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524zM688 1790v111q0 45 33 76.5t78 31.5h114q45 0 78 -31.5t33 -76.5v-111 q0 -45 -33 -77t-78 -32h-114q-45 0 -78 32t-33 77zM770 1784q0 -21 18 -21h136q18 0 18 21v123q0 20 -18 20h-136q-18 0 -18 -20v-123z" />
<glyph unicode="&#xc6;" horiz-adv-x="2816" d="M111 0v1229q0 102 71.5 174t173.5 72h2409v-166h-1180v-488h948v-168h-948v-487h1180v-166h-1346v539h-1143v-539h-165zM276 705h1143v524q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5v-524z" />
<glyph unicode="&#xc7;" horiz-adv-x="1683" d="M115 246v983q0 102 71.5 174t173.5 72h1225v-166h-1225q-33 0 -56 -23.5t-23 -56.5v-983q0 -33 23.5 -56.5t55.5 -23.5h1225v-166h-661l-70 -285h-164l72 285h-402q-102 0 -173.5 71.5t-71.5 174.5z" />
<glyph unicode="&#xc8;" horiz-adv-x="1568" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-487h1179v-166h-1345zM633 2056h166l69 -284h-163z" />
<glyph unicode="&#xc9;" horiz-adv-x="1568" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-487h1179v-166h-1345zM633 1772l72 284h161l-69 -284h-164z" />
<glyph unicode="&#xca;" horiz-adv-x="1568" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-487h1179v-166h-1345zM535 1769l145 240h121l145 -240h-86l-119 175l-123 -175h-83z" />
<glyph unicode="&#xcb;" horiz-adv-x="1568" d="M119 0v1475h1345v-166h-1179v-488h948v-168h-948v-487h1179v-166h-1345zM500 1772v167h170v-167h-170zM868 1772v167h168v-167h-168z" />
<glyph unicode="&#xcc;" horiz-adv-x="450" d="M74 2056h166l69 -284h-164zM117 0v1475h166v-1475h-166z" />
<glyph unicode="&#xcd;" horiz-adv-x="450" d="M74 1772l71 284h162l-69 -284h-164zM117 0v1475h166v-1475h-166z" />
<glyph unicode="&#xce;" horiz-adv-x="450" d="M-25 1769l146 240h121l145 -240h-86l-119 175l-123 -175h-84zM117 0v1475h166v-1475h-166z" />
<glyph unicode="&#xcf;" horiz-adv-x="450" d="M-59 1772v167h170v-167h-170zM117 0v1475h166v-1475h-166zM309 1772v167h168v-167h-168z" />
<glyph unicode="&#xd1;" horiz-adv-x="1703" d="M115 0v1475h227l1081 -1287v1287h166v-1475h-227l-1081 1286v-1286h-166zM492 1911v96q55 18 126 18q82 0 219.5 -68.5t209.5 -78.5h4q61 0 135 35v-105q-78 -29 -135 -28q-72 0 -209 73.5t-224 73.5q-80 0 -126 -16z" />
<glyph unicode="&#xd2;" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983zM696 2056h166l70 -284h-164z" />
<glyph unicode="&#xd3;" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983zM696 1772l72 284h162l-70 -284h-164z" />
<glyph unicode="&#xd4;" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983zM598 1769l145 240h121l146 -240h-86l-119 175l-123 -175h-84z" />
<glyph unicode="&#xd5;" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983zM487 1911v96q55 18 127 18q82 0 219 -68.5t209 -78.5h5q61 0 135 35v-105q-78 -29 -135 -28q-72 0 -209.5 73.5t-223.5 73.5q-80 0 -127 -16z" />
<glyph unicode="&#xd6;" d="M111 246v983q0 102 71.5 174t173.5 72h983q102 0 174 -72t72 -174v-983q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM276 246q0 -33 23.5 -56.5t56.5 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983 q-33 0 -56.5 -23.5t-23.5 -56.5v-983zM563 1772v167h170v-167h-170zM932 1772v167h168v-167h-168z" />
<glyph unicode="&#xd7;" horiz-adv-x="1118" d="M109 1036h221l215 -295l217 295h217l-324 -420l324 -421h-217l-217 294l-215 -294h-219l323 421z" />
<glyph unicode="&#xd9;" d="M111 246v1229h165v-1229q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM696 2056h166l70 -284h-164z" />
<glyph unicode="&#xda;" d="M111 246v1229h165v-1229q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM696 1772l72 284h162l-70 -284h-164z" />
<glyph unicode="&#xdb;" d="M111 246v1229h165v-1229q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM598 1769l145 240h121l146 -240h-86l-119 175l-123 -175h-84z" />
<glyph unicode="&#xdc;" d="M111 246v1229h165v-1229q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v1229h166v-1229q0 -102 -71.5 -174t-174.5 -72h-983q-102 0 -173.5 71.5t-71.5 174.5zM563 1772v167h170v-167h-170zM932 1772v167h168v-167h-168z" />
<glyph unicode="&#xdd;" horiz-adv-x="1650" d="M35 1475h190l572 -721l565 721h194l-677 -920v-555h-166v555zM674 1772l71 284h162l-69 -284h-164z" />
<glyph unicode="&#xdf;" horiz-adv-x="1705" d="M117 0v1241q0 104 71.5 177t176.5 73h993q82 0 152.5 -62.5t95.5 -146.5v-350q0 -82 -62 -166q61 -80 62 -164v-354q0 -102 -73 -175t-175 -73h-776v168h776q33 0 56.5 23.5t23.5 56.5v354q0 33 -23.5 56.5t-56.5 23.5h-776v145h776q33 0 56.5 23.5t23.5 56.5v332 q0 33 -23.5 56.5t-56.5 23.5h-993q-33 0 -56.5 -23.5t-23.5 -56.5v-1239h-168z" />
<glyph unicode="&#xe0;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM590 1847h166l69 -284h-163z" />
<glyph unicode="&#xe1;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM590 1563l72 284h161l-69 -284h-164z" />
<glyph unicode="&#xe2;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM492 1563l145 239h121l145 -239h-86l-119 174l-123 -174h-83z" />
<glyph unicode="&#xe3;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM381 1700v96q55 18 127 19q82 0 219 -69t209 -79h4q61 0 135 35v-105 q-78 -29 -135 -28q-72 0 -209 73.5t-223 73.5q-80 0 -127 -16z" />
<glyph unicode="&#xe4;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM457 1563v168h170v-168h-170zM825 1563v168h168v-168h-168z" />
<glyph unicode="&#xe5;" horiz-adv-x="1484" d="M106 248v430h1041v262q0 33 -23.5 56.5t-56.5 23.5h-961v168h961q104 0 177 -73t73 -175v-940h-963q-102 0 -175 72.5t-73 175.5zM274 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM573 1579v111q0 45 33 76.5t78 31.5h115q45 0 77.5 -31.5t32.5 -76.5v-111 q0 -45 -32.5 -77t-77.5 -32h-115q-45 0 -78 32t-33 77zM655 1573q1 -21 19 -21h135q18 0 18 21v123q0 20 -18 20h-135q-18 0 -19 -20v-123z" />
<glyph unicode="&#xe6;" horiz-adv-x="2412" d="M109 248v430h1040v262q0 33 -23.5 56.5t-56.5 23.5h-960v168h2000q104 0 176 -73t72 -175v-430h-1040v-270q2 -31 25.5 -51.5t54.5 -20.5h960v-168h-2001q-104 0 -175.5 72.5t-71.5 175.5zM276 248q0 -33 24 -56.5t56 -23.5h793v342h-873v-262zM1317 678h872v262 q0 33 -23.5 56.5t-56.5 23.5h-712q-33 0 -56.5 -23.5t-23.5 -56.5v-262z" />
<glyph unicode="&#xe7;" horiz-adv-x="1419" d="M104 248v692q0 102 73 175t175 73h959v-168h-959q-33 0 -56.5 -23.5t-23.5 -56.5v-692q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-524l-70 -285h-164l72 285h-277q-102 0 -175 72.5t-73 175.5z" />
<glyph unicode="&#xe8;" horiz-adv-x="1306" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-430h-1043v-262q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5zM272 678h873v262q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-262zM502 1847h166l69 -284 h-164z" />
<glyph unicode="&#xe9;" horiz-adv-x="1306" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-430h-1043v-262q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5zM272 678h873v262q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-262zM502 1565l71 284h162 l-69 -284h-164z" />
<glyph unicode="&#xea;" horiz-adv-x="1306" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-430h-1043v-262q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5zM272 678h873v262q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-262zM403 1563l146 239h121 l145 -239h-86l-119 174l-123 -174h-84z" />
<glyph unicode="&#xeb;" horiz-adv-x="1306" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-430h-1043v-262q0 -33 23.5 -56.5t56.5 -23.5h963v-168h-963q-102 0 -175 72.5t-73 175.5zM272 678h873v262q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5t-23.5 -56.5v-262zM369 1563v168h170v-168 h-170zM737 1563v168h168v-168h-168z" />
<glyph unicode="&#xec;" horiz-adv-x="438" d="M33 1849h166l69 -284h-164zM115 0v1188h168v-1188h-168z" />
<glyph unicode="&#xed;" horiz-adv-x="438" d="M100 1563l72 284h162l-70 -284h-164zM104 0v1188h168v-1188h-168z" />
<glyph unicode="&#xee;" horiz-adv-x="438" d="M-31 1563l146 239h121l145 -239h-86l-119 174l-123 -174h-84zM104 0v1188h168v-1188h-168z" />
<glyph unicode="&#xef;" horiz-adv-x="438" d="M-66 1567v168h170v-168h-170zM113 0v1188h168v-1188h-168zM303 1567v168h168v-168h-168z" />
<glyph unicode="&#xf1;" horiz-adv-x="1449" d="M111 0v1188h962q102 0 175 -73t73 -175v-940h-168v940q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -57 -23.5t-24 -56.5v-940h-168zM365 1698v96q55 18 127 18q82 0 219 -68.5t209 -78.5h4q61 0 135 35v-105q-78 -29 -135 -28q-72 0 -209 73.5t-223 73.5q-80 0 -127 -16z " />
<glyph unicode="&#xf2;" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692zM557 1849h166l70 -284h-164z" />
<glyph unicode="&#xf3;" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692zM557 1565l72 284h162l-70 -284h-164z" />
<glyph unicode="&#xf4;" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692zM459 1563l145 239h121l145 -239h-86l-118 174l-123 -174h-84z" />
<glyph unicode="&#xf5;" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692zM348 1698v96q55 18 127 18q82 0 219 -68.5t209 -78.5h4q61 0 135 35v-105q-78 -29 -135 -28q-72 0 -209 73.5t-223 73.5q-80 0 -127 -16z" />
<glyph unicode="&#xf6;" horiz-adv-x="1417" d="M104 248v692q0 102 73 175t175 73h713q104 0 177 -73t73 -175v-692q0 -102 -73 -175t-177 -73h-713q-102 0 -175 72.5t-73 175.5zM272 248q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713q-33 0 -56.5 -23.5 t-23.5 -56.5v-692zM424 1567v168h170v-168h-170zM793 1567v168h168v-168h-168z" />
<glyph unicode="&#xf7;" horiz-adv-x="1040" d="M37 522v168h971v-168h-971zM440 2v168h168v-168h-168zM440 1018v168h168v-168h-168z" />
<glyph unicode="&#xf9;" horiz-adv-x="1423" d="M109 248v940h167v-940q0 -33 24 -56.5t56 -23.5h713q33 0 57.5 23.5t24.5 56.5v940h168v-940q0 -102 -72.5 -175t-177.5 -73h-713q-102 0 -174.5 72.5t-72.5 175.5zM559 1849h166l70 -284h-164z" />
<glyph unicode="&#xfa;" horiz-adv-x="1423" d="M109 248v940h167v-940q0 -33 24 -56.5t56 -23.5h713q33 0 57.5 23.5t24.5 56.5v940h168v-940q0 -102 -72.5 -175t-177.5 -73h-713q-102 0 -174.5 72.5t-72.5 175.5zM559 1565l72 284h162l-70 -284h-164z" />
<glyph unicode="&#xfb;" horiz-adv-x="1423" d="M109 248v940h167v-940q0 -33 24 -56.5t56 -23.5h713q33 0 57.5 23.5t24.5 56.5v940h168v-940q0 -102 -72.5 -175t-177.5 -73h-713q-102 0 -174.5 72.5t-72.5 175.5zM461 1565l145 239h121l145 -239h-86l-118 174l-123 -174h-84z" />
<glyph unicode="&#xfc;" horiz-adv-x="1423" d="M109 248v940h167v-940q0 -33 24 -56.5t56 -23.5h713q33 0 57.5 23.5t24.5 56.5v940h168v-940q0 -102 -72.5 -175t-177.5 -73h-713q-102 0 -174.5 72.5t-72.5 175.5zM426 1563v168h170v-168h-170zM795 1563v168h168v-168h-168z" />
<glyph unicode="&#xfd;" horiz-adv-x="1409" d="M86 248v936h168v-936q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56 23.5t23 56.5v936h168v-1405q0 -104 -71.5 -177t-175.5 -73h-742v170h742q33 0 56 23.5t23 56.5v221h-792q-102 0 -175 72.5t-73 175.5zM553 1565l72 284h161l-69 -284h-164z" />
<glyph unicode="&#xff;" horiz-adv-x="1409" d="M86 248v936h168v-936q0 -33 23.5 -56.5t56.5 -23.5h713q33 0 56 23.5t23 56.5v936h168v-1405q0 -104 -71.5 -177t-175.5 -73h-742v170h742q33 0 56 23.5t23 56.5v221h-792q-102 0 -175 72.5t-73 175.5zM420 1567v168h170v-168h-170zM788 1567v168h168v-168h-168z" />
<glyph unicode="&#x152;" horiz-adv-x="2813" d="M109 246v983q0 102 71.5 174t173.5 72h2409v-166h-1180v-488h948v-168h-948v-487h1180v-166h-2409q-102 0 -173.5 71.5t-71.5 174.5zM274 246q0 -33 24 -56.5t56 -23.5h983q33 0 56.5 23.5t23.5 56.5v983q0 33 -23.5 56.5t-56.5 23.5h-983q-33 0 -56.5 -23.5t-23.5 -56.5 v-983z" />
<glyph unicode="&#x153;" horiz-adv-x="2410" d="M106 248v692q0 102 72 175t176 73h1753q104 0 176 -73t72 -175v-430h-1040v-262q0 -33 23.5 -56.5t56.5 -23.5h960v-168h-2001q-104 0 -176 72.5t-72 175.5zM274 248q0 -33 24 -56.5t56 -23.5h713q33 0 56.5 23.5t23.5 56.5v692q0 33 -23.5 56.5t-56.5 23.5h-713 q-33 0 -56.5 -23.5t-23.5 -56.5v-692zM1315 678h872v262q0 33 -23.5 56.5t-56.5 23.5h-712q-33 0 -56.5 -23.5t-23.5 -56.5v-262z" />
<glyph unicode="&#x178;" horiz-adv-x="1650" d="M35 1475h190l572 -721l565 721h194l-677 -920v-555h-166v555zM541 1772v167h170v-167h-170zM909 1772v167h168v-167h-168z" />
<glyph unicode="&#x2c6;" horiz-adv-x="614" d="M57 1784l146 239h121l145 -239h-86l-119 174l-123 -174h-84z" />
<glyph unicode="&#x2dc;" horiz-adv-x="825" d="M47 1925v96q55 18 127 19q82 0 219 -69t209 -79h4q61 0 135 35v-104q-78 -29 -135 -29q-72 0 -209 74t-223 74q-80 0 -127 -17z" />
<glyph unicode="&#x2000;" horiz-adv-x="1035" />
<glyph unicode="&#x2001;" horiz-adv-x="2071" />
<glyph unicode="&#x2002;" horiz-adv-x="1035" />
<glyph unicode="&#x2003;" horiz-adv-x="2071" />
<glyph unicode="&#x2004;" horiz-adv-x="690" />
<glyph unicode="&#x2005;" horiz-adv-x="517" />
<glyph unicode="&#x2006;" horiz-adv-x="345" />
<glyph unicode="&#x2007;" horiz-adv-x="345" />
<glyph unicode="&#x2008;" horiz-adv-x="258" />
<glyph unicode="&#x2009;" horiz-adv-x="414" />
<glyph unicode="&#x200a;" horiz-adv-x="115" />
<glyph unicode="&#x2010;" horiz-adv-x="1058" d="M121 522v168h799v-168h-799z" />
<glyph unicode="&#x2011;" horiz-adv-x="1058" d="M121 522v168h799v-168h-799z" />
<glyph unicode="&#x2012;" horiz-adv-x="1058" d="M121 522v168h799v-168h-799z" />
<glyph unicode="&#x2013;" horiz-adv-x="1449" d="M111 520v168h1230v-168h-1230z" />
<glyph unicode="&#x2014;" horiz-adv-x="1683" d="M111 520v168h1476v-168h-1476z" />
<glyph unicode="&#x2018;" horiz-adv-x="344" d="M68 1030v201q0 82 47 147.5t123 87.5v-436h-170z" />
<glyph unicode="&#x2019;" horiz-adv-x="339" d="M111 1040v437h168v-201q0 -82 -47.5 -147.5t-120.5 -88.5z" />
<glyph unicode="&#x201c;" horiz-adv-x="743" d="M96 1028v201q0 82 47 147.5t123 87.5v-436h-170zM467 1028v201q0 82 46 147.5t122 87.5v-436h-168z" />
<glyph unicode="&#x201d;" horiz-adv-x="743" d="M111 1040v437h170v-201q0 -82 -47.5 -147.5t-122.5 -88.5zM481 1040v437h168v-201q0 -82 -47 -147.5t-121 -88.5z" />
<glyph unicode="&#x2022;" horiz-adv-x="759" d="M295 723v43q0 59 57 59h51q59 0 60 -59v-43q0 -57 -60 -57h-51q-57 0 -57 57z" />
<glyph unicode="&#x2026;" horiz-adv-x="1175" d="M111 0v168h168v-168h-168zM498 0v168h168v-168h-168zM883 0v168h170v-168h-170z" />
<glyph unicode="&#x202f;" horiz-adv-x="414" />
<glyph unicode="&#x205f;" horiz-adv-x="517" />
<glyph unicode="&#x20ac;" horiz-adv-x="1636" d="M72 471v168h215v211h-215v170h215v207q0 104 72.5 177t177.5 73h1022v-170h-1022q-33 0 -56.5 -23.5t-23.5 -56.5v-207h868v-170h-868v-211h868v-168h-868v-223q0 -33 23.5 -56.5t56.5 -23.5h1022v-168h-1022q-104 0 -177 72.5t-73 175.5v223h-215z" />
<glyph unicode="&#x25fc;" horiz-adv-x="1187" d="M0 0v1188h1188v-1188h-1188z" />
<hkern u1="&#x3f;" u2="v" k="2" />
<hkern u1="A" u2="Y" k="27" />
<hkern u1="A" u2="W" k="63" />
<hkern u1="B" u2="Y" k="63" />
<hkern u1="B" u2="V" k="100" />
<hkern u1="D" u2="Z" k="55" />
<hkern u1="D" u2="V" k="59" />
<hkern u1="E" u2="O" k="63" />
<hkern u1="E" u2="M" k="59" />
<hkern u1="F" u2="y" k="41" />
<hkern u1="F" u2="T" k="-20" />
<hkern u1="F" u2="R" k="-10" />
<hkern u1="F" u2="J" k="492" />
<hkern u1="G" u2="W" k="55" />
<hkern u1="K" u2="H" k="59" />
<hkern u1="K" u2="A" k="61" />
<hkern u1="L" u2="Y" k="367" />
<hkern u1="L" u2="W" k="264" />
<hkern u1="L" u2="V" k="473" />
<hkern u1="M" u2="c" k="20" />
<hkern u1="O" u2="X" k="80" />
<hkern u1="O" u2="W" k="55" />
<hkern u1="O" u2="V" k="55" />
<hkern u1="P" u2="v" k="-2" />
<hkern u1="P" u2="d" k="-20" />
<hkern u1="P" u2="J" k="383" />
<hkern u1="P" u2="A" k="-20" />
<hkern u1="R" u2="W" k="39" />
<hkern u1="R" u2="V" k="39" />
<hkern u1="S" u2="Y" k="20" />
<hkern u1="S" u2="W" k="51" />
<hkern u1="S" u2="N" k="39" />
<hkern u1="T" u2="z" k="211" />
<hkern u1="T" u2="y" k="186" />
<hkern u1="T" u2="w" k="170" />
<hkern u1="T" u2="u" k="207" />
<hkern u1="T" u2="s" k="248" />
<hkern u1="T" u2="o" k="252" />
<hkern u1="V" u2="s" k="82" />
<hkern u1="V" u2="o" k="61" />
<hkern u1="V" u2="S" k="41" />
<hkern u1="V" u2="O" k="68" />
<hkern u1="V" u2="A" k="76" />
<hkern u1="W" u2="u" k="41" />
<hkern u1="W" u2="o" k="51" />
<hkern u1="W" u2="i" k="20" />
<hkern u1="W" u2="e" k="72" />
<hkern u1="W" u2="a" k="31" />
<hkern u1="W" u2="O" k="47" />
<hkern u1="W" u2="A" k="55" />
<hkern u1="X" u2="B" k="72" />
<hkern u1="Y" u2="u" k="199" />
<hkern u1="Y" u2="s" k="240" />
<hkern u1="Y" u2="p" k="203" />
<hkern u1="Y" u2="o" k="244" />
<hkern u1="Y" u2="i" k="39" />
<hkern u1="Y" u2="e" k="244" />
<hkern u1="Y" u2="a" k="199" />
<hkern u1="Y" u2="S" k="72" />
<hkern u1="Z" u2="Y" k="20" />
<hkern u1="a" u2="z" k="51" />
<hkern u1="a" u2="x" k="31" />
<hkern u1="a" u2="w" k="61" />
<hkern u1="a" u2="v" k="41" />
<hkern u1="a" u2="s" k="41" />
<hkern u1="a" u2="r" k="10" />
<hkern u1="a" u2="n" k="31" />
<hkern u1="a" u2="m" k="41" />
<hkern u1="a" u2="l" k="20" />
<hkern u1="a" u2="c" k="20" />
<hkern u1="a" u2="b" k="51" />
<hkern u1="b" u2="d" k="-61" />
<hkern u1="c" u2="z" k="41" />
<hkern u1="c" u2="u" k="41" />
<hkern u1="c" u2="t" k="51" />
<hkern u1="c" u2="k" k="41" />
<hkern u1="c" u2="h" k="31" />
<hkern u1="c" u2="e" k="51" />
<hkern u1="d" u2="u" k="47" />
<hkern u1="d" u2="o" k="45" />
<hkern u1="d" u2="e" k="41" />
<hkern u1="e" u2="x" k="35" />
<hkern u1="e" u2="w" k="61" />
<hkern u1="e" u2="v" k="41" />
<hkern u1="e" u2="r" k="10" />
<hkern u1="e" u2="l" k="41" />
<hkern u1="e" u2="e" k="31" />
<hkern u1="e" u2="c" k="41" />
<hkern u1="f" u2="u" k="-20" />
<hkern u1="f" u2="t" k="-10" />
<hkern u1="f" u2="&#x2c;" k="371" />
<hkern u1="g" u2="w" k="41" />
<hkern u1="g" u2="u" k="51" />
<hkern u1="g" u2="s" k="43" />
<hkern u1="g" u2="r" k="31" />
<hkern u1="g" u2="o" k="41" />
<hkern u1="g" u2="e" k="31" />
<hkern u1="g" u2="c" k="31" />
<hkern u1="g" u2="a" k="31" />
<hkern u1="h" u2="i" k="-10" />
<hkern u1="h" u2="f" k="-20" />
<hkern u1="h" u2="a" k="-10" />
<hkern u1="i" u2="x" k="84" />
<hkern u1="i" u2="v" k="10" />
<hkern u1="i" u2="q" k="31" />
<hkern u1="i" u2="p" k="51" />
<hkern u1="i" u2="n" k="31" />
<hkern u1="i" u2="f" k="96" />
<hkern u1="i" u2="c" k="31" />
<hkern u1="i" u2="a" k="72" />
<hkern u1="j" u2="e" k="41" />
<hkern u1="k" u2="e" k="10" />
<hkern u1="l" u2="&#x2019;" k="178" />
<hkern u1="l" u2="w" k="133" />
<hkern u1="l" u2="v" k="121" />
<hkern u1="l" u2="o" k="20" />
<hkern u1="l" u2="m" k="20" />
<hkern u1="l" u2="e" k="31" />
<hkern u1="l" u2="d" k="-10" />
<hkern u1="l" u2="a" k="20" />
<hkern u1="m" u2="w" k="51" />
<hkern u1="m" u2="m" k="27" />
<hkern u1="m" u2="k" k="27" />
<hkern u1="n" u2="x" k="51" />
<hkern u1="n" u2="p" k="20" />
<hkern u1="n" u2="o" k="31" />
<hkern u1="n" u2="c" k="41" />
<hkern u1="n" u2="b" k="41" />
<hkern u1="o" u2="x" k="72" />
<hkern u1="o" u2="w" k="72" />
<hkern u1="o" u2="v" k="27" />
<hkern u1="o" u2="u" k="47" />
<hkern u1="o" u2="t" k="47" />
<hkern u1="o" u2="s" k="41" />
<hkern u1="o" u2="r" k="20" />
<hkern u1="o" u2="o" k="41" />
<hkern u1="o" u2="n" k="31" />
<hkern u1="o" u2="l" k="41" />
<hkern u1="o" u2="a" k="20" />
<hkern u1="p" u2="s" k="-20" />
<hkern u1="p" u2="i" k="-31" />
<hkern u1="p" u2="d" k="-51" />
<hkern u1="q" u2="u" k="51" />
<hkern u1="r" u2="o" k="10" />
<hkern u1="r" u2="&#x2e;" k="41" />
<hkern u1="r" u2="&#x2c;" k="498" />
<hkern u1="s" u2="z" k="47" />
<hkern u1="s" u2="x" k="76" />
<hkern u1="s" u2="v" k="41" />
<hkern u1="s" u2="u" k="41" />
<hkern u1="s" u2="n" k="47" />
<hkern u1="s" u2="k" k="31" />
<hkern u1="s" u2="e" k="31" />
<hkern u1="s" u2="c" k="39" />
<hkern u1="t" u2="z" k="-10" />
<hkern u1="t" u2="i" k="-10" />
<hkern u1="t" u2="h" k="-10" />
<hkern u1="t" u2="d" k="-41" />
<hkern u1="t" u2="b" k="-10" />
<hkern u1="u" u2="z" k="31" />
<hkern u1="u" u2="x" k="31" />
<hkern u1="u" u2="t" k="31" />
<hkern u1="u" u2="s" k="31" />
<hkern u1="u" u2="p" k="31" />
<hkern u1="u" u2="n" k="-10" />
<hkern u1="u" u2="m" k="41" />
<hkern u1="u" u2="f" k="20" />
<hkern u1="u" u2="e" k="31" />
<hkern u1="u" u2="d" k="-20" />
<hkern u1="u" u2="c" k="41" />
<hkern u1="u" u2="b" k="31" />
<hkern u1="v" u2="s" k="51" />
<hkern u1="v" u2="o" k="59" />
<hkern u1="v" u2="e" k="61" />
<hkern u1="w" u2="s" k="31" />
<hkern u1="w" u2="r" k="41" />
<hkern u1="w" u2="o" k="41" />
<hkern u1="w" u2="e" k="41" />
<hkern u1="x" u2="e" k="100" />
<hkern u1="y" u2="o" k="47" />
<hkern u1="y" u2="n" k="31" />
<hkern u1="y" u2="l" k="-20" />
<hkern u1="y" u2="e" k="41" />
<hkern u1="y" u2="c" k="41" />
<hkern u1="y" u2="a" k="47" />
<hkern u1="z" u2="z" k="41" />
<hkern u1="z" u2="t" k="41" />
<hkern u1="z" u2="l" k="41" />
<hkern u1="z" u2="e" k="51" />
<hkern u1="z" u2="a" k="51" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M4 10v20c0 1.1 0.9 2 2 2h18c1.1 0 2-0.9 2-2v-20h-22zM10 28h-2v-14h2v14zM14 28h-2v-14h2v14zM18 28h-2v-14h2v14zM22 28h-2v-14h2v14z"></path>
<path d="M26.5 4h-6.5v-2.5c0-0.825-0.675-1.5-1.5-1.5h-7c-0.825 0-1.5 0.675-1.5 1.5v2.5h-6.5c-0.825 0-1.5 0.675-1.5 1.5v2.5h26v-2.5c0-0.825-0.675-1.5-1.5-1.5zM18 4h-6v-1.975h6v1.975z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 657 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M11.366 22.564l1.291-1.807-1.414-1.414-1.807 1.291c-0.335-0.187-0.694-0.337-1.071-0.444l-0.365-2.19h-2l-0.365 2.19c-0.377 0.107-0.736 0.256-1.071 0.444l-1.807-1.291-1.414 1.414 1.291 1.807c-0.187 0.335-0.337 0.694-0.443 1.071l-2.19 0.365v2l2.19 0.365c0.107 0.377 0.256 0.736 0.444 1.071l-1.291 1.807 1.414 1.414 1.807-1.291c0.335 0.187 0.694 0.337 1.071 0.444l0.365 2.19h2l0.365-2.19c0.377-0.107 0.736-0.256 1.071-0.444l1.807 1.291 1.414-1.414-1.291-1.807c0.187-0.335 0.337-0.694 0.444-1.071l2.19-0.365v-2l-2.19-0.365c-0.107-0.377-0.256-0.736-0.444-1.071zM7 27c-1.105 0-2-0.895-2-2s0.895-2 2-2 2 0.895 2 2-0.895 2-2 2zM32 12v-2l-2.106-0.383c-0.039-0.251-0.088-0.499-0.148-0.743l1.799-1.159-0.765-1.848-2.092 0.452c-0.132-0.216-0.273-0.426-0.422-0.629l1.219-1.761-1.414-1.414-1.761 1.219c-0.203-0.149-0.413-0.29-0.629-0.422l0.452-2.092-1.848-0.765-1.159 1.799c-0.244-0.059-0.492-0.109-0.743-0.148l-0.383-2.106h-2l-0.383 2.106c-0.251 0.039-0.499 0.088-0.743 0.148l-1.159-1.799-1.848 0.765 0.452 2.092c-0.216 0.132-0.426 0.273-0.629 0.422l-1.761-1.219-1.414 1.414 1.219 1.761c-0.149 0.203-0.29 0.413-0.422 0.629l-2.092-0.452-0.765 1.848 1.799 1.159c-0.059 0.244-0.109 0.492-0.148 0.743l-2.106 0.383v2l2.106 0.383c0.039 0.251 0.088 0.499 0.148 0.743l-1.799 1.159 0.765 1.848 2.092-0.452c0.132 0.216 0.273 0.426 0.422 0.629l-1.219 1.761 1.414 1.414 1.761-1.219c0.203 0.149 0.413 0.29 0.629 0.422l-0.452 2.092 1.848 0.765 1.159-1.799c0.244 0.059 0.492 0.109 0.743 0.148l0.383 2.106h2l0.383-2.106c0.251-0.039 0.499-0.088 0.743-0.148l1.159 1.799 1.848-0.765-0.452-2.092c0.216-0.132 0.426-0.273 0.629-0.422l1.761 1.219 1.414-1.414-1.219-1.761c0.149-0.203 0.29-0.413 0.422-0.629l2.092 0.452 0.765-1.848-1.799-1.159c0.059-0.244 0.109-0.492 0.148-0.743l2.106-0.383zM21 15.35c-2.402 0-4.35-1.948-4.35-4.35s1.948-4.35 4.35-4.35 4.35 1.948 4.35 4.35c0 2.402-1.948 4.35-4.35 4.35z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,8 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(1,1)">
<path stroke="#ff3b00" transform="rotate(45 15 15)" d="m4,4 l 11,-4 l 11,4 l 4,11 l -4,11 l -11,4 l -11,-4 l -4,-11 l 4,-11 l 22,0 l 0,22 l -22,0 z" stroke-width="1" fill="#000000"/>
<rect height="3" width="10" y="13.5" x="10" stroke-width="1" stroke="#ff3b00" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 404 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 18l8-8h-6v-8h-4v8h-6zM23.273 14.727l-2.242 2.242 8.128 3.031-13.158 4.907-13.158-4.907 8.127-3.031-2.242-2.242-8.727 3.273v8l16 6 16-6v-8z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 480 B

View File

@@ -1,28 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" height="400" viewBox="0 0 90 32">
<g>
<path d="M19.1,25.2c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6v3.3c0,0.3-0.1,0.6-0.2,0.7
c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1H3.6c-0.3,0-0.6-0.1-0.7-0.2c-0.2-0.1-0.3-0.3-0.3-0.4
c-0.1-0.2-0.2-0.4-0.1-0.6V10.2c0-0.3,0.1-0.5,0.2-0.7C2.7,9.4,2.9,9.3,3,9.2C3.2,9.1,3.4,9,3.6,9h15.5c0.3,0,0.6,0.1,0.7,0.2
c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6V22c0,0.3-0.1,0.6-0.2,0.7c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1
h-6.8v-6.8c0.3-0.2,0.6-0.4,0.8-0.7c0.2-0.3,0.3-0.7,0.3-1c0-0.6-0.2-1.1-0.6-1.4c-0.4-0.4-0.9-0.6-1.4-0.6c-0.5,0-1,0.2-1.4,0.6
c-0.4,0.4-0.6,0.9-0.6,1.4c0,0.8,0.3,1.4,1,1.8v8.7H19.1z"/>
<path d="M24.6,29.7V10.2c0-0.2,0-0.4,0.1-0.6c0.1-0.1,0.2-0.3,0.3-0.4C25.3,9.1,25.5,9,25.8,9h5.5c0.2,0,0.4,0.1,0.6,0.2
c0.1,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.4,0.2,0.7v13.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4c0.4,0.4,0.9,0.6,1.4,0.6
c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V2.3c0-0.2,0-0.4,0.1-0.6
c0.1-0.1,0.2-0.3,0.3-0.4C35.2,1.1,35.4,1,35.8,1h5.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.7v27.4
c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.1-0.2,0.3-0.4,0.4c-0.2,0.1-0.4,0.2-0.7,0.2H25.8c-0.2,0-0.4,0-0.6-0.1c-0.1-0.1-0.3-0.2-0.4-0.3
C24.7,30.3,24.6,30,24.6,29.7z"/>
<path d="M46.9,29.7V10.2c0-0.2,0-0.4,0.1-0.6c0.1-0.1,0.2-0.3,0.3-0.4C47.5,9.1,47.7,9,48.1,9h5.5c0.2,0,0.4,0.1,0.6,0.2
c0.1,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.4,0.2,0.7v13.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4c0.4,0.4,0.9,0.6,1.4,0.6
c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V2.3c0-0.2,0-0.4,0.1-0.6
c0.1-0.1,0.2-0.3,0.3-0.4C57.4,1.1,57.7,1,58,1h5.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.7v27.4
c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.1-0.2,0.3-0.4,0.4s-0.4,0.2-0.7,0.2H48.1c-0.2,0-0.4,0-0.6-0.1c-0.1-0.1-0.3-0.2-0.4-0.3
C46.9,30.3,46.9,30,46.9,29.7z"/>
<path d="M87,29.7c0,0.3-0.1,0.6-0.2,0.7c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1H70.3c-0.3,0-0.6-0.1-0.7-0.2
s-0.3-0.3-0.3-0.4c-0.1-0.2-0.2-0.4-0.1-0.6V2.3c0-0.3,0.1-0.6,0.2-0.7c0.1-0.2,0.3-0.3,0.4-0.4C69.9,1.1,70.1,1,70.3,1h5.5
c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6v21.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4
c0.4,0.4,0.8,0.6,1.4,0.6c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V10.2
c0-0.3,0.1-0.5,0.2-0.7c0.1-0.1,0.3-0.3,0.4-0.3C79.8,9.1,80,9,80.2,9h5.5c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4
C87,9.8,87,10,87,10.2V29.7z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,4 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M18 23l3 3 10-10-10-10-3 3 7 7z"></path>
<path d="M14 9l-3-3-10 10 10 10 3-3-7-7z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 248 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
<path d="M448 128v-16c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-192v128h192v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h576v-128h-576zM256 256v-128h128v128h-128zM832 432c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-576v128h576v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h192v-128h-192v-16zM640 576v-128h128v128h-128zM448 752c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-192v128h192v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h576v-128h-576v-16zM256 896v-128h128v128h-128z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 646 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M28 0h-28v32h32v-28l-4-4zM16 4h4v8h-4v-8zM28 28h-24v-24h2v10h18v-10h2.343l1.657 1.657v22.343z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 260 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM9.464 26.067c0.347-0.957 0.536-1.99 0.536-3.067 0-3.886-2.463-7.197-5.913-8.456 0.319-2.654 1.508-5.109 3.427-7.029 2.267-2.266 5.28-3.515 8.485-3.515s6.219 1.248 8.485 3.515c1.92 1.92 3.108 4.375 3.428 7.029-3.45 1.26-5.913 4.57-5.913 8.456 0 1.077 0.189 2.11 0.536 3.067-1.928 1.258-4.18 1.933-6.536 1.933s-4.608-0.675-6.536-1.933zM17.242 20.031c0.434 0.109 0.758 0.503 0.758 0.969v2c0 0.55-0.45 1-1 1h-2c-0.55 0-1-0.45-1-1v-2c0-0.466 0.324-0.86 0.758-0.969l0.742-14.031h1l0.742 14.031z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 688 B

View File

@@ -1,3 +0,0 @@
<svg height="1024" width="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 0C229.252 0 0 229.25199999999995 0 512c0 226.251 146.688 418.126 350.155 485.813 25.593 4.686 34.937-11.125 34.937-24.626 0-12.188-0.469-52.562-0.718-95.314-128.708 23.46-161.707-31.541-172.469-60.373-5.525-14.809-30.407-60.249-52.398-72.263-17.988-9.828-43.26-33.237-0.917-33.735 40.434-0.476 69.348 37.308 78.471 52.75 45.938 77.749 119.876 55.627 148.999 42.5 4.654-32.999 17.902-55.627 32.501-68.373-113.657-12.939-233.22-56.875-233.22-253.063 0-55.94 19.968-101.561 52.658-137.404-5.22-12.999-22.844-65.095 5.063-135.563 0 0 42.937-13.749 140.811 52.501 40.811-11.406 84.594-17.031 128.124-17.22 43.499 0.188 87.314 5.874 128.188 17.28 97.689-66.311 140.686-52.501 140.686-52.501 28 70.532 10.375 122.564 5.124 135.499 32.811 35.844 52.626 81.468 52.626 137.404 0 196.686-119.751 240-233.813 252.686 18.439 15.876 34.748 47.001 34.748 94.748 0 68.437-0.686 123.627-0.686 140.501 0 13.625 9.312 29.561 35.25 24.562C877.436 929.998 1024 738.126 1024 512 1024 229.25199999999995 794.748 0 512 0z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M31.562 25.905l-9.423-9.423c-0.583-0.583-1.538-0.583-2.121 0l-0.707 0.707-5.75-5.75 9.439-9.439h-10l-4.439 4.439-0.439-0.439h-2.121v2.121l0.439 0.439-6.439 6.439 5 5 6.439-6.439 5.75 5.75-0.707 0.707c-0.583 0.583-0.583 1.538 0 2.121l9.423 9.423c0.583 0.583 1.538 0.583 2.121 0l3.535-3.535c0.583-0.583 0.583-1.538 0-2.121z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 659 B

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M24.5 23.5c-2.003 0-3.887-0.78-5.303-2.197l-3.197-3.196-3.196 3.196c-1.417 1.417-3.3 2.197-5.303 2.197s-3.887-0.78-5.304-2.197c-1.417-1.417-2.197-3.3-2.197-5.303s0.78-3.887 2.197-5.304c1.417-1.417 3.3-2.197 5.304-2.197s3.887 0.78 5.303 2.197l3.196 3.196 3.196-3.196c1.417-1.417 3.3-2.197 5.303-2.197s3.887 0.78 5.303 2.197c1.417 1.417 2.197 3.3 2.197 5.304s-0.78 3.887-2.197 5.303c-1.416 1.417-3.3 2.197-5.303 2.197zM21.304 19.197c0.854 0.853 1.989 1.324 3.196 1.323s2.342-0.47 3.196-1.324c0.854-0.854 1.324-1.989 1.324-3.196s-0.47-2.342-1.324-3.196c-0.854-0.854-1.989-1.324-3.196-1.324s-2.342 0.47-3.196 1.324l-3.196 3.196 3.196 3.197zM7.5 11.48c-1.207 0-2.342 0.47-3.196 1.324s-1.324 1.989-1.324 3.196c0 1.207 0.47 2.342 1.324 3.196s1.989 1.324 3.196 1.324c1.207 0 2.342-0.47 3.196-1.324l3.196-3.196-3.196-3.196c-0.854-0.854-1.989-1.324-3.196-1.324v0z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M14 9.5c0-0.825 0.675-1.5 1.5-1.5h1c0.825 0 1.5 0.675 1.5 1.5v1c0 0.825-0.675 1.5-1.5 1.5h-1c-0.825 0-1.5-0.675-1.5-1.5v-1z"></path>
<path d="M20 24h-8v-2h2v-6h-2v-2h6v8h2z"></path>
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 675 B

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M13.757 19.868c-0.416 0-0.832-0.159-1.149-0.476-2.973-2.973-2.973-7.81 0-10.783l6-6c1.44-1.44 3.355-2.233 5.392-2.233s3.951 0.793 5.392 2.233c2.973 2.973 2.973 7.81 0 10.783l-2.743 2.743c-0.635 0.635-1.663 0.635-2.298 0s-0.635-1.663 0-2.298l2.743-2.743c1.706-1.706 1.706-4.481 0-6.187-0.826-0.826-1.925-1.281-3.094-1.281s-2.267 0.455-3.094 1.281l-6 6c-1.706 1.706-1.706 4.481 0 6.187 0.635 0.635 0.635 1.663 0 2.298-0.317 0.317-0.733 0.476-1.149 0.476z"></path>
<path d="M8 31.625c-2.037 0-3.952-0.793-5.392-2.233-2.973-2.973-2.973-7.81 0-10.783l2.743-2.743c0.635-0.635 1.664-0.635 2.298 0s0.635 1.663 0 2.298l-2.743 2.743c-1.706 1.706-1.706 4.481 0 6.187 0.826 0.826 1.925 1.281 3.094 1.281s2.267-0.455 3.094-1.281l6-6c1.706-1.706 1.706-4.481 0-6.187-0.635-0.635-0.635-1.663 0-2.298s1.663-0.635 2.298 0c2.973 2.973 2.973 7.81 0 10.783l-6 6c-1.44 1.44-3.355 2.233-5.392 2.233z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,7 +0,0 @@
<svg width="201" height="201" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<circle fill-opacity="0" r="70" cy="100" cx="100" stroke-width="5" />
<line y2="60" x2="101" y1="0" x1="101" stroke-width="5" />
<line y2="101" x2="200" y1="101" x1="140" stroke-width="5" />
<line y2="101" x2="60" y1="101" x1="0" stroke-width="5" />
<line y2="200" x2="101" y1="140" x1="101" stroke-width="5" />
</svg>

Before

Width:  |  Height:  |  Size: 417 B

View File

@@ -1,4 +0,0 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<ellipse ry="25" rx="95" cy="100" cx="100" fill-opacity="0" stroke-width="5" />
<ellipse ry="95" rx="25" cy="100" cx="100" fill-opacity="0" stroke-width="5" />
</svg>

Before

Width:  |  Height:  |  Size: 258 B

View File

@@ -1,5 +0,0 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<line y2="170" x2="162" y1="170" x1="8" stroke-width="6" />
<path d="m13,138l144,0l0,-50l-27,-40l-90,0l-27,40l0,50z" id="svg_12" fill-opacity="0" stroke-width="6" />
<line y2="91" x2="200" y1="91" x1="159" stroke-width="6" />
</svg>

Before

Width:  |  Height:  |  Size: 326 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<path d="M437.020 74.98c-48.353-48.351-112.64-74.98-181.020-74.98s-132.667 26.629-181.020 74.98c-48.351 48.353-74.98 112.64-74.98 181.020s26.629 132.667 74.98 181.020c48.353 48.351 112.64 74.98 181.020 74.98s132.667-26.629 181.020-74.98c48.351-48.353 74.98-112.64 74.98-181.020s-26.629-132.667-74.98-181.020zM448 256c0 41.407-13.177 79.794-35.556 111.19l-267.633-267.634c31.396-22.379 69.782-35.556 111.189-35.556 105.869 0 192 86.131 192 192zM64 256c0-41.407 13.177-79.793 35.556-111.189l267.635 267.634c-31.397 22.378-69.784 35.555-111.191 35.555-105.869 0-192-86.131-192-192z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 697 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 3c-3.472 0-6.737 1.352-9.192 3.808s-3.808 5.72-3.808 9.192c0 3.472 1.352 6.737 3.808 9.192s5.72 3.808 9.192 3.808c3.472 0 6.737-1.352 9.192-3.808s3.808-5.72 3.808-9.192c0-3.472-1.352-6.737-3.808-9.192s-5.72-3.808-9.192-3.808zM16 0v0c8.837 0 16 7.163 16 16s-7.163 16-16 16c-8.837 0-16-7.163-16-16s7.163-16 16-16zM14 22h4v4h-4zM14 6h4v12h-4z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 681 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<path d="M192 0l-192 256h192l-128 256 448-320h-256l192-192z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 178 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M14 22h4v4h-4zM22 8c1.105 0 2 0.895 2 2v6l-6 4h-4v-2l6-4v-2h-10v-4h12zM16 3c-3.472 0-6.737 1.352-9.192 3.808s-3.808 5.72-3.808 9.192c0 3.472 1.352 6.737 3.808 9.192s5.72 3.808 9.192 3.808c3.472 0 6.737-1.352 9.192-3.808s3.808-5.72 3.808-9.192c0-3.472-1.352-6.737-3.808-9.192s-5.72-3.808-9.192-3.808zM16 0v0c8.837 0 16 7.163 16 16s-7.163 16-16 16c-8.837 0-16-7.163-16-16s7.163-16 16-16z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 723 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M22 2l-10 10h-6l-6 8c0 0 6.357-1.77 10.065-0.94l-10.065 12.94 13.184-10.255c1.839 4.208-1.184 10.255-1.184 10.255l8-6v-6l10-10 2-10-10 2z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 475 B

View File

@@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<path d="M32 12h-12l4.485-4.485c-2.267-2.266-5.28-3.515-8.485-3.515s-6.219 1.248-8.485 3.515c-2.266 2.267-3.515 5.28-3.515 8.485s1.248 6.219 3.515 8.485c2.267 2.266 5.28 3.515 8.485 3.515s6.219-1.248 8.485-3.515c0.189-0.189 0.371-0.384 0.546-0.583l3.010 2.634c-2.933 3.349-7.239 5.464-12.041 5.464-8.837 0-16-7.163-16-16s7.163-16 16-16c4.418 0 8.418 1.791 11.313 4.687l4.687-4.687v12z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 499 B

View File

@@ -1,6 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<rect x="73.001" y="94.017" width="53.997" height="11.945"/>
<path d="M10.324,185.445l89.217,14.348l0.458,0.077l89.677-14.43L200,99.998l-10.338-89.765L100,0.129L10.34,10.233 L-0.001,99.986L10.324,185.445z M193.206,99.986L100,191.108L6.795,99.986L100,8.868L193.206,99.986z M6.82,107.775l87.583,85.624 l-78.983-12.702L6.82,107.775z M184.583,180.692l-78.992,12.712l87.587-85.634L184.583,180.692z M193.745,92.746L105.26,6.245 l79.339,8.938L193.745,92.746z M15.41,15.185L94.736,6.25L6.255,92.751L15.41,15.185z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 642 B

View File

@@ -1,7 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M100.002,200C155.139,200,200,155.142,200,100.001c0-55.143-44.861-100.002-99.998-100.002 C44.86-0.001-0.002,44.857-0.002,100.001C-0.001,155.142,44.86,200,100.002,200z M100.002,5.574 c52.063,0,94.423,42.359,94.423,94.427c0,52.067-42.361,94.422-94.423,94.422c-52.07,0-94.428-42.358-94.428-94.422 C5.574,47.933,47.933,5.574,100.002,5.574z"/>
<path d="M100.002,148.557c26.771,0,48.558-21.783,48.558-48.555c0-26.771-21.786-48.556-48.558-48.556 c-26.777,0-48.557,21.782-48.557,48.556C51.446,126.778,73.225,148.557,100.002,148.557z M100.002,57.015 c23.699,0,42.986,19.283,42.986,42.986c0,23.7-19.282,42.987-42.986,42.987c-23.705,0-42.991-19.282-42.991-42.987 C57.011,76.298,76.302,57.015,100.002,57.015z"/>
<rect x="73.404" y="93.985" width="53.197" height="12.033"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 912 B

View File

@@ -1,6 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M100.002,200c55.138,0,99.996-44.861,99.996-100c0-55.141-44.858-100-99.996-100 C44.861,0-0.001,44.857-0.001,100C0,155.139,44.861,200,100.002,200z M100.002,194.424c-35.465,0-66.413-19.663-82.552-48.651 l44.426-23.388c7.704,13.067,21.888,21.884,38.127,21.884c16.054,0,30.096-8.621,37.853-21.446l44.441,23.389 C166.092,174.961,135.282,194.424,100.002,194.424z M100.002,61.306c21.335,0,38.691,17.356,38.691,38.694 c0,21.338-17.364,38.691-38.691,38.691c-21.339,0-38.696-17.354-38.696-38.691C61.307,78.662,78.663,61.306,100.002,61.306z M194.422,100c0,14.802-3.427,28.808-9.521,41.287l-44.447-23.4c2.433-5.477,3.812-11.521,3.812-17.89 c0-23.578-18.539-42.852-41.8-44.145V5.636C153.392,6.956,194.422,48.762,194.422,100z M96.895,5.655v50.233 C73.938,57.491,55.73,76.635,55.73,100c0,6.187,1.286,12.081,3.592,17.434l-44.455,23.402C8.911,128.472,5.571,114.619,5.571,100 C5.577,48.972,46.261,7.297,96.895,5.655z"/>
<rect x="73.403" y="93.983" width="53.196" height="12.032"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,7 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M145.137,59.126h4.498v6.995h5.576V46.556h-5.576v6.994h-4.498V16.328h-5.574v57.667h-15.411v14.824h-7.63 v-14.58h-13.044v14.58h-8.295v-14.58H82.138v14.58h-6.573v-14.58H59.072v14.58h-6.573v-14.58H39.458v36.338h13.041V94.391h6.573 v16.186h16.493V94.391h6.573v16.186h13.044V94.391h8.295v16.186h13.044V94.391h7.63v40.457l17.634,17.637h13.185v31.182h5.577 V73.996H145.14v-14.87H145.137z M154.97,146.907h-10.871l-14.376-14.376V79.57h25.247V146.907z"/>
<rect fill="#999999" x="147.703" y="16.328" width="5.572" height="7.345"/>
<rect fill="#999999" x="131.295" y="16.328" width="5.577" height="7.345"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 744 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M0 26h32v4h-32zM4 18h4v6h-4zM10 10h4v14h-4zM16 16h4v8h-4zM22 4h4v20h-4z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 409 B

View File

@@ -1,4 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<path d="M20 4.581v4.249c1.131 0.494 2.172 1.2 3.071 2.099 1.889 1.889 2.929 4.4 2.929 7.071s-1.040 5.182-2.929 7.071c-1.889 1.889-4.4 2.929-7.071 2.929s-5.182-1.040-7.071-2.929c-1.889-1.889-2.929-4.4-2.929-7.071s1.040-5.182 2.929-7.071c0.899-0.899 1.94-1.606 3.071-2.099v-4.249c-5.783 1.721-10 7.077-10 13.419 0 7.732 6.268 14 14 14s14-6.268 14-14c0-6.342-4.217-11.698-10-13.419zM14 0h4v16h-4z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 510 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M14 18h4v-8h6l-8-8-8 8h6zM20 13.5v3.085l9.158 3.415-13.158 4.907-13.158-4.907 9.158-3.415v-3.085l-12 4.5v8l16 6 16-6v-8z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 458 B

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 2.899l13.409 26.726h-26.819l13.409-26.726zM16 0c-0.69 0-1.379 0.465-1.903 1.395l-13.659 27.222c-1.046 1.86-0.156 3.383 1.978 3.383h27.166c2.134 0 3.025-1.522 1.978-3.383h0l-13.659-27.222c-0.523-0.93-1.213-1.395-1.903-1.395v0z"></path>
<path d="M18 26c0 1.105-0.895 2-2 2s-2-0.895-2-2c0-1.105 0.895-2 2-2s2 0.895 2 2z"></path>
<path d="M16 22c-1.105 0-2-0.895-2-2v-6c0-1.105 0.895-2 2-2s2 0.895 2 2v6c0 1.105-0.895 2-2 2z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 762 B

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="images/logo/mstile-70x70.png"/>
<square150x150logo src="images/logo/mstile-150x150.png"/>
<square310x310logo src="images/logo/mstile-310x310.png"/>
<wide310x150logo src="images/logo/mstile-310x150.png"/>
<TileColor>#000000</TileColor>
</tile>
</msapplication>
</browserconfig>

View File

@@ -1,87 +0,0 @@
<!DOCTYPE html>
<html ng-app="app" ng-strict-di="true" manifest="/coriolis.appcache">
<head>
<title ng-bind="title">Coriolis</title>
<link rel="stylesheet" href="/app.css">
<!-- Standard headers -->
<meta name="description" content="A ship builder, outfitting and comparison tool for Elite Dangerous">
<meta name="mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="manifest" href="/images/logo/manifest.json">
<link rel="icon" sizes="152x152 192x192" type="image/png" href="/images/logo/192x192.png">
<link rel="shortcut icon" href="/images/logo/favicon.ico">
<!-- Apple/iOS headers -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="Coriolis">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" sizes="180x180" href="/images/logo/apple-touch-icon-precomposed.png">
<link rel="apple-touch-icon" href="/images/logo/apple-touch-icon.png">
<!-- iPhone, iPod Touch, portrait -->
<link href="/images/splash/320x460.png" media="(device-width: 320px) and (device-height: 480px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
<!-- iPhone, iPod Touch, landscape -->
<link href="/images/splash/480x320.png" media="(device-width: 320px) and (device-height: 480px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
<!-- iPhone 4, 4S, portrait -->
<link href="/images/splash/640x920.png" media="(device-width: 320px) and (device-height: 480px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 4, 4S, landscape -->
<link href="/images/splash/960x640.png" media="(device-width: 320px) and (device-height: 480px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 5, 5S, 5C, portrait -->
<link href="/images/splash/640x1096.png" media="(device-width: 320px) and (device-height: 568px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 5, 5S, 5C, landscape -->
<link href="/images/splash/1136x640.png" media="(device-width: 320px) and (device-height: 568px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 6, portrait -->
<link href="/images/splash/750x1294.png" media="(device-width: 375px) and (device-height: 667px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 6, landscape -->
<link href="/images/splash/1334x750.png" media="(device-width: 375px) and (device-height: 667px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPhone 6+, portrait -->
<link href="/images/splash/1242x2148.png" media="(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image">
<!-- iPhone 6+, landscape -->
<link href="/images/splash/2208x1242.png" media="(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image">
<!-- iPad 1, 2, Mini, portrait -->
<link href="/images/splash/768x1004.png" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
<!-- iPad 1, 2, Mini, landscape -->
<link href="/images/splash/1024x748.png" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
<!-- iPad 3, 4, Air, Air 2, Mini 2, Mini 3, portrait -->
<link href="/images/splash/1536x2008.png" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPad 3, 4, Air, Air 2, Mini 2, Mini 3, landscape -->
<link href="/images/splash/2048x1496.png" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- Microsoft Windows Phone/Tablet headers -->
<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-TileImage" content="/images/logo/mstile-144x144.png">
<meta name="msapplication-config" content="/images/logo/browserconfig.xml">
<meta name="theme-color" content="#000000">
</head>
<body style="background-color:#000;">
<div style="height: 0; width: 0; overflow:hidden"><%= svgContent %></div>
<shipyard-header></shipyard-header>
<div id="main" ui-view ng-click="bgClicked($event)" ng-style="{'font-size': sizeRatio + 'em'}"></div>
<div ui-view="modal" ng-click="bgClicked($event)"></div>
<footer>
<div class="right cap">
<a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project"><span translate="version"></span> <%= version %> - <%= date %></a>
</div>
<div style="max-width:50%" class="l">
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
</div>
</footer>
<script src="/lib.js" type="text/javascript"></script>
<script src="/app.js" type="text/javascript"></script>
<% if (uaTracking) { %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '<%= uaTracking %> ', 'auto');
var GAPI_KEY = '<%= gapiKey %>';
</script>
<% } %>
</body>
</html>

View File

@@ -1,114 +0,0 @@
angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates', 'pascalprecht.translate'])
.run(['$rootScope', '$location', '$window', '$document', '$state', '$translate', 'localeFormat', 'Persist', 'Discounts', 'Languages', 'SizeMap',
function($rootScope, $location, $window, $doc, $state, $translate, localeFormat, Persist, Discounts, Languages, SizeMap) {
// App is running as a standalone web app on tablet/mobile
var isStandAlone;
// This was causing issues on Windows phones ($window.external was causing Angular js to throw an exception). Backup is to try this and set isStandAlone to false if this fails.
try {
isStandAlone = $window.navigator.standalone || ($window.external && $window.external.msIsSiteMode && $window.external.msIsSiteMode());
} catch (ex) {
isStandAlone = false;
}
// Redirect any state transition errors to the error controller/state
$rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error) {
e.preventDefault();
$state.go('error', error, { location: false, reload: true }); // Go to error state, reload the controller, keep the current URL
});
// Track on Google analytics if available
$rootScope.$on('$stateChangeSuccess', function(e, to, toParams, from, fromParams) {
$rootScope.prevState = { name: from.name, params: fromParams };
if (to.url) { // Only track states that have a URL
if ($window.ga) {
ga('send', 'pageview', { page: $location.path() });
}
if (isStandAlone) {
// Persist the current state
Persist.setState({ name: to.name, params: toParams });
}
}
});
$rootScope.language = {
opts: Languages,
current: Languages[Persist.getLangCode()] ? Persist.getLangCode() : 'en'
};
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
// Global Reference variables
$rootScope.insurance = { opts: [{ name: 'standard', pct: 0.05 }, { name: 'alpha', pct: 0.025 }, { name: 'beta', pct: 0.0375 }] };
$rootScope.discounts = { opts: Discounts };
$rootScope.sizeRatio = Persist.getSizeRatio();
$rootScope.SZM = SizeMap;
$rootScope.title = 'Coriolis';
$rootScope.changeLanguage = function() {
$translate.use($rootScope.language.current);
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
$rootScope.$broadcast('languageChanged', $rootScope.language.current);
};
// Formatters
$rootScope.fRPct = d3.format('%');
$rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); };
function updateNumberFormat() {
var locale = $rootScope.localeFormat;
var fGen = $rootScope.fGen = locale.numberFormat('n');
$rootScope.fCrd = locale.numberFormat(',.0f');
$rootScope.fPwr = locale.numberFormat(',.2f');
$rootScope.fRound = function(d) { return fGen(d3.round(d, 2)); };
$rootScope.fPct = locale.numberFormat('.2%');
$rootScope.f1Pct = locale.numberFormat('.1%');
}
/**
* Returns the name of the component mounted in the specified slot
* @param {Object} slot The slot object
* @return {String} The component name
*/
$rootScope.cName = function(slot) {
return $translate.instant(slot.c ? slot.c.name ? slot.c.name : slot.c.grp : null);
};
// Global Event Listeners
$doc.bind('keyup', function(e) {
if (e.keyCode == 27) { // Escape Key
$rootScope.$broadcast('close', e);
$rootScope.$apply();
} else {
$rootScope.$broadcast('keyup', e);
}
});
$rootScope.bgClicked = function(e) {
$rootScope.$broadcast('close', e);
};
if ($window.applicationCache) {
// Listen for appcache updated event, present refresh to update view
$window.applicationCache.addEventListener('updateready', function() {
if ($window.applicationCache.status == $window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
$rootScope.appCacheUpdate = true;
$rootScope.$apply();
}
}, false);
}
if (isStandAlone) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
$state.go(state.name, state.params, { location: 'replace' });
} else {
$state.go('shipyard', null, { location: 'replace' }); // Default to home page
}
}
}]);

View File

@@ -1,81 +0,0 @@
/**
* Sets up the routes and handlers before the Angular app is kicked off.
*/
angular.module('app').config(['$provide', '$stateProvider', '$urlRouterProvider', '$locationProvider', 'ShipsDB', function($provide, $stateProvider, $urlRouterProvider, $locationProvider, ships) {
// Use HTML5 push and replace state if possible
$locationProvider.html5Mode({ enabled: true, requireBase: false });
/**
* Set up all states and their routes.
*/
$stateProvider
.state('outfit', {
url: '/outfit/:shipId/:code?bn',
params: {
shipId: { value: 'sidewinder', squash: false }, // Allow 'shipId' parameter to default to sidewinder
code: { value: null, squash: true } // Allow 'code' parameter to be empty/optional
},
templateUrl: 'views/page-outfit.html',
controller: 'OutfitController',
resolve: {
shipId: ['$stateParams', function($p) { // Ensure ship exists before loading controller
if (!ships[$p.shipId]) {
throw { type: 'no-ship', message: $p.shipId };
}
}]
},
sticky: true
})
.state('compare', {
url: '/compare/:name',
params: {
name: { value: null, squash: true }
},
templateUrl: 'views/page-comparison.html',
controller: 'ComparisonController',
sticky: true
})
.state('comparison', {
url: '/comparison/:code',
templateUrl: 'views/page-comparison.html',
controller: 'ComparisonController',
sticky: true
})
.state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController', sticky: true })
.state('error', { params: { type: null, message: null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController', sticky: true })
// Modal States and views
.state('modal', { abstract: true, views: { 'modal': { templateUrl: 'views/_modal.html', controller: 'ModalController' } } })
.state('modal.about', { views: { 'modal-content': { templateUrl: 'views/modal-about.html' } } })
.state('modal.export', { params: { title: null, data: null, promise: null, description: null }, views: { 'modal-content': { templateUrl: 'views/modal-export.html', controller: 'ExportController' } } })
.state('modal.import', { params: { obj: null }, views: { 'modal-content': { templateUrl: 'views/modal-import.html', controller: 'ImportController' } } })
.state('modal.link', { params: { url: null }, views: { 'modal-content': { templateUrl: 'views/modal-link.html', controller: 'LinkController' } } })
.state('modal.delete', { views: { 'modal-content': { templateUrl: 'views/modal-delete.html', controller: 'DeleteController' } } });
// Redirects
$urlRouterProvider.when('/outfit', '/outfit/sidewinder');
/**
* 404 Handler - Keep current URL/ do not redirect, change to error state.
*/
$urlRouterProvider.otherwise(function($injector, $location) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { type: 404, message: null, details: null }, { location: false, reload: true });
return $location.path;
});
/**
* Global Error Handler. Decorates the existing error handler such that it
* redirects uncaught errors to the error page.
*
*/
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', function($delegate, $injector) {
return function(err, cause) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { type: null, message: err.message, details: err.stack }, { location: false, reload: true });
$delegate(err, cause);
};
}]);
}]);

View File

@@ -1,243 +0,0 @@
angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', '$translate', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, $translate, Utils, ShipFacets, Ships, Ship, Persist, Serializer) {
$rootScope.title = 'Coriolis - Compare';
$scope.predicate = 'name'; // Sort by ship name as default
$scope.desc = false;
$scope.facetSortOpts = { containment: '#facet-container', orderChanged: function() { $scope.saved = false; } };
$scope.builds = [];
$scope.unusedBuilds = [];
$scope.name = $stateParams.name;
$scope.compareMode = !$stateParams.code;
$scope.importObj = {}; // Used for importing comparison builds (from permalinked comparison)
var defaultFacets = [9, 6, 4, 1, 3, 2]; // Reverse order of Armour, Shields, Speed, Jump Range, Cargo Capacity, Cost
var facets = $scope.facets = angular.copy(ShipFacets);
var shipId, buildName, comparisonData;
/**
* Add an existing build to the comparison. The build must be saved locally.
* @param {string} id The unique ship key/id
* @param {string} name The build name
*/
$scope.addBuild = function(id, name, code) {
var data = Ships[id]; // Get ship properties
code = code ? code : Persist.builds[id][name]; // Retrieve build code if not passed
if (!code) { // No build found
return;
}
var b = new Ship(id, data.properties, data.slots); // Create a new Ship instance
Serializer.toShip(b, code); // Populate components from code
// Extend ship instance and add properties below
b.buildName = name;
b.code = code;
b.pctRetracted = b.powerRetracted / b.powerAvailable;
b.pctDeployed = b.powerDeployed / b.powerAvailable;
$scope.builds.push(b); // Add ship build to comparison
$scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc); // Resort
_.remove($scope.unusedBuilds, function(o) { // Remove from unused builds
return o.id == id && o.buildName == name;
});
$scope.saved = false;
};
/**
* Removes a build from the comparison
* @param {string} id The unique ship key/id
* @param {string} name The build name
*/
$scope.removeBuild = function(id, name) {
_.remove($scope.builds, function(s) {
if (s.id == id && s.buildName == name) {
$scope.unusedBuilds.push({ id: id, buildName: name, name: s.name }); // Add build back to unused builds
return true;
}
return false;
});
$scope.saved = false;
};
/**
* Toggles the selected the set of facets used in the comparison
* @param {number} i The index of the facet in facets
*/
$scope.toggleFacet = function(i) {
facets[i].active = !facets[i].active;
$scope.tblUpdate = !$scope.tblUpdate; // Simple switch to trigger the table to update
$scope.saved = false;
};
/**
* Click handler for sorting by facets in the table
* @param {object} e Event object
*/
$scope.handleClick = function(e) {
var elem = angular.element(e.target);
if (elem.attr('prop')) { // Get component ID
$scope.sort(elem.attr('prop'));
} else if (elem.attr('del')) { // Delete index
$scope.removeBuild(elem.attr('del'));
}
};
/**
* Sort the comparison array based on the selected facet / ship property
* @param {string} key Ship property
*/
$scope.sort = function(key) {
$scope.desc = $scope.predicate == key ? !$scope.desc : $scope.desc;
$scope.predicate = key;
$scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc);
};
/**
* Saves the current comparison's selected facets and builds
*/
$scope.save = function() {
$scope.name = $scope.name.trim();
if ($scope.name == 'all') {
return;
}
var selectedFacets = [];
facets.forEach(function(f) {
if (f.active) {
selectedFacets.unshift(f.index);
}
});
Persist.saveComparison($scope.name, $scope.builds, selectedFacets);
$state.go('compare', { name: $scope.name }, { location: 'replace', notify: false });
$scope.saved = true;
};
/**
* Permantently delete the current comparison
*/
$scope.delete = function() {
Persist.deleteComparison($scope.name);
$state.go('compare', { name: null }, { location: 'replace', reload: true });
};
/**
* Set saved to false when the name of the comparison is changed.
*/
$scope.nameChange = function() {
$scope.saved = false;
};
/**
* Hide/Show the select builds menu
* @param {boolean} s Show true/false
* @param {Event} e Event Object
*/
$scope.selectBuilds = function(s, e) {
e.stopPropagation();
$scope.showBuilds = s;
};
/**
* Show the permalink modal
* @param {Event} e Event object
*/
$scope.permalink = function(e) {
e.stopPropagation();
$state.go('modal.link', { url: genPermalink() });
};
/**
* Generate the forum embed code for the comparison
* and show the export modal.
*
* @param {Event} e Event object
*/
$scope.embed = function(e) {
e.stopPropagation();
// Make a request to goo.gl to shorten the URL, returns a promise
var promise = Utils.shortenUrl( genPermalink()).then(
function(shortUrl) {
return Utils.comparisonBBCode(facets, $scope.builds, shortUrl);
},
function(err) {
return 'Error - ' + err.statusText;
}
);
$state.go('modal.export', { promise: promise, title: $translate.instant('FORUM') + ' BBCode' });
};
/**
* Generates the long permalink URL
* @return {string} The long permalink URL
*/
function genPermalink() {
var selectedFacets = [];
facets.forEach(function(f) {
if (f.active) {
selectedFacets.unshift(f.index);
}
});
var code = Serializer.fromComparison(
$scope.name,
$scope.builds,
selectedFacets,
$scope.predicate,
$scope.desc
);
return $state.href('comparison', { code: code }, { absolute: true });
}
/* Event listeners */
$scope.$on('close', function() {
$scope.showBuilds = false;
});
$scope.$on('languageChanged', function() {
$scope.tblUpdate = !$scope.tblUpdate; // Simple switch to trigger the table to update
});
/* Initialization */
if ($scope.compareMode) {
if ($scope.name == 'all') {
for (shipId in Persist.builds) {
for (buildName in Persist.builds[shipId]) {
$scope.addBuild(shipId, buildName);
}
}
} else {
for (shipId in Persist.builds) {
for (buildName in Persist.builds[shipId]) {
$scope.unusedBuilds.push({ id: shipId, buildName: buildName, name: Ships[shipId].properties.name });
}
}
comparisonData = Persist.getComparison($scope.name);
if (comparisonData) {
defaultFacets = comparisonData.facets;
comparisonData.builds.forEach(function(b) {
$scope.addBuild(b.shipId, b.buildName);
});
$scope.saved = true;
}
}
} else {
try {
comparisonData = Serializer.toComparison($stateParams.code);
defaultFacets = comparisonData.f;
$scope.name = comparisonData.n;
$scope.predicate = comparisonData.p;
$scope.desc = comparisonData.d;
comparisonData.b.forEach(function(build) {
$scope.addBuild(build.s, build.n, build.c);
if (!$scope.importObj[build.s]) {
$scope.importObj[build.s] = {};
}
$scope.importObj[build.s][build.n] = build.c;
});
} catch (e) {
throw { type: 'bad-comparison', message: e.message, details: e };
}
}
// Replace fmt with actual format function as defined in rootScope and retain original index
facets.forEach(function(f, i) { f.index = i; });
// Remove default facets, mark as active, and add them back in selected order
_.pullAt(facets, defaultFacets).forEach(function(f) { f.active = true; facets.unshift(f); });
$scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc);
}]);

View File

@@ -1,7 +0,0 @@
angular.module('app').controller('DeleteController', ['$scope', 'Persist', function($scope, Persist) {
$scope.deleteAll = function() {
Persist.deleteAll();
$scope.$parent.dismiss();
};
}]);

View File

@@ -1,29 +0,0 @@
angular.module('app')
.controller('ErrorController', ['$window', '$rootScope', '$scope', '$stateParams', '$location', function($window, $rootScope, $scope, $p, $location) {
$rootScope.title = 'Error';
$scope.path = $location.path();
$scope.type = $p.type || 'unknown';
$scope.browser = $window.navigator.userAgent;
switch ($scope.type) {
case 404:
$scope.msgPre = 'Page';
$scope.msgHighlight = $scope.path;
$scope.msgPost = 'Not Found';
break;
case 'no-ship':
$scope.msgPre = 'Ship';
$scope.msgHighlight = $p.message;
$scope.msgPost = 'does not exist';
break;
case 'build-fail':
$scope.msgPre = 'Build Failure!';
$scope.details = $p.details;
break;
default:
$scope.msgPre = 'Uh, Jameson, we have a problem..';
$scope.errorMessage = $p.message;
$scope.details = $p.details;
}
}]);

View File

@@ -1,19 +0,0 @@
angular.module('app').controller('ExportController', ['$scope', '$stateParams', function($scope, $stateParams) {
$scope.title = $stateParams.title || 'Export';
$scope.description = $stateParams.description;
if ($stateParams.promise) {
$scope.export = 'Generating...';
$stateParams.promise.then(function(data) {
$scope.export = (typeof data === 'object') ? angular.toJson(data, true) : data;
});
} else {
$scope.export = angular.toJson($stateParams.data, true);
}
$scope.onTextClick = function($event) {
$event.target.select();
};
}]);

View File

@@ -1,316 +0,0 @@
angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$scope', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'GroupMap', 'Persist', 'Serializer', function(_, $rootScope, $scope, $stateParams, Ships, Ship, Components, GroupMap, Persist, Serializer) {
$scope.importValid = false;
$scope.importString = null;
$scope.errorMsg = null;
$scope.canEdit = true;
$scope.builds = $stateParams.obj || null;
$scope.ships = Ships;
var textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
var lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
var mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 };
var standardMap = { 'RB': 0, 'TM': 1, 'FH': 2, 'EC': 3, 'PC': 4, 'SS': 5, 'FS': 6 };
var bhMap = { 'lightweight alloy': 0, 'reinforced alloy': 1, 'military grade composite': 2, 'mirrored surface composite': 3, 'reactive surface composite': 4 };
function isEmptySlot(slot) {
return slot.maxClass == this && slot.c === null;
}
function equalsIgnoreCase(str) {
return str.toLowerCase() == this.toLowerCase();
}
function validateBuild(shipId, code, name) {
var shipData = Ships[shipId];
if (!shipData) {
throw '"' + shipId + '" is not a valid Ship Id!';
}
if (typeof name != 'string' || name.length == 0) {
throw shipData.properties.name + ' build "' + name + '" must be a string at least 1 character long!';
}
if (typeof code != 'string' || code.length < 10) {
throw shipData.properties.name + ' build "' + name + '" is not valid!';
}
try {
Serializer.toShip(new Ship(shipId, shipData.properties, shipData.slots), code);
} catch (e) {
throw shipData.properties.name + ' build "' + name + '" is not valid!';
}
}
function detailedJsonToBuild(detailedBuild) {
var ship;
if (!detailedBuild.name) {
throw 'Build Name missing!';
}
if (!detailedBuild.name.trim()) {
throw 'Build Name must be a string at least 1 character long!';
}
try {
ship = Serializer.fromDetailedBuild(detailedBuild);
} catch (e) {
throw detailedBuild.ship + ' Build "' + detailedBuild.name + '": Invalid data';
}
return { shipId: ship.id, name: detailedBuild.name, code: Serializer.fromShip(ship) };
}
function importBackup(importData) {
if (importData.builds && typeof importData.builds == 'object') {
for (var shipId in importData.builds) {
for (var buildName in importData.builds[shipId]) {
validateBuild(shipId, importData.builds[shipId][buildName], buildName);
}
}
$scope.builds = importData.builds;
} else {
throw 'builds must be an object!';
}
if (importData.comparisons) {
for (var compName in importData.comparisons) {
var comparison = importData.comparisons[compName];
for (var i = 0, l = comparison.builds.length; i < l; i++) {
var build = comparison.builds[i];
if (!importData.builds[build.shipId] || !importData.builds[build.shipId][build.buildName]) {
throw build.shipId + ' build "' + build.buildName + '" data is missing!';
}
}
}
$scope.comparisons = importData.comparisons;
}
if (importData.discounts instanceof Array && importData.discounts.length == 2) {
$scope.discounts = importData.discounts;
}
if (typeof importData.insurance == 'string' && importData.insurance.length > 3) {
$scope.insurance = importData.insurance;
}
}
function importDetailedArray(importArr) {
var builds = {};
for (var i = 0, l = importArr.length; i < l; i++) {
var build = detailedJsonToBuild(importArr[i]);
if (!builds[build.shipId]) {
builds[build.shipId] = {};
}
builds[build.shipId][build.name] = build.code;
}
$scope.builds = builds;
}
function importTextBuild(buildStr) {
var buildName = textBuildRegex.exec(buildStr)[1].trim();
var shipName = buildName.toLowerCase();
var shipId = null;
for (var sId in Ships) {
if (Ships[sId].properties.name.toLowerCase() == shipName) {
shipId = sId;
break;
}
}
if (!shipId) { throw 'No such ship found: "' + buildName + '"'; }
var lines = buildStr.split('\n');
var ship = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots);
ship.buildWith(null);
for (var i = 1; i < lines.length; i++) {
var line = lines[i].trim();
if (!line) { continue; }
if (line.substring(0, 3) == '---') { break; }
var parts = lineRegex.exec(line);
if (!parts) { throw 'Error parsing: "' + line + '"'; }
var typeSize = parts[1];
var cl = parts[2];
var rating = parts[3];
var mount = parts[4];
var missile = parts[5];
var name = parts[6].trim();
var slot, group;
if (isNaN(typeSize)) { // Standard or Hardpoint
if (typeSize.length == 1) { // Hardpoint
var slotClass = mountMap[typeSize];
if (cl > slotClass) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.hardpoints, isEmptySlot, slotClass);
if (!slot) { throw 'No hardpoint slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var hp = Components.findHardpoint(group, cl, rating, group ? null : name, mount, missile);
if (!hp) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, hp.id, hp, true);
} else if (typeSize == 'BH') {
var bhId = bhMap[name.toLowerCase()];
if (bhId === undefined) { throw 'Unknown bulkhead: "' + line + '"'; }
ship.useBulkhead(bhId, true);
} else if (standardMap[typeSize] != undefined) {
var standardIndex = standardMap[typeSize];
if (ship.standard[standardIndex].maxClass < cl) { throw name + ' exceeds max class for the ' + ship.name; }
ship.use(ship.standard[standardIndex], cl + rating, Components.standard(standardIndex, cl + rating), true);
} else {
throw 'Unknown component: "' + line + '"';
}
} else {
if (cl > typeSize) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.internal, isEmptySlot, typeSize);
if (!slot) { throw 'No internal slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var intComp = Components.findInternal(group, cl, rating, group ? null : name);
if (!intComp) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, intComp.id, intComp);
}
}
var builds = {};
builds[shipId] = {};
builds[shipId]['Imported ' + buildName] = Serializer.fromShip(ship);
$scope.builds = builds;
}
$scope.validateImport = function() {
var importData = null;
var importString = $scope.importString.trim();
$scope.importValid = false;
$scope.errorMsg = null;
$scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null;
if (!importString) { return; }
try {
if (textBuildRegex.test(importString)) { // E:D Shipyard build text
importTextBuild(importString);
} else { // JSON Build data
importData = angular.fromJson($scope.importString);
if (!importData || typeof importData != 'object') {
throw 'Must be an object or array!';
}
if (importData instanceof Array) { // Must be detailed export json
importDetailedArray(importData);
} else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export
importDetailedArray([importData]); // Convert to array with singleobject
} else { // Using Backup JSON
importBackup(importData);
}
}
} catch (e) {
$scope.errorMsg = (typeof e == 'string') ? e : 'Cannot Parse the data!';
return;
}
$scope.importValid = true;
};
$scope.hasBuild = function(shipId, name) {
return Persist.getBuild(shipId, name) !== null;
};
$scope.hasComparison = function(name) {
return Persist.getComparison(name) !== null;
};
$scope.process = function() {
if ($scope.builds) {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
// Update builds object such that orginal name retained, but can be renamed
builds[shipId][buildName] = {
code: code,
useName: buildName
};
}
}
}
if ($scope.comparisons) {
var comparisons = $scope.comparisons;
for (var name in comparisons) {
comparisons[name].useName = name;
}
}
$scope.processed = true;
};
$scope.import = function() {
if ($scope.builds) {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var build = builds[shipId][buildName];
var name = build.useName.trim();
if (name) {
Persist.saveBuild(shipId, name, build.code);
}
}
}
}
if ($scope.comparisons) {
var comparisons = $scope.comparisons;
for (var comp in comparisons) {
var comparison = comparisons[comp];
var useName = comparison.useName.trim();
if (useName) {
Persist.saveComparison(useName, comparison.builds, comparison.facets);
}
}
}
if ($scope.discounts) {
$rootScope.discounts.ship = $scope.discounts[0];
$rootScope.discounts.components = $scope.discounts[1];
$rootScope.$broadcast('discountChange');
Persist.setDiscount($scope.discounts);
}
if ($scope.insurance) {
$rootScope.insurance.current = $scope.insurance;
Persist.setInsurance($scope.insurance);
}
$scope.$parent.dismiss();
};
/* Initialization */
if ($scope.builds) { // If import is passed an build object
$scope.canEdit = false;
$scope.process();
}
}]);

View File

@@ -1,16 +0,0 @@
angular.module('app').controller('LinkController', ['$scope', 'Utils', '$stateParams', function($scope, Utils, $stateParams) {
$scope.url = $stateParams.url;
$scope.shortenedUrl = 'Shortening...';
$scope.onTextClick = function($event) {
$event.target.select();
};
Utils.shortenUrl($scope.url)
.then(function(url) {
$scope.shortenedUrl = url;
}, function(e) {
$scope.shortenedUrl = 'Error - ' + e.statusText;
});
}]);

View File

@@ -1,14 +0,0 @@
angular.module('app').controller('ModalController', ['$rootScope', '$scope', '$state', function($rootScope, $scope, $state) {
$scope.dismiss = function() {
if ($rootScope.prevState) {
var state = $rootScope.prevState;
$state.go(state.name, state.params, { location: 'replace', reload: false });
} else {
$state.go('shipyard');
}
};
$scope.$on('close', $scope.dismiss);
}]);

View File

@@ -1,655 +0,0 @@
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', '$translate', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', 'calcSpeed', function($window, $rootScope, $scope, $state, $p, $translate, Ships, Ship, Components, Serializer, Persist, calcTotalRange, calcSpeed) {
var win = angular.element($window); // Angularized window object for event triggering
var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
var retrofitShip = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship for retrofit comparison
// Update the ship instance with the code (if provided) or the 'factory' defaults.
if ($p.code) {
Serializer.toShip(ship, $p.code); // Populate components from 'code' URL param
$scope.code = $p.code;
} else {
ship.buildWith(data.defaults); // Populate with default components
}
$scope.buildName = $p.bn ? $window.decodeURIComponent($p.bn) : null;
$scope.ships = Ships;
$rootScope.title = ship.name + ($scope.buildName ? ' - ' + $scope.buildName : '');
$scope.ship = ship;
$scope.pp = ship.standard[0]; // Power Plant
$scope.th = ship.standard[1]; // Thruster
$scope.fsd = ship.standard[2]; // Frame Shrift Drive
$scope.ls = ship.standard[3]; // Life Support
$scope.pd = ship.standard[4]; // Power Distributor
$scope.ss = ship.standard[5]; // Sensors
$scope.ft = ship.standard[6]; // Fuel Tank
$scope.hps = ship.hardpoints;
$scope.internal = ship.internal;
$scope.costList = ship.costList;
$scope.powerList = ship.powerList;
$scope.priorityBands = ship.priorityBands;
$scope.availCS = ship.getAvailableComponents();
$scope.selectedSlot = null;
$scope.savedCode = Persist.getBuild(ship.id, $scope.buildName);
$scope.canSave = Persist.isEnabled();
$scope.allBuilds = Persist.builds;
$scope.fuel = 0;
$scope.pwrDesc = false;
$scope.pwrPredicate = 'type';
$scope.retroDesc = false;
$scope.retroPredicate = 'netCost';
$scope.costDesc = true;
$scope.costPredicate = 'c.cost';
$scope.ammoDesc = true;
$scope.ammoPredicate = 'ammoUnitCost';
$scope.costTab = Persist.getCostTab() || 'costs';
if ($scope.savedCode) {
Serializer.toShip(retrofitShip, $scope.savedCode); // Populate components from last save
$scope.retrofitBuild = $scope.buildName;
} else {
retrofitShip.buildWith(data.defaults);
$scope.retrofitBuild = null;
}
ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
retrofitShip.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
updateRetrofitCosts();
$scope.jrSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: ship.unladenRange,
yMin: 0,
func: function(cargo) { // X Axis is Cargo
return ship.getJumpRangeForMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel);
}
};
$scope.jrChart = {
labels: {
xAxis: {
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'jump range',
unit: 'LY'
}
}
};
$scope.trSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: ship.unladenTotalRange,
yMin: 0,
func: function(cargo) { // X Axis is Cargo
return calcTotalRange(ship.unladenMass + cargo, $scope.fsd.c, $scope.fuel);
}
};
$scope.trChart = {
labels: {
xAxis: {
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'total range',
unit: 'LY'
}
}
};
$scope.speedSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: calcSpeed(ship.unladenMass, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed).boost,
yMin: 0,
series: ['boost', '4 Pips', '2 Pips', '0 Pips'],
colors: ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'],
func: function(cargo) { // X Axis is Cargo
return calcSpeed(ship.unladenMass + $scope.fuel + cargo, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed);
}
};
$scope.speedChart = {
labels: {
xAxis: {
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'speed',
unit: 'm/s'
}
}
};
/**
* 'Opens' a select for component selection.
*
* @param {[type]} e The event object
* @param {[type]} slot The slot that is being 'opened' for selection
*/
$scope.selectSlot = function(e, slot) {
e.stopPropagation();
if ($scope.selectedSlot == slot) {
$scope.selectedSlot = null;
} else {
$scope.selectedSlot = slot;
}
};
/**
* Updates the ships build with the selected component for the
* specified slot. Prevents the click event from propagation.
*
* @param {string} type Shorthand key/string for identifying the slot & component type
* @param {[type]} slot The slot object belonging to the ship instance
* @param {[type]} e The event object
*/
$scope.select = function(type, slot, e, id) {
e.stopPropagation();
if (!id) { // Find component id if not passed
var elem = e.target;
while (elem && elem !== e.currentTarget && !elem.getAttribute('cpid')) {
elem = elem.parentElement;
}
if (elem) {
id = elem.getAttribute('cpid');
}
}
if (id) {
if (id == 'empty') {
ship.use(slot, null, null);
} else if (type == 'h') {
ship.use(slot, id, Components.hardpoints(id));
} else if (type == 'c') {
ship.use(slot, id, Components.standard(ship.standard.indexOf(slot), id));
} else if (type == 'i') {
ship.use(slot, id, Components.internal(id));
} else if (type == 'b') {
ship.useBulkhead(id);
}
$scope.selectedSlot = null;
updateState(Serializer.fromShip(ship));
}
};
/**
* Reload the build from the last save.
*/
$scope.reloadBuild = function() {
if ($scope.buildName && $scope.savedCode) {
Serializer.toShip(ship, $scope.savedCode); // Repopulate with components from last save
updateState($scope.savedCode);
}
};
$scope.resetBuild = function() {
ship.buildWith(data.defaults); // Populate with default components
updateState(null);
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
*/
$scope.optimizeMassBuild = function() {
updateState(Serializer.fromShip(ship.optimizeMass()));
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
*/
$scope.optimizeStandard = function() {
updateState(Serializer.fromShip(ship.useLightestStandard()));
};
$scope.useStandard = function(rating) {
updateState(Serializer.fromShip(ship.useStandard(rating)));
};
$scope.useHardpoint = function(group, mount, clobber, missile) {
updateState(Serializer.fromShip(ship.useWeapon(group, mount, clobber, missile)));
};
$scope.useUtility = function(group, rating, clobber) {
updateState(Serializer.fromShip(ship.useUtility(group, rating, clobber)));
};
$scope.emptyInternal = function() {
updateState(Serializer.fromShip(ship.emptyInternal()));
};
$scope.emptyHardpoints = function() {
updateState(Serializer.fromShip(ship.emptyWeapons()));
};
$scope.emptyUtility = function() {
updateState(Serializer.fromShip(ship.emptyUtility()));
};
$scope.fillWithCargo = function() {
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('cr', slot.maxClass, 'E');
if (!slot.c) {
ship.use(slot, id, Components.internal(id));
}
});
updateState(Serializer.fromShip(ship));
};
$scope.fillWithCells = function() {
var chargeCap = 0; // Capacity of single activation
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('scb', slot.maxClass, 'A');
if (!slot.c && (!slot.eligible || slot.eligible.scb)) { // Check eligibility because of Orca, don't overwrite generator
ship.use(slot, id, Components.internal(id));
chargeCap += Components.internal(id).recharge;
ship.setSlotEnabled(slot, chargeCap <= ship.shieldStrength); // Don't waste cell capacity on overcharge
}
});
updateState(Serializer.fromShip(ship));
};
$scope.fillWithArmor = function() {
ship.internal.forEach(function(slot) {
var hr = Components.findInternal('hr', Math.min(slot.maxClass, 5), 'D'); // Hull reinforcements top out at 5D
if (!slot.c && hr) {
ship.use(slot, hr.id, hr);
}
});
updateState(Serializer.fromShip(ship));
};
/**
* Fill all internal slots with Cargo Racks, and optmize internal components.
* Hardpoints are not altered.
*/
$scope.optimizeCargo = function() {
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('cr', slot.maxClass, 'E');
ship.use(slot, id, Components.internal(id));
});
ship.useLightestStandard();
updateState(Serializer.fromShip(ship));
};
/**
* Optimize standard and internal components, hardpoints for exploration
*/
$scope.optimizeExplorer = function() {
var intLength = ship.internal.length,
heatSinkCount = 2, // Fit 2 heat sinks if possible
afmUnitCount = 2, // Fit 2 AFM Units if possible
sgSlot,
fuelScoopSlot,
sgId = $scope.availCS.lightestShieldGenerator(ship.hullMass),
sg = Components.internal(sgId);
ship.setSlotEnabled(ship.cargoHatch, false)
.use(ship.internal[--intLength], '2f', Components.internal('2f')) // Advanced Discovery Scanner
.use(ship.internal[--intLength], '2i', Components.internal('2i')); // Detailed Surface Scanner
for (var i = 0; i < intLength; i++) {
var slot = ship.internal[i];
var nextSlot = (i + 1) < intLength ? ship.internal[i + 1] : null;
if (!fuelScoopSlot && (!slot.eligible || slot.eligible.fs)) { // Fit best possible Fuel Scoop
var fuelScoopId = Components.findInternalId('fs', slot.maxClass, 'A');
fuelScoopSlot = slot;
ship.use(fuelScoopSlot, fuelScoopId, Components.internal(fuelScoopId));
ship.setSlotEnabled(fuelScoopSlot, true);
// Mount a Shield generator if possible AND an AFM Unit has been mounted already (Guarantees at least 1 AFM Unit)
} else if (!sgSlot && afmUnitCount < 2 && sg.class <= slot.maxClass && (!slot.eligible || slot.eligible.sg) && (!nextSlot || nextSlot.maxClass < sg.class)) {
sgSlot = slot;
ship.use(sgSlot, sgId, sg);
ship.setSlotEnabled(sgSlot, true);
} else if (afmUnitCount > 0 && (!slot.eligible || slot.eligible.am)) {
afmUnitCount--;
var am = Components.findInternal('am', slot.maxClass, afmUnitCount ? 'B' : 'A');
ship.use(slot, am.id, am);
ship.setSlotEnabled(slot, false); // Disabled power for AFM Unit
} else {
ship.use(slot, null, null);
}
}
ship.hardpoints.forEach(function(s) {
if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks
ship.use(s, '02', Components.hardpoints('02'));
ship.setSlotEnabled(s, heatSinkCount == 2); // Only enable a single Heatsink
heatSinkCount--;
} else {
ship.use(s, null, null);
}
});
if (sgSlot) {
// The SG and Fuel scoop to not need to be powered at the same time
if (sgSlot.c.power > fuelScoopSlot.c.power) { // The Shield generator uses the most power
ship.setSlotEnabled(fuelScoopSlot, false);
} else { // The Fuel scoop uses the most power
ship.setSlotEnabled(sgSlot, false);
}
}
ship.useLightestStandard({ pd: '1D', ppRating: 'A' });
updateState(Serializer.fromShip(ship));
};
/**
* Save the current build. Will replace the saved build if there is one
* for this ship & with the exact name.
*/
$scope.saveBuild = function() {
if (!$scope.buildName) {
return;
}
// No change hav been made, i.e. save ship default build under a name
if (!$scope.code) {
$scope.code = Serializer.fromShip(ship);
}
// Only save if there a build name and a change has been made or the build has never been saved
if ($scope.code != $scope.savedCode) {
Persist.saveBuild(ship.id, $scope.buildName, $scope.code);
$scope.savedCode = $scope.code;
if ($scope.retrofitBuild === $scope.buildName) {
Serializer.toShip(retrofitShip, $scope.code);
}
updateState($scope.code);
}
};
/**
* Export the build to detailed JSON
*/
$scope.exportBuild = function(e) {
e.stopPropagation();
if ($scope.buildName) {
$state.go('modal.export', {
title: $scope.buildName + ' ' + $translate.instant('export'),
description: $translate.instant('PHRASE_EXPORT_DESC'),
data: Serializer.toDetailedBuild($scope.buildName, ship, $scope.code || Serializer.fromShip(ship))
});
}
};
/**
* Permanently delete the current build and redirect/reload this controller
* with the 'factory' build of the current ship.
*/
$scope.deleteBuild = function() {
Persist.deleteBuild(ship.id, $scope.buildName);
$state.go('outfit', { shipId: ship.id, code: null, bn: null }, { location: 'replace', reload: true });
};
/**
* On build name change, retrieve the existing saved code if there is one
*/
$scope.bnChange = function() {
$scope.savedCode = Persist.getBuild(ship.id, $scope.buildName);
};
/**
* Toggle cost of the selected component
* @param {object} item The component being toggled
*/
$scope.toggleCost = function(item) {
ship.setCostIncluded(item, !item.incCost);
};
/**
* Toggle cost of the selected component for retrofitting comparison
* @param {object} item The component being toggled
*/
$scope.toggleRetrofitCost = function(item) {
retrofitShip.setCostIncluded(item, !item.incCost);
updateRetrofitCosts();
};
/**
* [sortCost description]
* @param {[type]} key [description]
* @return {[type]} [description]
*/
$scope.sortCost = function(key) {
$scope.costDesc = $scope.costPredicate == key ? !$scope.costDesc : $scope.costDesc;
$scope.costPredicate = key;
};
$scope.sortPwr = function(key) {
$scope.pwrDesc = $scope.pwrPredicate == key ? !$scope.pwrDesc : $scope.pwrDesc;
$scope.pwrPredicate = key;
};
$scope.sortRetrofit = function(key) {
$scope.retroDesc = $scope.retroPredicate == key ? !$scope.retroDesc : $scope.retroDesc;
$scope.retroPredicate = key;
};
$scope.sortAmmo = function(key) {
$scope.ammoDesc = $scope.ammoPredicate == key ? !$scope.ammoDesc : $scope.ammoDesc;
$scope.ammoPredicate = key;
};
/**
* Toggle the power on/off for the selected component
* @param {object} item The component being toggled
*/
$scope.togglePwr = function(c) {
ship.setSlotEnabled(c, !c.enabled);
updateState(Serializer.fromShip(ship));
};
$scope.incPriority = function(c) {
if (ship.changePriority(c, c.priority + 1)) {
updateState(Serializer.fromShip(ship));
}
};
$scope.decPriority = function(c) {
if (ship.changePriority(c, c.priority - 1)) {
updateState(Serializer.fromShip(ship));
}
};
$scope.fuelChange = function(fuel) {
$scope.fuel = fuel;
updateAmmoCosts();
win.triggerHandler('render');
};
$scope.statusRetracted = function(slot) {
return ship.getSlotStatus(slot, false);
};
$scope.statusDeployed = function(slot) {
return ship.getSlotStatus(slot, true);
};
$scope.setRetrofitBase = function() {
if ($scope.retrofitBuild) {
Serializer.toShip(retrofitShip, Persist.getBuild(ship.id, $scope.retrofitBuild));
} else {
retrofitShip.buildWith(data.defaults);
}
updateRetrofitCosts();
};
$scope.updateCostTab = function(tab) {
Persist.setCostTab(tab);
$scope.costTab = tab;
};
$scope.ppWarning = function(pp) {
return pp.pGen < ship.powerRetracted;
};
$scope.pdWarning = function(pd) {
return pd.enginecapacity < ship.boostEnergy;
};
// Utilify functions
function updateState(code) {
$scope.code = code;
$state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false });
$scope.speedSeries.xMax = $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity;
$scope.jrSeries.yMax = ship.unladenRange;
$scope.trSeries.yMax = ship.unladenTotalRange;
$scope.speedSeries.yMax = calcSpeed(ship.unladenMass, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed).boost;
updateRetrofitCosts();
win.triggerHandler('pwrchange');
}
function updateRetrofitCosts() {
var costs = $scope.retrofitList = [];
var total = 0, i, l, item;
if (ship.bulkheads.id != retrofitShip.bulkheads.id) {
item = {
buyClassRating: ship.bulkheads.c.class + ship.bulkheads.c.rating,
buyName: ship.bulkheads.c.name,
sellClassRating: retrofitShip.bulkheads.c.class + retrofitShip.bulkheads.c.rating,
sellName: retrofitShip.bulkheads.c.name,
netCost: ship.bulkheads.discountedCost - retrofitShip.bulkheads.discountedCost,
retroItem: retrofitShip.bulkheads
};
costs.push(item);
if (retrofitShip.bulkheads.incCost) {
total += item.netCost;
}
}
for (var g in { standard: 1, internal: 1, hardpoints: 1 }) {
var retroSlotGroup = retrofitShip[g];
var slotGroup = ship[g];
for (i = 0, l = slotGroup.length; i < l; i++) {
if (slotGroup[i].id != retroSlotGroup[i].id) {
item = { netCost: 0, retroItem: retroSlotGroup[i] };
if (slotGroup[i].id) {
item.buyName = slotGroup[i].c.name || slotGroup[i].c.grp;
item.buyClassRating = slotGroup[i].c.class + slotGroup[i].c.rating;
item.netCost = slotGroup[i].discountedCost;
}
if (retroSlotGroup[i].id) {
item.sellName = retroSlotGroup[i].c.name || retroSlotGroup[i].c.grp;
item.sellClassRating = retroSlotGroup[i].c.class + retroSlotGroup[i].c.rating;
item.netCost -= retroSlotGroup[i].discountedCost;
}
costs.push(item);
if (retroSlotGroup[i].incCost) {
total += item.netCost;
}
}
}
}
$scope.retrofitTotal = total;
updateAmmoCosts();
}
function updateAmmoCosts() {
var costs = $scope.ammoList = [];
var total = 0, i, l, item, q, limpets = 0, srvs = 0, scoop = false;
for (var g in { standard: 1, internal: 1, hardpoints: 1 }) {
var slotGroup = ship[g];
for (i = 0, l = slotGroup.length; i < l; i++) {
if (slotGroup[i].id) {
//special cases needed for SCB, AFMU, and limpet controllers since they don't use standard ammo/clip
q = 0;
switch (slotGroup[i].c.grp) {
case 'fs': //skip fuel calculation if scoop present
scoop = true;
break;
case 'scb':
q = slotGroup[i].c.cells;
break;
case 'am':
q = slotGroup[i].c.ammo;
break;
case 'fx': case 'hb': case 'cc': case 'pc':
limpets = ship.cargoCapacity;
break;
case 'pv':
srvs += slotGroup[i].c.bays;
break;
default:
q = slotGroup[i].c.clip + slotGroup[i].c.ammo;
}
//calculate ammo costs only if a cost is specified
if (slotGroup[i].c.ammocost > 0) {
item = {
ammoClassRating: slotGroup[i].c.class + slotGroup[i].c.rating,
ammoName: slotGroup[i].c.name || slotGroup[i].c.grp,
ammoMax: q,
ammoUnitCost: slotGroup[i].c.ammocost,
ammoTotalCost: q * slotGroup[i].c.ammocost
};
costs.push(item);
total += item.ammoTotalCost;
}
}
}
}
//limpets if controllers exist and cargo space available
if (srvs > 0) {
item = {
ammoName: 'SRVs',
ammoMax: srvs,
ammoUnitCost: 6005,
ammoTotalCost: srvs * 6005
};
costs.push(item);
total += item.ammoTotalCost;
}
//limpets if controllers exist and cargo space available
if (limpets > 0) {
item = {
ammoName: 'limpets',
ammoMax: ship.cargoCapacity,
ammoUnitCost: 101,
ammoTotalCost: ship.cargoCapacity * 101
};
costs.push(item);
total += item.ammoTotalCost;
}
//calculate refuel costs if no scoop present
if (!scoop) {
item = {
ammoName: 'fuel',
ammoMax: $scope.fuel,
ammoUnitCost: 50,
ammoTotalCost: $scope.fuel * 50
};
costs.push(item);
total += item.ammoTotalCost;
}
$scope.ammoTotal = total;
}
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('close', function() {
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('languageChanged', function() {
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('discountChange', function() {
ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
retrofitShip.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
updateRetrofitCosts();
});
}]);

View File

@@ -1,59 +0,0 @@
angular.module('app').controller('ShipyardController', ['$rootScope', '$scope', 'ShipsDB', 'Ship', 'Components', function($rootScope, $scope, ShipsDB, Ship, Components) {
$rootScope.title = 'Coriolis - Shipyard';
$scope.shipPredicate = 'properties.name';
$scope.shipDesc = false;
function countHp(slot) {
this.hp[slot.maxClass]++;
this.hpCount++;
}
function countInt(slot) {
var crEligible = !slot.eligible || slot.eligible.cr;
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++;
this.maxCargo += crEligible ? Components.findInternal('cr', slot.maxClass, 'E').capacity : 0;
}
function shipSummary(shipId, shipData) {
var summary = angular.copy(shipData.properties);
var ship = new Ship(shipId, shipData.properties, shipData.slots);
summary.id = s;
summary.hpCount = 0;
summary.intCount = 0;
summary.maxCargo = 0;
summary.hp = [0, 0, 0, 0, 0]; // Utility, Small, Medium, Large, Huge
summary.int = [0, 0, 0, 0, 0, 0, 0, 0]; // Sizes 1 - 8
// Build Ship
ship.buildWith(shipData.defaults); // Populate with stock/default components
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
ship.optimizeMass({ th: ship.standard[1].maxClass + 'A' }); // Optmize mass with Max Thrusters
summary.topSpeed = ship.topSpeed;
summary.topBoost = ship.topBoost;
return summary;
}
/* Initialization */
if (!$rootScope.shipsOverview) { // Only generate this once
$rootScope.shipsOverview = [];
for (var s in ShipsDB) {
$scope.shipsOverview.push(shipSummary(s, ShipsDB[s]));
}
}
/**
* Sort ships
* @param {object} key Sort predicate
*/
$scope.sortShips = function(key) {
$scope.shipDesc = $scope.shipPredicate == key ? !$scope.shipDesc : $scope.shipDesc;
$scope.shipPredicate = key;
};
}]);

View File

@@ -1,164 +0,0 @@
angular.module('app').directive('areaChart', ['$window', '$translate', function($window, $translate) {
return {
restrict: 'A',
scope: {
config: '=',
series: '='
},
link: function(scope, element) {
var series = scope.series,
config = scope.config,
labels = config.labels,
margin = { top: 15, right: 15, bottom: 35, left: 60 },
fmt = d3.format('.3r'),
fmtLong = d3.format('.2f'),
func = series.func,
drag = d3.behavior.drag(),
dragging = false,
// Define Axes
xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')),
yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt),
x = d3.scale.linear(),
y = d3.scale.linear(),
data = [];
// Create chart
var svg = d3.select(element[0]).append('svg');
var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Define Area
var area = d3.svg.area();
var gradient = vis.append('defs')
.append('linearGradient')
.attr('id', 'gradient')
.attr('x1', '0%').attr('y1', '0%')
.attr('x2', '100%').attr('y2', '100%')
.attr('spreadMethod', 'pad');
gradient.append('stop')
.attr('offset', '0%')
.attr('stop-color', '#ff8c0d')
.attr('stop-opacity', 1);
gradient.append('stop')
.attr('offset', '100%')
.attr('stop-color', '#ff3b00')
.attr('stop-opacity', 1);
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text($translate.instant(labels.yAxis.title) + ' (' + $translate.instant(labels.yAxis.unit) + ')');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text($translate.instant(labels.xAxis.title) + ' (' + $translate.instant(labels.xAxis.unit) + ')');
// Create and Add tooltip
var tip = vis.append('g').style('display', 'none');
tip.append('rect').attr('width', '4.5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip');
tip.append('circle')
.attr('class', 'marker')
.attr('r', 4);
tip.append('text').attr('class', 'label x').attr('y', '-0.25em');
tip.append('text').attr('class', 'label y').attr('y', '0.85em');
vis.insert('path', ':first-child') // Area/Path to appear behind everything else
.data([data])
.attr('class', 'area')
.attr('fill', 'url(#gradient)')
.attr('d', area)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
/**
* Watch for changes in the series data (mass changes, etc)
*/
scope.$watchCollection('series', render);
angular.element($window).bind('orientationchange resize render', render);
function render() {
var width = element[0].parentElement.offsetWidth,
height = width * 0.5,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom;
data.length = 0; // Reset Data array
if (series.xMax == series.xMin) {
var yVal = func(series.xMin);
data.push([ series.xMin, yVal ]);
data.push([ series.xMin, yVal ]);
area.x(function(d, i) { return i * w; }).y0(h).y1(function(d) { return y(d[1]); });
} else {
for (var val = series.xMin; val <= series.xMax; val += 1) {
data.push([ val, func(val) ]);
}
area.x(function(d) { return x(d[0]); }).y0(h).y1(function(d) { return y(d[1]); });
}
// Update Chart Size
svg.attr('width', width).attr('height', height);
// Update domain and scale for axes
x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true);
xAxis.scale(x);
xLbl.attr('transform', 'translate(0,' + h + ')');
xTxt.attr('x', w / 2);
y.range([h, 0]).domain([series.yMin, series.yMax]);
yAxis.scale(y);
yTxt.attr('x', -h / 2);
vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').call(xAxis);
vis.selectAll('path.area') // Area/Path to appear behind everything else
.data([data])
.attr('d', area);
}
function showTip() {
tip.style('display', null);
}
function hideTip() {
if (!dragging) {
tip.style('display', 'none');
}
}
function moveTip() {
var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.65);
tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')');
tip.selectAll('rect').attr('x', flip ? '-5.75em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.select('text.label.x').text(fmtLong(x0) + ' ' + $translate.instant(labels.xAxis.unit));
tip.select('text.label.y').text(fmtLong(y0) + ' ' + $translate.instant(labels.yAxis.unit));
}
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
});
}
};
}]);

View File

@@ -1,134 +0,0 @@
angular.module('app').directive('barChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
function bName(build) {
return build.buildName + '\n' + build.name;
}
function insertLinebreaks(d) {
var el = d3.select(this);
var lines = d.split('\n');
el.text('').attr('y', -6);
for (var i = 0; i < lines.length; i++) {
var tspan = el.append('tspan').text(lines[i].length > 18 ? lines[i].substring(0, 15) + '...' : lines[i]);
if (i > 0) {
tspan.attr('x', -9).attr('dy', '1em');
} else {
tspan.attr('class', 'primary');
}
}
}
return {
restrict: 'A',
scope: {
data: '=',
facet: '='
},
link: function(scope, element) {
var color = d3.scale.ordinal().range([ '#7b6888', '#6b486b', '#3182bd', '#a05d56', '#d0743c']),
labels = scope.facet.lbls,
fmt = null,
unit = null,
properties = scope.facet.props,
margin = { top: 10, right: 20, bottom: 40, left: 150 },
y0 = d3.scale.ordinal(),
y1 = d3.scale.ordinal(),
x = d3.scale.linear(),
yAxis = d3.svg.axis().scale(y0).outerTickSize(0).orient('left'),
xAxis = d3.svg.axis().scale(x).ticks(5).outerTickSize(0).orient('bottom');
// Create chart
var svg = d3.select(element[0]).append('svg');
var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Create and Add tooltip
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(property, propertyIndex) {
return (labels ? ($translate.instant(labels[propertyIndex]) + ': ') : '') + fmt(property.value) + ' ' + unit;
});
vis.call(tip);
// Create Y Axis SVG Elements
vis.append('g').attr('class', 'y axis');
vis.selectAll('g.y.axis g text').each(insertLinebreaks);
// Create X Axis SVG Elements
var xAxisLbl = vis.append('g')
.attr('class', 'x axis cap')
.append('text')
.attr('y', 33)
.attr('dy', '.1em')
.style('text-anchor', 'middle');
updateFormats();
function render() {
var data = scope.data,
width = element[0].offsetWidth,
w = width - margin.left - margin.right,
height = 50 + (30 * data.length * $rootScope.sizeRatio),
h = height - margin.top - margin.bottom,
maxVal = d3.max(data, function(d) { return d3.max(properties, function(p) {return d[p]; }); });
// Update chart size
svg.attr('width', width).attr('height', height);
// Remove existing elements
vis.selectAll('.ship').remove();
vis.selectAll('rect').remove();
// Update X & Y Axis
x.range([0, w]).domain([0, maxVal]);
y0.domain(data.map(bName)).rangeRoundBands([0, h], 0.3);
y1.domain(properties).rangeRoundBands([0, y0.rangeBand()]);
vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').attr('transform', 'translate(0,' + h + ')').call(xAxis);
xAxisLbl.attr('x', w / 2);
// Update Y-Axis labels
vis.selectAll('g.y.axis g text').each(insertLinebreaks);
var group = vis.selectAll('.ship')
.data(scope.data, bName)
.enter().append('g')
.attr('class', 'g')
.attr('transform', function(build) { return 'translate(0,' + y0(bName(build)) + ')'; });
group.selectAll('rect')
.data(function(build) {
var o = [];
for (var i = 0; i < properties.length; i++) {
o.push({ name: properties[i], value: build[properties[i]] });
}
return o;
})
.enter().append('rect')
.attr('height', y1.rangeBand())
.attr('x', 0)
.attr('y', function(d) {return y1(d.name); })
.attr('width', function(d) { return x(d.value); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.style('fill', function(d) { return color(d.name); });
}
function updateFormats() {
fmt = $rootScope[scope.facet.fmt];
unit = $translate.instant(scope.facet.unit);
xAxisLbl.text($translate.instant(scope.facet.title) + (unit ? (' (' + $translate.instant(unit) + ')') : ''));
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2s'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('data', render); // Watch for changes in the comparison array
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
tip.destroy(); // Remove the tooltip from the DOM
});
}
};
}]);

View File

@@ -1,80 +0,0 @@
angular.module('app').directive('comparisonTable', ['$state', '$translate', '$rootScope', function($state, $translate, $rootScope) {
function tblHeader(facets) {
var r1 = ['<tr class="main"><th rowspan="2" class="prop" prop="name">', $translate.instant('SHIP'), '</th><th rowspan="2" class="prop" prop="buildName">', $translate.instant('BUILD'), '</th>'];
var r2 = [];
for (var i = 0, l = facets.length; i < l; i++) {
if (facets[i].active) {
var f = facets[i];
var p = f.props;
var pl = p.length;
r1.push('<th rowspan="', f.props.length == 1 ? 2 : 1, '" colspan="', pl, '"');
if (pl == 1) {
r1.push(' prop="', p[0], '" class="prop"');
} else {
for (var j = 0; j < pl; j++) {
r2.push('<th prop="', p[j], '" class="prop ', j === 0 ? 'lft' : '', '">', $translate.instant(f.lbls[j]), '</th>');
}
}
r1.push('>', $translate.instant(f.title), '</th>');
}
}
r1.push('</tr><tr>');
r1.push(r2.join(''));
r1.push('</tr>');
return r1.join('');
}
function tblBody(facets, builds) {
var body = [];
if (builds.length === 0) {
return '<td colspan="100" class="cen">No builds added to comparison!</td';
}
for (var i = 0, l = builds.length; i < l; i++) {
var b = builds[i];
body.push('<tr class="tr">');
var href = $state.href('outfit', { shipId: b.id, code: b.code, bn: b.buildName });
body.push('<td class="tl"><a href="', href, '">', b.name, '</a></td>');
body.push('<td class="tl"><a href="', href, '">', b.buildName, '</a></td>');
for (var j = 0, fl = facets.length; j < fl; j++) {
if (facets[j].active) {
var f = facets[j];
var p = f.props;
for (var k = 0, pl = p.length; k < pl; k++) {
body.push('<td>', $rootScope[f.fmt](b[p[k]]), '<u> ', $translate.instant(f.unit), '</u></td>');
}
}
}
body.push('</tr>');
}
return body.join('');
}
return {
restrict: 'A',
link: function(scope, element) {
var header = angular.element('<thead></thead>');
var body = angular.element('<tbody></tbody>');
element.append(header);
element.append(body);
var updateAll = function() {
header.html(tblHeader(scope.facets));
body.html(tblBody(scope.facets, scope.builds));
};
scope.$watchCollection('facets', updateAll);
scope.$watch('tblUpdate', updateAll);
scope.$watchCollection('builds', function() {
body.html(tblBody(scope.facets, scope.builds));
});
}
};
}]);

View File

@@ -1,90 +0,0 @@
angular.module('app').directive('componentSelect', ['$translate', function($translate) {
// Generting the HTML in this manner is MUCH faster than using an angular template.
function appendGroup(list, opts, cid, mass, checkWarning) {
var prevClass = null, prevRating = null;
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
var id = o.id || (o.class + o.rating); // Standard components' ID is their class and rating
if (i > 0 && opts.length > 3 && o.class != prevClass && (o.rating != prevRating || o.mode) && o.grp != 'pa') {
list.push('<br/>');
}
list.push('<li class="', o.name ? 'lc' : 'c');
if (cid == id) {
list.push(' active');
}
if (checkWarning && checkWarning(opts[i])) {
list.push(' warning');
}
list.push(((o.maxmass && (mass + (o.mass ? o.mass : 0)) > o.maxmass) ? ' disabled"' : '" cpid="' + id + '"'), '>');
if (o.mode) {
list.push('<svg class="icon lg"><use xlink:href="#mount-', o.mode, '"></use></svg> ');
}
list.push('<span>', o.class, o.rating);
if (o.missile) {
list.push('/' + o.missile);
}
if (o.name) {
list.push(' ' + $translate.instant(o.name));
}
list.push('</span></li>');
prevClass = o.class;
prevRating = o.rating;
}
}
return {
restrict: 'A',
scope: {
opts: '=', // Component Options object
groups: '=', // Groups of Component Options
mass: '=', // Current ship mass
s: '=', // Current Slot
warning: '=' // Check warning function
},
link: function(scope, element) {
var list = [];
var cid = scope.s.id; // Slot's current component id
var component = scope.s.c; // Slot's Current Component (may be null/undefined)
var opts = scope.opts;
var groups = scope.groups;
var mass = (scope.mass ? scope.mass : 0) - (component && component.mass ? component.mass : 0); // Mass minus the currently selected component
if (groups) {
// At present time slots with grouped options (Hardpoints and Internal) can be empty
list.push('<div class="empty-c upp" cpid="empty">', $translate.instant('empty'), '</div>');
for (var g in groups) {
var grp = groups[g];
var grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component
list.push('<div id="', grpCode, '" class="select-group cap">', $translate.instant(g), '</div><ul>');
appendGroup(list, grp, cid, mass, scope.warning);
list.push('</ul>');
}
} else {
list.push('<ul>');
appendGroup(list, opts, cid, mass, scope.warning);
list.push('</ul>');
}
element.html(list.join(''));
// If groups are present and a component is already selectd
if (groups && component && component.grp) {
var groupElement = angular.element(document.getElementById(component.grp));
var parentElem = element[0].parentElement;
parentElem.scrollTop = groupElement[0].offsetTop; // Scroll to currently selected group
}
}
};
}]);

View File

@@ -1,14 +0,0 @@
angular.module('app').directive('contextMenu', ['$parse', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.contextMenu);
element.bind('contextmenu', function(e) {
if (!e.shiftKey) {
scope.$apply(function() {
e.preventDefault();
fn(scope, { $event: e });
});
}
});
};
}]);

View File

@@ -1,114 +0,0 @@
angular.module('app').directive('shipyardHeader', ['lodash', '$window', '$rootScope', '$state', 'Persist', 'Serializer', 'ShipsDB', function(_, $window, $rootScope, $state, Persist, Serializer, ships) {
return {
restrict: 'E',
templateUrl: 'views/_header.html',
scope: true,
link: function(scope) {
scope.openedMenu = null;
scope.ships = ships;
scope.allBuilds = Persist.builds;
scope.buildsList = Object.keys(scope.allBuilds).sort();
scope.allComparisons = Object.keys(Persist.comparisons).sort();
scope.bs = Persist.state;
var win = angular.element($window); // Angularized window object for event triggering
var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance());
var savedDiscounts = Persist.getDiscount() || [1, 1];
$rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0];
$rootScope.discounts.ship = savedDiscounts[0];
$rootScope.discounts.components = savedDiscounts[1];
/**
* Save selected insurance option
*/
scope.updateInsurance = function() {
Persist.setInsurance($rootScope.insurance.current.name);
};
/**
* Save selected discount option
*/
scope.updateDiscount = function() {
Persist.setDiscount([$rootScope.discounts.ship, $rootScope.discounts.components]);
$rootScope.$broadcast('discountChange');
};
scope.backup = function(e) {
e.preventDefault();
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'backup',
data: Persist.getAll(),
description: 'PHRASE_BACKUP_DESC'
});
};
scope.detailedExport = function(e) {
e.preventDefault();
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'detailed export',
data: Serializer.toDetailedExport(scope.allBuilds),
description: 'PHRASE_EXPORT_DESC'
});
};
scope.cleanedBuildList = function(shipId) {
return Object.keys(scope.allBuilds[shipId]);
};
scope.openMenu = function(e, menu) {
e.stopPropagation();
if (menu == scope.openedMenu) {
scope.openedMenu = null;
return;
}
if ((menu == 'comp' || menu == 'b') && !scope.bs.hasBuilds) {
scope.openedMenu = null;
return;
}
if (menu == 'comp') {
scope.allComparisons = Object.keys(Persist.comparisons).sort();
}
scope.openedMenu = menu;
};
// Close menus if a navigation change event occurs
$rootScope.$on('$stateChangeStart', function() {
scope.openedMenu = null;
});
// Listen to close event to close opened menus or modals
$rootScope.$on('close', function() {
scope.openedMenu = null;
});
scope.textSizeChange = function(size) {
if (size != $rootScope.sizeRatio) {
$rootScope.sizeRatio = size;
document.getElementById('main').style.fontSize = size + 'em';
Persist.setSizeRatio(size);
win.triggerHandler('resize');
}
};
scope.resetTextSize = function() {
if ($rootScope.sizeRatio != 1) {
scope.textSizeChange(1);
scope.$broadcast('reset', 1);
}
};
scope.$watchCollection('allBuilds', function() {
scope.buildsList = Object.keys(scope.allBuilds).sort();
});
}
};
}]);

View File

@@ -1,247 +0,0 @@
angular.module('app').directive('lineChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
var RENDER_POINTS = 20; // Only render 20 points on the graph
return {
restrict: 'A',
scope: {
config: '=',
series: '='
},
link: function(scope, element) {
var seriesConfig = scope.series,
series = seriesConfig.series,
color = d3.scale.ordinal().range(scope.series.colors ? scope.series.colors : ['#ff8c0d']),
config = scope.config,
labels = config.labels,
margin = { top: 15, right: 15, bottom: 35, left: 60 },
fmtLong = null,
func = seriesConfig.func,
drag = d3.behavior.drag(),
dragging = false,
// Define Scales
x = d3.scale.linear(),
y = d3.scale.linear(),
// Define Axes
xAxis = d3.svg.axis().scale(x).outerTickSize(0).orient('bottom'),
yAxis = d3.svg.axis().scale(y).ticks(6).outerTickSize(0).orient('left'),
data = [];
// Create chart
var svg = d3.select(element[0]).append('svg');
var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var lines = vis.append('g');
// Define Area
var line = d3.svg.line().y(function(d) { return y(d[1]); });
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('class', 'cap')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle');
// xTxt.append('tspan').attr('class', 'metric');
// yTxt.append('tspan').attr('class', 'metric');
// Create and Add tooltip
var tipHeight = 2 + (1.25 * (series ? series.length : 0.75));
var tips = vis.append('g').style('display', 'none').attr('class', 'tooltip');
var markers = vis.append('g').style('display', 'none');
tips.append('rect')
.attr('height', tipHeight + 'em')
.attr('y', (-tipHeight / 2) + 'em')
.attr('class', 'tip');
tips.append('text')
.attr('class', 'label x')
.attr('dy', (-tipHeight / 2) + 'em')
.attr('y', '1.25em');
var background = vis.append('rect') // Background to capture hover/drag
.attr('fill-opacity', 0)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
updateFormats();
function render() {
var width = element[0].parentElement.offsetWidth,
height = width * 0.5 * $rootScope.sizeRatio,
xMax = seriesConfig.xMax,
xMin = seriesConfig.xMin,
yMax = seriesConfig.yMax,
yMin = seriesConfig.yMin,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom,
c, s, val, yVal, delta;
data.length = 0; // Reset Data array
if (seriesConfig.xMax == seriesConfig.xMin) {
line.x(function(d, i) { return i * w; });
} else {
line.x(function(d) { return x(d[0]); });
}
if (series) {
for (s = 0; s < series.length; s++) {
data.push([]);
}
if (xMax == xMin) {
yVal = func(xMin);
for (s = 0; s < series.length; s++) {
data[s].push( [ xMin, yVal[ series[s] ] ], [ 1, yVal[ series[s] ] ]);
}
} else {
delta = (xMax - xMin) / RENDER_POINTS;
val = 0;
for (c = 0; c <= RENDER_POINTS; c++) {
yVal = func(val);
for (s = 0; s < series.length; s++) {
data[s].push([ val, yVal[ series[s] ] ]);
}
val += delta;
}
}
} else {
var seriesData = [];
if (xMax == xMin) {
yVal = func(xMin);
seriesData.push([ xMin, yVal ], [ 1, yVal ]);
} else {
delta = (xMax - xMin) / RENDER_POINTS;
val = 0;
for (c = 0; c <= RENDER_POINTS; c++) {
seriesData.push([val, func(val) ]);
val += delta;
}
}
data.push(seriesData);
}
// Update Chart Size
svg.attr('width', width).attr('height', height);
background.attr('height', h).attr('width', w);
// Update domain and scale for axes
x.range([0, w]).domain([xMin, xMax]).clamp(true);
xLbl.attr('transform', 'translate(0,' + h + ')');
xTxt.attr('x', w / 2);
y.range([h, 0]).domain([yMin, yMax]);
yTxt.attr('x', -h / 2);
vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').call(xAxis);
lines.selectAll('path.line')
.data(data)
.attr('d', line) // Update existing series
.enter() // Add new series
.append('path')
.attr('class', 'line')
.attr('stroke', function(d, i) { return color(i); })
.attr('stroke-width', 2)
.attr('d', line);
tips.selectAll('text.label.y').data(data).enter()
.append('text')
.attr('class', 'label y')
.attr('dy', (-tipHeight / 2) + 'em')
.attr('y', function(d, i) { return 1.25 * (i + 2) + 'em'; });
markers.selectAll('circle.marker').data(data).enter().append('circle').attr('class', 'marker').attr('r', 4);
}
function showTip() {
tips.style('display', null);
markers.style('display', null);
}
function hideTip() {
if (!dragging) {
tips.style('display', 'none');
markers.style('display', 'none');
}
}
function moveTip() {
var xPos = d3.mouse(this)[0],
x0 = x.invert(xPos),
y0 = func(x0),
yTotal = 0,
flip = (x0 / x.domain()[1] > 0.65),
tipWidth = 0,
minTransY = (tips.selectAll('rect').node().getBoundingClientRect().height / 2) - margin.top;
tips.selectAll('text.label.y').text(function(d, i) {
var yVal = series ? y0[series[i]] : y0;
yTotal += yVal;
return (series ? $translate.instant(series[i]) : '') + ' ' + fmtLong(yVal);
}).append('tspan').attr('class', 'metric').text(' ' + $translate.instant(labels.yAxis.unit));
tips.selectAll('text').each(function() {
if (this.getBBox().width > tipWidth) {
tipWidth = Math.ceil(this.getBBox().width);
}
});
tipWidth += 8;
markers.selectAll('circle.marker').attr('cx', x(x0)).attr('cy', function(d, i) { return y(series ? y0[series[i]] : y0); });
tips.selectAll('text.label').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
tips.selectAll('text.label.x').text(fmtLong(x0)).append('tspan').attr('class', 'metric').text(' ' + $translate.instant(labels.xAxis.unit));
tips.attr('transform', 'translate(' + x(x0) + ',' + Math.max(minTransY, y(yTotal / (series ? series.length : 1))) + ')');
tips.selectAll('rect')
.attr('width', tipWidth + 4)
.attr('x', flip ? -tipWidth - 12 : 8)
.style('text-anchor', flip ? 'end' : 'start');
}
function updateFormats() {
xTxt.text($translate.instant(labels.xAxis.title)).append('tspan').attr('class', 'metric').text(' (' + $translate.instant(labels.xAxis.unit) + ')');
yTxt.text($translate.instant(labels.yAxis.title)).append('tspan').attr('class', 'metric').text(' (' + $translate.instant(labels.yAxis.unit) + ')');
fmtLong = $rootScope.localeFormat.numberFormat('.2f');
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
yAxis.tickFormat($rootScope.localeFormat.numberFormat('.3r'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('series', render); // Watch for changes in the series data
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
});
}
};
}]);

View File

@@ -1,9 +0,0 @@
angular.module('app').directive('loader', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.addClass('loader');
element.html('<svg viewbox="0 0 40 40" width="100%" height="100%"><path d="m5,8l5,8l5,-8z" class="l1 d1" /><path d="m5,8l5,-8l5,8z" class="l1 d2" /><path d="m10,0l5,8l5,-8z" class="l1 d3" /><path d="m15,8l5,-8l5,8z" class="l1 d4" /><path d="m20,0l5,8l5,-8z" class="l1 d5" /><path d="m25,8l5,-8l5,8z" class="l1 d6" /><path d="m25,8l5,8l5,-8z" class="l1 d7" /><path d="m30,16l5,-8l5,8z" class="l1 d8" /><path d="m30,16l5,8l5,-8z" class="l1 d9" /><path d="m25,24l5,-8l5,8z" class="l1 d10" /><path d="m25,24l5,8l5,-8z" class="l1 d11" /><path d="m20,32l5,-8l5,8z" class="l1 d13" /><path d="m15,24l5,8l5,-8z" class="l1 d14" /><path d="m10,32l5,-8l5,8z" class="l1 d15" /><path d="m5,24l5,8l5,-8z" class="l1 d16" /><path d="m5,24l5,-8l5,8z" class="l1 d17" /><path d="m0,16l5,8l5,-8z" class="l1 d18" /><path d="m0,16l5,-8l5,8z" class="l1 d20" /><path d="m10,16l5,-8l5,8z" class="l2 d0" /><path d="m15,8l5,8l5,-8z" class="l2 d3" /><path d="m20,16l5,-8l5,8z" class="l2 d6" /><path d="m20,16l5,8l5,-8z" class="l2 d9" /><path d="m15,24l5,-8l5,8z" class="l2 d12" /><path d="m10,16l5,8l5,-8z" class="l2 d15" /></svg>');
}
};
});

View File

@@ -1,209 +0,0 @@
angular.module('app').directive('powerBands', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
return {
restrict: 'A',
scope: {
bands: '=',
available: '='
},
link: function(scope, element) {
var bands = null,
available = 0,
maxBand,
maxPwr,
deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
wattScale = d3.scale.linear(),
pctScale = d3.scale.linear().domain([0, 1]),
wattFmt,
pctFmt,
wattAxis = d3.svg.axis().scale(wattScale).outerTickSize(0).orient('top'),
pctAxis = d3.svg.axis().scale(pctScale).outerTickSize(0).orient('bottom'),
// Create chart
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g'),
deployed = vis.append('g').attr('class', 'power-band'),
retracted = vis.append('g').attr('class', 'power-band');
svg.on('contextmenu', function() {
if (!d3.event.shiftKey) {
d3.event.preventDefault();
for (var i = 0, l = bands.length; i < l; i++) {
bands[i].retSelected = false;
bands[i].depSelected = false;
}
dataChange();
}
});
// Create Y Axis SVG Elements
var wattAxisGroup = vis.append('g').attr('class', 'watt axis');
vis.append('g').attr('class', 'pct axis');
var retText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var depText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var retLbl = vis.append('text').attr('dy', '0.5em');
var depLbl = vis.append('text').attr('dy', '0.5em');
updateFormats(true);
function dataChange() {
bands = scope.bands;
available = scope.available;
maxBand = bands[bands.length - 1];
deployedSum = 0;
retractedSum = 0;
retBandsSelected = false;
depBandsSelected = false;
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
for (var b = 0, l = bands.length; b < l; b++) {
if (bands[b].retSelected) {
retractedSum += bands[b].retracted + bands[b].retOnly;
retBandsSelected = true;
}
if (bands[b].depSelected) {
deployedSum += bands[b].deployed + bands[b].retracted;
depBandsSelected = true;
}
}
render();
}
function render() {
var size = $rootScope.sizeRatio,
mTop = Math.round(25 * size),
mRight = Math.round(130 * size),
mBottom = Math.round(25 * size),
mLeft = Math.round(45 * size),
barHeight = Math.round(20 * size),
width = element[0].offsetWidth,
innerHeight = (barHeight * 2) + 2,
height = innerHeight + mTop + mBottom,
w = width - mLeft - mRight,
repY = (barHeight / 2),
depY = (barHeight * 1.5) - 1;
// Update chart size
svg.attr('width', width).attr('height', height);
vis.attr('transform', 'translate(' + mLeft + ',' + mTop + ')');
// Remove existing elements
retracted.selectAll('rect').remove();
retracted.selectAll('text').remove();
deployed.selectAll('rect').remove();
deployed.selectAll('text').remove();
wattAxisGroup.selectAll('line.threshold').remove();
// Update X & Y Axis
wattScale.range([0, w]).domain([0, maxPwr]).clamp(true);
pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true);
wattAxisGroup.call(wattAxis);
vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis);
var pwrWarningClass = 'threshold' + (bands[0].retractedSum * 2 >= available ? ' exceeded' : '');
vis.select('.pct.axis g:nth-child(6)').selectAll('line, text').attr('class', pwrWarningClass);
wattAxisGroup.append('line')
.attr('x1', pctScale(0.5))
.attr('x2', pctScale(0.5))
.attr('y1', 0)
.attr('y2', innerHeight)
.attr('class', pwrWarningClass);
retText.attr('y', repY);
depText.attr('y', depY);
updateLabel(retLbl, w, repY, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
updateLabel(depLbl, w, depY, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
retracted.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.retracted + d.retOnly), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly), 0)); })
.attr('y', 1)
.on('click', function(d) {
d.retSelected = !d.retSelected;
dataChange();
})
.attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); });
retracted.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted + d.retOnly) / 2); })
.attr('y', repY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.retSelected = !d.retSelected;
dataChange();
})
.text(function(d, i) { return bandText(d.retracted + d.retOnly, i); });
deployed.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.deployed + d.retracted), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed), 0)); })
.attr('y', barHeight + 1)
.on('click', function(d) {
d.depSelected = !d.depSelected;
dataChange();
})
.attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available); });
deployed.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); })
.attr('y', depY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.depSelected = !d.depSelected;
dataChange();
})
.text(function(d, i) { return bandText(d.deployed + d.retracted, i); });
}
function updateLabel(lbl, width, y, selected, sum, avail) {
lbl
.attr('x', width + 5 )
.attr('y', y)
.attr('class', getClass(selected, sum, avail))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / avail)) + ')');
}
function getClass(selected, sum, avail) {
// Round to avoid floating point precision errors
return selected ? 'secondary' : ((Math.round(sum * 100) / 100) >= avail) ? 'warning' : 'primary';
}
function bandText(val, index) {
if (val > 0 && wattScale(val) > 13) {
return index + 1;
}
return '';
}
function updateFormats(preventRender) {
retText.text($translate.instant('ret'));
depText.text($translate.instant('dep'));
wattFmt = $rootScope.localeFormat.numberFormat('.2f');
pctFmt = $rootScope.localeFormat.numberFormat('.1%');
wattAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
pctAxis.tickFormat($rootScope.localeFormat.numberFormat('%'));
if (!preventRender) {
render();
}
}
// Watch for changes to data and events
angular.element($window).bind('pwrchange', dataChange);
angular.element($window).bind('orientationchange resize', render);
scope.$watchCollection('available', dataChange);
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize pwrchange', render);
});
}
};
}]);

View File

@@ -1,90 +0,0 @@
angular.module('app').directive('slider', ['$window', function($window) {
return {
restrict: 'A',
scope: {
min: '=',
def: '=',
max: '=',
unit: '=',
change: '&onChange',
ignoreResize: '='
},
link: function(scope, element) {
var unit = scope.unit,
margin = unit ? { top: -10, right: 145, left: 50 } : { top: 0, right: 10, left: 10 },
height = unit ? 40 : 20, // Height is fixed
h = height - margin.top,
fmt = d3.format('.2f'),
pct = d3.format('.1%'),
def = scope.def !== undefined ? scope.def : scope.max,
val = def,
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
xAxisContainer = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'),
x = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom').tickFormat(function(d) { return d + unit; }).tickSize(0).tickPadding(12),
slider = vis.append('g').attr('class', 'slider'),
filled = slider.append('path').attr('class', 'filled').attr('transform', 'translate(0,' + h / 2 + ')'),
brush = d3.svg.brush().x(x).extent([scope.max, scope.max]).on('brush', brushed),
handle = slider.append('circle').attr('class', 'handle').attr('r', '0.6em'),
lbl = unit ? slider.append('g').append('text').attr('y', h / 2) : null;
slider.call(brush);
slider.select('.background').attr('height', h);
handle.attr('transform', 'translate(0,' + h / 2 + ')');
function render() {
var width = element[0].offsetWidth, w = width - margin.left - margin.right;
svg.attr('width', width).attr('height', height);
x.domain([scope.min || 0, scope.max]).range([0, w]).clamp(true);
handle.attr('cx', x(val));
if (unit) {
xAxisContainer.call(xAxis.tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max]));
lbl.attr('x', w + 20);
}
slider.call(brush.extent([val, val]));
drawBrush();
slider.selectAll('.extent,.resize').remove();
}
function brushed() {
val = x.invert(d3.mouse(this)[0]);
brush.extent([val, val]);
scope.change({ val: val });
drawBrush();
}
function drawBrush() {
if (unit) {
lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max));
}
handle.attr('cx', x(val));
filled.attr('d', 'M0,0V0H' + x(val) + 'V0');
}
/**
* Watch for changes in the max, window size
*/
scope.$watch('max', function(newMax, oldMax) {
val = newMax * (val / oldMax); // Retain percentage filled
scope.change({ val: val });
render();
});
if (!scope.ignoreResize) {
angular.element($window).bind('orientationchange resize', render);
}
scope.$on('reset', function(e, resetVal) {
val = resetVal;
drawBrush();
});
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
});
}
};
}]);

View File

@@ -1,13 +0,0 @@
angular.module('app').directive('slotHardpoint', ['$rootScope', function($r) {
return {
restrict: 'A',
scope: {
hp: '=',
size: '='
},
templateUrl: 'views/_slot-hardpoint.html',
link: function(scope) {
scope.$r = $r;
}
};
}]);

View File

@@ -1,13 +0,0 @@
angular.module('app').directive('slotInternal', ['$rootScope', function($r) {
return {
restrict: 'A',
scope: {
c: '=slot',
fuel: '='
},
templateUrl: 'views/_slot-internal.html',
link: function(scope) {
scope.$r = $r;
}
};
}]);

View File

@@ -1,65 +0,0 @@
/**
* BBCode Generator functions for embedding in the Elite Dangerous Forums
*/
angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', '$translate', '$rootScope', function($window, $state, $http, $q, $translate, $rootScope) {
var shortenAPI = 'https://www.googleapis.com/urlshortener/v1/url?key=';
function shortenUrl(url) {
if ($window.navigator.onLine) {
return $http.post(shortenAPI + GAPI_KEY, { longUrl: url }).then(function(response) {
return response.data.id;
});
} else {
return $q.reject({ statusText: 'Not Online' });
}
}
function comparisonBBCode(facets, builds, link) {
var colCount = 2, b, i, j, k, f, fl, p, pl, l = [];
for (i = 0; i < facets.length; i++) {
if (facets[i].active) {
f = facets[i];
p = f.props;
if (p.length == 1) {
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
} else {
for (j = 0; j < p.length; j++) {
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '\n', $translate.instant(f.lbls[j]).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
}
}
}
}
l.push('[/tr]\n');
for (i = 0; i < builds.length; i++) {
b = builds[i];
//var href = $state.href('outfit',{shipId: b.id, code: b.code, bn: b.buildName}, {absolute: true});
l.push('[tr][td]', b.name, '[/td][td]', b.buildName, '[/td]');
for (j = 0, fl = facets.length; j < fl; j++) {
if (facets[j].active) {
f = facets[j];
p = f.props;
for (k = 0, pl = p.length; k < pl; k++) {
l.push('[td="align: right"]', $rootScope[f.fmt](b[p[k]]), ' [size=-2]', $translate.instant(f.unit), '[/size][/td]');
}
}
}
l.push('[/tr]\n');
}
l.push('[tr][td="align: center, colspan:', colCount, '"][size=-3]\n[url=', link, ']Interactive Comparison at Coriolis.io[/url][/td][/tr]\n[/size][/table]');
l.unshift('[table="width:', colCount * 90, ',align: center"]\n[tr][th][B][COLOR=#FF8C0D]Ship[/COLOR][/B][/th][th][B][COLOR="#FF8C0D"]Build[/COLOR][/B][/th]');
return l.join('');
}
return {
comparisonBBCode: comparisonBBCode,
shortenUrl: shortenUrl
};
}]);

View File

@@ -1,220 +0,0 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('de', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, der %e. %B %Y, %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
});
$translateProvider.translations('de', {
PHRASE_EXPORT_DESC: 'Ein detaillierter JSON-Export Ihrer Konfiguration für die Verwendung in anderen Websites und Tools',
'A-Rated': 'A-Klasse',
about: 'Über',
action: 'Aktion',
added: 'Hinzugefügt',
Advanced: 'Verbessert',
'Advanced Discovery Scanner': 'Fortgeschrittener Aufklärungsscanner',
agility: 'Manövrierbarkeit',
ammo: 'Munition',
PHRASE_CONFIRMATION: 'Sind Sie sicher?',
armour: 'Panzerung',
am: 'Automatische Feldwartungs-Einheit',
available: 'Verfügbar',
backup: 'Sicherungsdatei',
'Basic Discovery Scanner': 'Einfacher Aufklärungsscanner',
bl: 'Strahlenlaser',
beta: 'Beta',
bins: 'Behälter',
boost: 'Boost',
build: 'Ausstattung',
'build name': 'Ausstattungsname',
builds: 'Ausstattungen',
bh: 'Rumpfhüllenverstärkung',
ul: 'Salvenlaser',
buy: 'Kaufen',
cancel: 'Abbrechen',
c: 'Kanone',
capital: 'Kapital',
cargo: 'Fracht',
'Cargo Hatch': 'Frachtluke',
cr: 'Frachtgestell',
cs: 'Frachtscanner',
cells: 'Zellen',
'Chaff Launcher': 'Düppel-Werfer',
close: 'Schließen',
cc: 'Krallensteuerung: Sammler',
compare: 'Vergleichen',
'compare all': 'Alles Vergleichen',
comparison: 'Vergleich',
comparisons: 'Vergleiche',
component: 'Komponente',
cost: 'Preis',
costs: 'Kosten',
cm: 'Gegenmaßnahme',
create: 'Erstellen',
'create new': 'Neu Erstellen',
Cytoscrambler: 'Zytostreuer',
damage: 'Schaden',
delete: 'Löschen',
'delete all': 'Alles Löschen',
dep: 'Ausg',
deployed: 'Ausgefahren',
'detailed export': 'Detailierter Export',
'Detailed Surface Scanner': 'Detailoberflächenscanner',
disabled: 'Deaktiviert',
discount: 'Rabatt',
Distruptor: 'Disruptor',
dc: 'Standard-Landecomputer',
done: 'Fertig',
'edit data': 'Bearbeiten',
efficiency: 'Effizienz',
'Electronic Countermeasure': 'Elektronische Gegenmaßnahme',
empty: 'leer',
Enforcer: 'Vollstrecker',
ENG: 'ANT',
'enter name': 'Namen eingeben',
export: 'Export',
fixed: 'Fixiert',
forum: 'Forum',
fc: 'Splitterkanone',
fd: 'Frameshiftantrieb',
ws: 'Frameshift-Sogwolkenscanner',
FSD: 'FSA',
fi: 'FSA-Unterbrecher',
fuel: 'Treibstoff',
fs: 'Treibstoffsammler',
ft: 'Treibstofftank',
fx: 'Krallensteuerung Treibstoffstransfer',
'full tank': 'Tank voll',
Gimballed: 'Kardanisch',
H: 'R',
hardpoints: 'Waffenaufhängungen',
hb: 'Krallen-Steuereinheit (Ladelukenöffner)',
'Heat Sink Launcher': 'Kühlkörperwerfer',
huge: 'Riesig',
hull: 'Hülle',
hr: 'Rumpfhüllenverstärkung (Paket)',
'Imperial Hammer': 'Imperialer Hammer',
import: 'Importieren',
'import all': 'Alles Importieren',
insurance: 'Versicherung',
'Intermediate Discovery Scanner': 'Mittlerer Aufklärungsscanner',
'internal compartments': 'Innenbereichskabine',
'jump range': 'Sprungreichweite',
jumps: 'Sprünge',
kw: 'Tötungsbefehl-Scanner',
L: 'G',
laden: 'Beladen',
language: 'Sprache',
large: 'Groß',
limpets: 'Krallen',
ls: 'Lebenserhaltung',
'Lightweight Alloy': 'Leichte Legierung',
'lock factor': 'Massensperrefaktor',
LS: 'Ls',
LY: 'Lj',
mass: 'Masse',
'max mass': 'maximale Masse',
medium: 'Mittel',
'Military Grade Composite': 'Militär-Komposit',
nl: 'Minenwerfer',
'Mining Lance': 'Lanzenabbaulaser',
ml: 'Abbaulaser',
'Mirrored Surface Composite': 'Gespiegelte-Oberfläche-Komposit',
mr: 'Raketenbatterie',
mc: 'Mehrfachgeschütz',
'net cost': 'Nettokosten',
no: 'Nein',
PHRASE_NO_BUILDS: 'Keine Konfigurationen zum Vergleich ausgewählt!',
PHRASE_NO_RETROCH: 'Keine Umrüständerungen',
none: 'Nichts',
'none created': 'Leer',
off: 'Aus',
on: 'An',
'optimal mass': 'optimale Masse',
'optimize mass': 'Masse optimieren',
overwrite: 'Überschreiben',
Pacifier: 'Friedensstifter',
'Pack-Hound': 'Schwarmwerfer',
PHRASE_IMPORT: 'JSON hier einfügen oder importieren',
pen: 'Durchdr.',
penetration: 'Durchdringung',
permalink: 'Permalink',
pa: 'Plasmabeschleuniger',
'Point Defence': 'Punktverteidigung',
power: 'Energie',
pd: 'Energieverteiler',
pp: 'Kraftwerk',
pri: 'Prio',
priority: 'Priorität',
psg: 'Prismaschildgenerator',
proceed: 'Fortfahren',
pc: 'Krallensteuerung: Erzsucher',
pl: 'Impulslaser',
PWR: 'En',
rg: 'Schienenkanone',
range: 'Reichweite',
rate: 'Rate',
'Reactive Surface Composite': 'Reaktive-Oberfläche-Komposit',
recharge: 'Aufladen',
rf: 'Raffinerie',
'refuel time': 'Auftankzeit',
'Reinforced Alloy': 'Verstärkte Legierung',
reload: 'Aktualisieren',
rename: 'Umbenennen',
repair: 'Reparieren',
reset: 'Zurücksetzen',
ret: 'Eing',
retracted: 'Eingefahren',
'retrofit costs': 'Änderungskosten',
'retrofit from': 'Nachrüsten von',
ROF: 'Kad',
S: 'K',
save: 'Speichern',
sc: 'Scanner',
PHRASE_SELECT_BUILDS: 'Ausstattung zum Vergleich auswählen',
sell: 'Verkaufen',
s: 'Sensoren',
settings: 'Einstellungen',
sb: 'Schild-Booster',
scb: 'Schildzellenbank',
sg: 'Schildgenerator',
shields: 'Schilde',
ship: 'Schiff',
ships: 'Schiffe',
shortened: 'Gekürzt',
size: 'Größe',
skip: 'Überspringen',
small: 'Klein',
speed: 'Geschwindigkeit',
standard: 'Standard',
'Standard Docking Computer': 'Standard-Landecomputer',
Stock: 'Standard',
T: 't',
T_LOAD: 'T-Lad',
'The Retributor': 'Retributor',
t: 'Schubdüsen',
time: 'Dauer',
tp: 'Torpedoaufhängung',
total: 'Gesamt',
'total range': 'Maximale Reichweite',
turret: 'Geschützturm',
type: 'Typ',
U: 'W',
unladen: 'Unbeladen',
PHRASE_UPDATE_RDY: 'Update verfügbar! Klicken zum Aktualisieren',
utility: 'Werkzeug',
'utility mounts': 'Werkzeug-Steckplätze',
WEP: 'WAF',
yes: 'Ja',
PHRASE_BACKUP_DESC: 'Export aller Coriolis-Daten, um sie zu sichern oder oder um sie zu einem anderen Browser/Gerät zu übertragen.'
});
}]);

View File

@@ -1,219 +0,0 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider.translations('en', {
PHRASE_EXPORT_DESC: 'A detailed JSON export of your build for use in other sites and tools',
'A-Rated': 'A-Rated',
about: 'about',
action: 'action',
added: 'added',
Advanced: 'Advanced',
'Advanced Discovery Scanner': 'Advanced Discovery Scanner',
agility: 'agility',
alpha: 'alpha',
ammo: 'ammo',
PHRASE_CONFIRMATION: 'Are You Sure?',
armour: 'armour',
am: 'Auto Field-Maintenance Unit',
available: 'available',
backup: 'backup',
'Basic Discovery Scanner': 'Basic Discovery Scanner',
bl: 'Beam Laser',
beta: 'beta',
bins: 'bins',
boost: 'boost',
build: 'build',
'build name': 'Build Name',
builds: 'builds',
bh: 'bulkheads',
'bsg': 'Bi-Weave Shield Generator',
ul: 'Burst Laser',
buy: 'buy',
cancel: 'cancel',
c: 'Cannon',
capital: 'capital',
cargo: 'cargo',
'Cargo Hatch': 'Cargo Hatch',
cr: 'Cargo Rack',
cs: 'Cargo Scanner',
cells: 'cells',
'Chaff Launcher': 'Chaff Launcher',
close: 'close',
cc: 'Collector Limpet Controller',
compare: 'compare',
'compare all': 'compare all',
comparison: 'comparison',
comparisons: 'comparisons',
component: 'component',
cost: 'cost',
costs: 'costs',
cm: 'Countermeasure',
CR: 'CR',
create: 'create',
'create new': 'create new',
credits: 'credits',
Cytoscrambler: 'Cytoscrambler',
damage: 'damage',
delete: 'delete',
'delete all': 'delete all',
dep: 'dep',
deployed: 'deployed',
'detailed export': 'detailed export',
'Detailed Surface Scanner': 'Detailed Surface Scanner',
disabled: 'disabled',
discount: 'discount',
Distruptor: 'Distruptor',
dc: 'Docking Computer',
done: 'done',
DPS: 'DPS',
'edit data': 'edit data',
efficiency: 'efficiency',
'Electronic Countermeasure': 'Electronic Countermeasure',
empty: 'empty',
Enforcer: 'Enforcer',
ENG: 'ENG',
'enter name': 'Enter Name',
EPS: 'EPS',
export: 'export',
fixed: 'fixed',
forum: 'forum',
fc: 'Fragment Cannon',
fd: 'Frame Shift Drive',
ws: 'Frame Shift Wake Scanner',
FSD: 'FSD',
fi: 'FSD Interdictor',
fuel: 'fuel',
fs: 'Fuel Scoop',
ft: 'Fuel Tank',
fx: 'Fuel Transfer Limpet Controller',
'full tank': 'full tank',
Gimballed: 'Gimballed',
H: 'H',
hardpoints: 'hardpoints',
hb: 'Hatch Breaker Limpet Controller',
'Heat Sink Launcher': 'Heat Sink Launcher',
huge: 'huge',
hull: 'hull',
hr: 'Hull Reinforcement Package',
'Imperial Hammer': 'Imperial Hammer',
import: 'import',
'import all': 'import all',
insurance: 'insurance',
'Intermediate Discovery Scanner': 'Intermediate Discovery Scanner',
'internal compartments': 'internal compartments',
'jump range': 'jump range',
jumps: 'jumps',
kw: 'Kill Warrant Scanner',
L: 'L',
laden: 'laden',
language: 'language',
large: 'large',
'limpets': 'Limpets',
ls: 'life support',
'Lightweight Alloy': 'Lightweight Alloy',
'lock factor': 'lock factor',
LS: 'Ls',
LY: 'LY',
M: 'M',
'm/s': 'm/s',
mass: 'mass',
max: 'max',
'max mass': 'max mass',
medium: 'medium',
'Military Grade Composite': 'Military Grade Composite',
nl: 'Mine Launcher',
'Mining Lance': 'Mining Lance',
ml: 'Mining Laser',
'Mirrored Surface Composite': 'Mirrored Surface Composite',
mr: 'Missile Rack',
mc: 'Multi-cannon',
'net cost': 'net cost',
no: 'no',
PHRASE_NO_BUILDS: 'No builds added to comparison!',
PHRASE_NO_RETROCH: 'No Retrofitting changes',
none: 'none',
'none created': 'none created',
off: 'off',
on: 'on',
optimal: 'optimal',
'optimal mass': 'optimal mass',
'optimize mass': 'optimize mass',
overwrite: 'overwrite',
Pacifier: 'Pacifier',
'Pack-Hound': 'Pack-Hound',
PHRASE_IMPORT: 'Paste JSON or import here',
pen: 'pen',
penetration: 'penetration',
permalink: 'permalink',
pa: 'Plasma Accelerator',
'Point Defence': 'Point Defence',
power: 'power',
pd: 'power distributor',
pp: 'power plant',
pri: 'pri',
priority: 'priority',
psg: 'Prismatic Shield Generator',
proceed: 'proceed',
pc: 'Prospector Limpet Controller',
pl: 'Pulse Laser',
pv: 'Planetary Vehicle Hangar',
PWR: 'PWR',
rg: 'Rail Gun',
range: 'range',
rate: 'rate',
'Reactive Surface Composite': 'Reactive Surface Composite',
recharge: 'recharge',
rf: 'Refinery',
'refuel time': 'refuel time',
'Reinforced Alloy': 'Reinforced Alloy',
reload: 'reload',
rename: 'rename',
repair: 'repair',
reset: 'reset',
ret: 'ret',
retracted: 'retracted',
'retrofit costs': 'retrofit costs',
'retrofit from': 'retrofit from',
ROF: 'ROF',
S: 'S',
save: 'save',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Select Builds to Compare',
sell: 'sell',
s: 'sensors',
settings: 'settings',
sb: 'Shield Booster',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
shields: 'shields',
ship: 'ship',
ships: 'ships',
shortened: 'shortened',
size: 'size',
skip: 'skip',
small: 'small',
speed: 'speed',
standard: 'standard',
'Standard Docking Computer': 'Standard Docking Computer',
Stock: 'Stock',
SYS: 'SYS',
T: 'T',
T_LOAD: 't-load',
'The Retributor': 'The Retributor',
t: 'thrusters',
time: 'time',
tp: 'Torpedo Pylon',
total: 'total',
'total range': 'total range',
turret: 'turret',
type: 'type',
U: 'U',
unladen: 'unladen',
PHRASE_UPDATE_RDY: 'Update Available! Click to Refresh',
URL: 'URL',
utility: 'utility',
'utility mounts': 'utility mounts',
version: 'version',
WEP: 'WEP',
yes: 'yes',
PHRASE_BACKUP_DESC: 'Backup of all Coriolis data to save or transfer to another browser/device'
});
}]);

View File

@@ -1,212 +0,0 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('es', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, %e de %B de %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],
shortDays: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb'],
months: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],
shortMonths: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']
});
$translateProvider.translations('es', {
'PHRASE_EXPORT_DESC': 'Una detallada exportaci\u00f3n JSON de tu construcci\u00f3n para usarlo en otros sitios web y herramientas',
'A-Rated': 'Calidad-A',
'about': 'Acerca',
'action': 'Acci\u00f3n',
'added': 'A\u00f1adido',
'Advanced Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n avanzado',
'agility': 'Maniobrabilidad',
'alpha': 'Alfa',
'ammo': 'Munici\u00f3n',
'PHRASE_CONFIRMATION': '\u00bfEst\u00e1s seguro?',
'armour': 'Blindaje',
'am': 'Unidad de auto-reparaciones',
'available': 'Disponible',
'backup': 'Reserva',
'Basic Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n b\u00e1sico',
'bl': 'L\u00e1ser de haz',
'bins': 'contenedores',
'boost': 'incrementar',
'build': 'Construcci\u00f3n',
'build name': 'Nombre de la construcci\u00f3n',
'builds': 'Construcciones',
'bh': 'mamparos',
'ul': 'Laser de r\u00e1fagas',
'buy': 'Comprar',
'cancel': 'Cancelar',
'c': 'Ca\u00f1\u00f3n',
'capital': 'capital',
'cargo': 'Carga',
'Cargo Hatch': 'Compuerta de carga',
'cr': 'Compartimento de carga',
'cs': 'Esc\u00e1ner de carga',
'cells': 'celdas',
'Chaff Launcher': 'Lanzador de birutas',
'close': 'Cerrar',
'cc': 'Controlador de Drones de Recogida',
'compare': 'Comparar',
'compare all': 'comparar todas',
'comparison': 'Comparativa',
'comparisons': 'Comparativas',
'component': 'Componente',
'cost': 'Coste',
'costs': 'Costes',
'cm': 'Contramedidas',
'create': 'Crear',
'create new': 'Crear nuevo',
'credits': 'Cr\u00e9ditos',
'damage': 'Da\u00f1o',
'delete': 'Borrar',
'delete all': 'Borrar todo',
'dep': 'desp',
'deployed': 'Desplegado',
'detailed export': 'Exportacion detallada',
'Detailed Surface Scanner': 'Escaner de exploraci\u00f3n detallada',
'disabled': 'Desactivado',
'discount': 'Descuento',
'dc': 'Ordenador de aterrizaje',
'done': 'Hecho',
'DPS': 'DPS (Da\u00f1o Por Segundo)',
'edit data': 'Editar datos',
'efficiency': 'Eficiencia',
'Electronic Countermeasure': 'Contramedidas electr\u00f3nicas',
'empty': 'Vac\u00edo',
'ENG': 'MOT',
'enter name': 'Introduce el nombre',
'export': 'exportar',
'fixed': 'fijo',
'forum': 'Foro',
'fc': 'Ca\u00f1\u00f3n de fragmentaci\u00f3n',
'fd': 'Motor de salto',
'ws': 'Esc\u00e1ner de Salto',
'fi': 'Interdictor FSD',
'fuel': 'Combustible',
'fs': 'Recolector de Combustible',
'ft': 'Tanque de combustible',
'fx': 'Sistema de Transferencia de Combustilble',
'full tank': 'Tanque lleno',
'Gimballed': 'Card\u00e1n',
'H': 'E',
'hardpoints': 'Montura de armas',
'hb': 'Controlador de Apertura de Bah\u00eda de Carga',
'Heat Sink Launcher': 'Eyector de Acumulador de Calor',
'huge': 'enorme',
'hull': 'Casco',
'hr': 'Sistema de Casco Reforzado',
'import': 'Importar',
'import all': 'Importar todo',
'insurance': 'Seguro',
'Intermediate Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n media',
'internal compartments': 'Compartimentos internos',
'jump range': 'Rango de salto',
'jumps': 'Saltos',
'kw': 'Esc\u00e1ner Detector de Recompensas',
'L': 'G',
'laden': 'Cargada',
'language': 'Idioma',
'large': 'Grande',
'ls': 'Soporte vital',
'Lightweight Alloy': 'Aleaci\u00f3n ligera',
'limpets': 'Drones',
'lock factor': 'factor de bloqueo',
'mass': 'Masa',
'max': 'm\u00e1x',
'max mass': 'Masa m\u00e1xima',
'medium': 'medio',
'Military Grade Composite': 'Blindaje Militar',
'nl': 'Lanzaminas',
'Mining Lance': 'Lanza de miner\u00eda',
'ml': 'L\u00e1ser de miner\u00eda',
'Mirrored Surface Composite': 'Blindaje Reflectante',
'mr': 'Bah\u00eda de Misiles',
'mc': 'Ca\u00f1\u00f3n m\u00faltiple',
'net cost': 'Coste neto',
'PHRASE_NO_BUILDS': '\u00a1No se a\u00f1adieron plantillas para comparaci\u00f3n!',
'PHRASE_NO_RETROCH': 'No hay cambios en los ajutes',
'none': 'Nada',
'none created': 'Nada creado',
'off': 'apagado',
'on': 'encendido',
'optimal': '\u00f3ptimo',
'optimal mass': 'masa \u00f3ptima',
'optimize mass': 'optimizar masa',
'overwrite': 'Sobreescribir',
'PHRASE_IMPORT': 'Pega el JSON o imp\u00f3rtalo aqu\u00ed',
'penetration': 'penetraci\u00f3n',
'permalink': 'enlace permanente',
'pa': 'Acelerador de Plasma',
'Point Defence': 'Punto de Defensa',
'power': 'energ\u00eda',
'pd': 'distribuidor de energ\u00eda',
'pp': 'Planta de Energ\u00eda',
'priority': 'prioridad',
'proceed': 'Proceder',
'pc': 'Controlador de drones de prospecci\u00f3n',
'pl': 'L\u00e1ser de Pulso',
'PWR': 'POT',
'rg': 'Ca\u00f1\u00f3n de Riel',
'range': 'rango',
'rate': 'ratio',
'Reactive Surface Composite': 'Blindaje Reactivo',
'recharge': 'recargar',
'rf': 'Refineria',
'refuel time': 'Tiempo para repostar',
'Reinforced Alloy': 'Armadura reforzada',
'reload': 'Recargar',
'rename': 'Renombrar',
'repair': 'Reparar',
'reset': 'Reiniciar',
'ret': 'PLE',
'retracted': 'plegadas',
'retrofit costs': 'costes de equipamiento',
'retrofit from': 'equipamiento desde',
'ROF': 'RDF',
'S': 'P',
'save': 'guardar',
'sc': 'sc\u00e1ner',
'PHRASE_SELECT_BUILDS': 'Selecciona equipamientos para comparar',
'sell': 'Vender',
's': 'Sensores',
'settings': 'Configuraci\u00f3n',
'sb': 'Potenciador de Escudos',
'scb': 'C\u00e9lula de Energ\u00eda de Escudos',
'sg': 'Generador de escudos',
'shields': 'Escudos',
'ship': 'Nave ',
'ships': 'Naves',
'shortened': 'Abreviado',
'size': 'Tama\u00f1o',
'skip': 'omitir',
'small': 'Peque\u00f1o',
'speed': 'velocidad',
'standard': 'est\u00e1ndar',
'Standard Docking Computer': 'Computador de Atraque Est\u00e1ndar',
'Stock': 'De serie',
'SYS': 'SIS',
'T_LOAD': 'c-t\u00e9rmica',
't': 'Propulsores',
'time': 'Tiempo',
'tp': 'Anclaje de torpedo',
'total': 'Total',
'total range': 'Rango total',
'turret': 'torreta',
'type': 'Tipo',
'unladen': 'Sin carga',
'PHRASE_UPDATE_RDY': 'Actualizacion disponible! Haz click para recargar',
'URL': 'Enlace',
'utility': 'utilidad',
'utility mounts': 'monturas de utilidad',
'version': 'Versi\u00f3n',
'WEP': 'ARM',
'yes': 'si',
'PHRASE_BACKUP_DESC': 'Copia de seguridad de todos los datos de Coriolis para guardarlos o transferirlos a otro navegador\/dispositivo'
});
}]);

View File

@@ -1,200 +0,0 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('fr', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, le %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
shortDays: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
months: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
shortMonths: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
});
$translateProvider.translations('fr', {
PHRASE_EXPORT_DESC: 'Export détaillé en JSON de votre configuration pour utilisation sur d\'autres sites et outils',
'A-Rated': 'Classe-A ',
about: 'à propos',
added: 'ajouté',
Advanced: 'Avancé',
'Advanced Discovery Scanner': 'Détecteur découverte avancé',
agility: 'manœuvrabilité',
ammo: 'munitions',
PHRASE_CONFIRMATION: 'Êtes-vous sûr ?',
armour: 'Armure',
am: 'Unité de maintenance de terrain auto',
available: 'Disponibilité',
backup: 'sauvegarde',
'Basic Discovery Scanner': 'Détecteur découverte simple',
bl: 'Rayon Laser',
bins: 'bennes',
build: 'Configuration',
'build name': 'Nom de la configuration',
builds: 'Configurations',
bh: 'Coque',
ul: 'Laser à rafale',
buy: 'Acheter',
cancel: 'Annuler',
c: 'Canon',
cargo: 'Soute',
'Cargo Hatch': 'Écoutille de soute',
cr: 'Compartiment de soute',
cs: 'Détecteur de cargaison',
cells: 'Cellules',
'Chaff Launcher': 'Lanceur de paillettes',
close: 'fermer',
cc: 'Contrôleur de Collecteur',
compare: 'comparer',
'compare all': 'tout comparer',
comparison: 'comparaison',
comparisons: 'comparaisons',
component: 'composant',
cost: 'coût',
costs: 'coûts',
cm: 'Contre-mesure',
create: 'Créer',
'create new': 'Créer nouveau',
credits: 'crédits',
damage: 'Dégâts',
delete: 'supprimer',
'delete all': 'tout supprimer',
dep: 'depl',
deployed: 'déployé',
'detailed export': 'export détaillé',
'Detailed Surface Scanner': 'Détecteur surface détaillé',
disabled: 'désactivé',
discount: 'réduction',
Distruptor: 'Disrupteur',
dc: 'Ordinateur d\'appontage',
done: 'Valider',
'edit data': 'Editer donnée',
efficiency: 'efficacité',
'Electronic Countermeasure': 'Contre-mesures électroniques',
empty: 'Vide',
'enter name': 'Entrer un nom',
fixed: 'fixé',
fc: 'Canon à fragmentation',
fd: 'Réacteur FSD',
ws: 'Détecteur de sillage FSD',
fi: 'Intercepteur de réacteur FSD',
fuel: 'carburant',
fs: 'Récupérateur de carburant',
ft: 'Réservoir de carburant',
fx: 'Contrôleur de ravitailleur',
'full tank': 'Réservoir plein',
Gimballed: 'Point',
hardpoints: 'Points d\'emport',
hb: 'Contrôle de patelle perce-soute',
'Heat Sink Launcher': 'Éjecteur de dissipateur thermique',
huge: 'Très grand',
hull: 'Coque',
hr: 'Ensemble de mesures permettant de renforcer la coque',
'Imperial Hammer': 'Marteau impérial',
import: 'Importer',
'import all': 'Importer tout',
insurance: 'Assurance',
'Intermediate Discovery Scanner': 'Détecteur découverte intermédiaire',
'internal compartments': 'compartiments internes',
'jump range': 'Distance de saut',
jumps: 'Sauts',
kw: 'Détecteur d\'avis de recherche',
laden: 'chargé',
language: 'Langue',
large: 'large',
ls: 'Systèmes de survie',
'Lightweight Alloy': 'alliage léger',
'limpets': 'Patelles',
'lock factor': 'facteur inhibition de masse',
LS: 'SL',
LY: 'AL',
mass: 'Masse',
'max mass': 'masse max',
'Military Grade Composite': 'Composite militaire',
nl: 'Lance-mines',
'Mining Lance': 'Lance de minage',
ml: 'Laser minier',
'Mirrored Surface Composite': 'Composite à surface miroir',
mr: 'Batterie de missiles',
mc: 'Canon multiple',
'net cost': 'coûts nets',
no: 'non',
PHRASE_NO_BUILDS: 'Aucune configuration ajoutée pour comparaison',
PHRASE_NO_RETROCH: 'Configuration non modifiée',
none: 'aucun',
'none created': 'Rien de créé',
off: 'éteint',
on: 'allumé',
'optimal mass': 'masse optimale',
'optimize mass': 'optimiser masse',
overwrite: 'remplacer',
Pacifier: 'Pacificateur',
PHRASE_IMPORT: 'Coller ici votre JSON à importer',
pen: 'pén.',
penetration: 'pénétration',
permalink: 'lien durable',
pa: 'accélérateur plasma',
'Point Defence': 'Défense ponctuelle',
power: 'énergie',
pd: 'Répartiteur de puissance',
pp: 'Générateur',
priority: 'priorité',
psg: 'générateur de bouclier prisme',
proceed: 'continuer',
pc: 'Contrôleur de prospecteur',
pl: 'Laser à impulsion',
PWR: 'P',
rg: 'Canon électrique',
range: 'portée',
rate: 'cadence',
'Reactive Surface Composite': 'Composite à surface réactive',
recharge: 'recharger',
rf: 'Raffinerie',
'refuel time': 'Temps de remplissage',
'Reinforced Alloy': 'alliage renforcé',
reload: 'recharger',
rename: 'renommer',
repair: 'réparer',
reset: 'Réinitialisation',
ret: 'esc',
retracted: 'escamoté',
'retrofit costs': 'Valeur de rachat',
'retrofit from': 'Racheter de',
ROF: 'cadence',
save: 'sauvegarder',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Sélectionner les configurations à comparer',
sell: 'vendre',
s: 'Capteurs',
settings: 'paramètres',
sb: 'Survolteur de bouclier',
scb: 'Réserve de cellules d\'énergie',
sg: 'Générateur de bouclier',
shields: 'boucliers',
ship: 'vaisseau',
ships: 'vaisseaux',
shortened: 'raccourci',
size: 'taille',
skip: 'Suivant',
small: 'petit',
speed: 'vitesse',
'Standard Docking Computer': 'Ordinateur d\'appontage standard',
Stock: 'de base',
T_LOAD: 'Charge thermique',
'The Retributor': 'Le Rétributeur',
t: 'propulseurs',
time: 'temps',
tp: 'Tube lance-torpille',
'total range': 'Distance maximale',
turret: 'tourelle',
unladen: 'Non chargé',
PHRASE_UPDATE_RDY: 'Mise à jour disponible ! Cliquez ici pour mettre à jour',
utility: 'utilitaire',
'utility mounts': 'Support utilitaire',
WEP: 'ARM',
yes: 'oui',
PHRASE_BACKUP_DESC: 'Exportation détaillée des données de Coriolis pour l\'utilisation dans d\'autres sites et outils'
});
}]);

View File

@@ -1,133 +0,0 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('es', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['€', ''],
dateTime: '%A %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
shortDays: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
shortMonths: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
});
$translateProvider.translations('it', {
PHRASE_EXPORT_DESC: 'Un export dettagliato in formato JSON della tua configurazione per essere usato in altri siti o tools',
'A-Rated': 'Classe A',
about: 'Info su Coriolis',
action: 'azione',
added: 'aggiunto',
Advanced: 'Avanzato',
agility: 'agilità',
ammo: 'munizioni',
PHRASE_CONFIRMATION: 'Sei sicuro ?',
armour: 'armatura',
available: 'disponibile',
bins: 'contenitore',
build: 'configurazione',
'build name': 'Nome Configurazione',
builds: 'configurazioni',
buy: 'compra',
cancel: 'cancella',
cells: 'celle',
close: 'chiudi',
compare: 'confronta',
'compare all': 'confronta tutti',
comparison: 'comparazione',
comparisons: 'comparazioni',
component: 'componente',
cost: 'costo',
costs: 'costi',
cm: 'Contromisure',
create: 'crea',
'create new': 'crea nuovo',
credits: 'crediti',
damage: 'danno',
delete: 'elimina',
'delete all': 'elimina tutto',
dep: 'dep',
deployed: 'deployed',
'detailed export': 'esportazione dettagliata',
disabled: 'disabilita',
discount: 'sconto',
done: 'fatto',
'edit data': 'modifica i dati',
efficiency: 'efficenza',
empty: 'vuoto',
Enforcer: 'Rinforzatore',
'enter name': 'Inserisci un nome',
export: 'esporta',
fixed: 'fissi',
fuel: 'carburante',
'full tank': 'Serbatoio Pieno',
huge: 'enorme',
hull: 'corazza',
import: 'importa',
'import all': 'importa tutto',
insurance: 'assicurazione',
'internal compartments': 'compartimenti interni',
'jump range': 'distanza di salto',
jumps: 'salti',
laden: 'carico',
language: 'lingua',
large: 'largo',
mass: 'massa',
max: 'massimo',
'max mass': 'massa massimale',
medium: 'medio',
'net cost': 'costo netto',
PHRASE_NO_BUILDS: 'nessuna configurazione è stata aggiunta per la comparazione!',
PHRASE_NO_RETROCH: 'Nessun cambiamento di Retrofitting',
none: 'nessuno',
'none created': 'nessuno creato',
optimal: 'ottimale',
'optimal mass': 'massa ottimale',
'optimize mass': 'ottimizza la massa',
overwrite: 'sovrasscrivi',
PHRASE_IMPORT: 'Incolla un JSON o importalo qua',
penetration: 'penetrazione',
power: 'potenza',
priority: 'priorità',
proceed: 'procedi',
range: 'distanza',
rate: 'rateo',
recharge: 'ricarica',
reload: 'ricarica',
rename: 'rinomina',
repair: 'ripara',
reset: 'resetta',
retracted: 'retratti',
'retrofit costs': 'costi di retrofit',
'retrofit from': 'retrofit da',
save: 'salva',
sell: 'vendi',
settings: 'impostazioni',
shields: 'scudi',
ship: 'nave',
ships: 'navi',
shortened: 'accorciato',
size: 'grandezza',
skip: 'salta',
small: 'piccolo',
speed: 'velocità',
Stock: 'appena comprata',
t: 'thrusters',
time: 'tempo',
total: 'totale',
'total range': 'distanza totale',
turret: 'torrette',
type: 'tipo',
unladen: 'scarico',
PHRASE_UPDATE_RDY: 'Aggiornamenti disponibili ! Clicca per Aggiornare',
utility: 'supporti',
'utility mounts': 'supporti di utilità',
version: 'versione',
yes: 'sì',
PHRASE_BACKUP_DESC: 'Esportazione di tutti i dati su Coriolis per salvarli o trasferirli in un altro Browser/dispositivo'
});
}]);

View File

@@ -1,23 +0,0 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider
.useSanitizeValueStrategy('escapeParameters')
.useStorage('Persist')
.fallbackLanguage('en') // Use English as default/fallback language
.registerAvailableLanguageKeys(['en', 'de', 'es', 'fr', 'it', 'ru'], {
'en*': 'en',
'de*': 'de',
'es*': 'es',
'fr*': 'fr',
'it*': 'it',
'ru*': 'ru'
})
.determinePreferredLanguage();
}])
.value('Languages', {
en: 'English',
de: 'Deutsch',
it: 'Italiano',
es: 'Español',
fr: 'Français',
ru: 'ру́сский'
});

View File

@@ -1,234 +0,0 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('ru', {
decimal: ',',
thousands: '\xa0',
grouping: [3],
currency: ['', ' руб.'],
dateTime: '%A, %e %B %Y г. %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
shortDays: ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],
months: ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'],
shortMonths: ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек']
});
$translateProvider.translations('ru', {
PHRASE_EXPORT_DESC: 'Подробный экспорта JSON вашего телосложения для использования в других местах и инструментов',
'A-Rated': 'А-Класса',
about: 'О сайте',
action: 'Действие',
added: 'Добавлено',
Advanced: 'Продвинутый',
'Advanced Discovery Scanner': 'Продвинутый астросканер',
agility: 'Маневренность',
alpha: 'Альфа',
ammo: 'Боекомплект',
PHRASE_CONFIRMATION: 'Вы уверены?',
armour: 'Броня',
am: 'Ремонтный модуль',
available: 'доступно',
backup: 'Резервная копия',
'Basic Discovery Scanner': 'Стандартный исследовательский сканер',
bl: 'Лучевой лазер',
beta: 'Бета',
bins: 'контейнеры',
boost: 'форсаж',
build: 'cборка',
'build name': 'название сборки',
builds: 'cборки',
bh: 'Корпус',
ul: 'Мультиимпульсный лазер',
buy: 'купить',
cancel: 'отменить',
c: 'Пушка',
capital: 'Крупный',
cargo: 'Груз',
'Cargo Hatch': 'Грузовой люк',
cr: 'Грузовой отсек',
cs: 'Сканер груза',
cells: 'Ячейки',
'Chaff Launcher': 'Постановщик помех',
close: 'закрыть',
cc: 'Контроллер "дрон-сборщик"',
compare: 'сравнить ',
'compare all': 'сравнить все',
comparison: 'сравнение',
comparisons: 'сравнения',
component: 'Компонент',
cost: 'Стоимость',
costs: 'Расходы',
cm: 'Контрмеры',
CR: 'кр.',
create: 'создать',
'create new': 'Создать новый',
credits: 'Кредиты',
Cytoscrambler: 'сайтоскрамблер',
damage: 'Урон',
delete: 'Удалить',
'delete all': 'Удалить все',
dep: 'Вып',
deployed: 'Открыты',
'detailed export': 'Подробный экспорт',
'Detailed Surface Scanner': 'Подробный сканер поверхности',
disabled: 'Отключено',
discount: 'Скидка',
Distruptor: 'Дисраптор',
dc: 'Стыковочный компьютер',
done: 'готово',
DPS: 'УВС',
'edit data': 'Редактирование',
efficiency: 'Эффективность',
'Electronic Countermeasure': 'Электронная противомера',
empty: 'пусто',
Enforcer: 'Энфорсер',
ENG: 'ДВГ',
'enter name': 'Введите имя',
EPS: 'ЭВС',
export: 'Экспорт',
fixed: 'Фиксированое',
forum: 'Форум',
fc: 'Осколочное Орудие',
fd: 'Двигатель FSD',
ws: 'FSD Сканнер',
fi: 'Перехватчик FSD',
fuel: 'Топливо',
fs: 'Топливосборщик',
ft: 'Топливный бак',
fx: 'Контроллер Дрона-заправщика',
'full tank': 'Полный бак',
Gimballed: 'Шарнирное',
H: 'O',
hardpoints: 'Орудийные порты',
hb: 'Контроллер "дрон-взломщик"',
'Heat Sink Launcher': 'Теплоотводная ПУ',
huge: 'огромный',
hull: 'Корпус',
hr: 'Набор усиления корпуса',
'Imperial Hammer': 'Имперский Молот',
import: 'импортировать ',
'import all': 'импортировать все',
insurance: 'Страховка',
'Intermediate Discovery Scanner': 'Средний исследовательский сканер',
'internal compartments': 'внутренние отсеки',
'jump range': 'Дальность прыжка',
jumps: 'Прыжков',
kw: 'Полицейский сканер',
L: 'б',
laden: 'Груженый',
language: 'Язык',
large: 'большой',
ls: 'Система жизнеобеспечения',
'Lightweight Alloy': 'Легкий сплав',
'limpets': 'Дроны',
'lock factor': 'Масс. блок',
LS: 'Св.сек',
LY: 'Св.лет',
M: 'С',
'm/s': 'м/с',
mass: 'Масса',
max: 'Макс',
'max mass': 'Максимальная масса',
medium: 'Средний',
'Military Grade Composite': 'Военный композит',
nl: 'Минноукладчик',
'Mining Lance': 'Бурильная сулица',
ml: 'Бурильный лазер',
'Mirrored Surface Composite': 'Зеркальный композит',
mr: 'Ракетная установка',
mc: 'Многоствольное орудие',
'net cost': 'разница в цене',
no: 'Нет',
PHRASE_NO_BUILDS: 'Нечего сравнивать',
PHRASE_NO_RETROCH: 'нет ранних версий сборки\конфигурации',
none: 'ни один',
'none created': 'не создано',
off: 'выкл',
on: 'вкл',
optimal: 'Оптимальный',
'optimal mass': 'Оптимальная масса',
'optimize mass': 'Оптимизировать массу',
overwrite: 'перезаписать',
Pacifier: 'Миротворец',
'Pack-Hound': 'Ракета "Гончая"',
PHRASE_IMPORT: 'Для импорта вставьте код в эту форму',
pen: 'ПБ',
penetration: 'Пробитие',
permalink: 'Постоянная ссылка',
pa: 'Ускоритель плазмы',
'Point Defence': 'Противоракетная защита',
power: 'Мощность',
pd: 'Распределитель энергии',
pp: 'Реактор',
pri: 'Осн',
priority: 'Приоритет',
psg: 'Генератор призматического щита',
proceed: 'продолжить',
pc: 'Контроллер "Дрон-исследователь"',
pl: 'Импульсный лазер',
PWR: 'Эн',
rg: 'Рельсотрон',
range: 'Дальность',
rate: 'скорость',
'Reactive Surface Composite': 'Динамическая защита',
recharge: 'Перезарядка',
rf: 'Переработка',
'refuel time': 'Время дозаправки',
'Reinforced Alloy': 'Усиленный сплав',
reload: 'Перезарядить',
rename: 'Переименовать',
repair: 'Починка',
reset: 'Сброс',
ret: 'Убр.',
retracted: 'Убрано',
'retrofit costs': 'цена модификации',
'retrofit from': 'модификация от',
ROF: 'В/сек',
S: 'М',
save: 'Сохранить',
sc: 'Сканер',
PHRASE_SELECT_BUILDS: 'Выберите конфигурацию для сравнения',
sell: 'Продать',
s: 'Сенсоры',
settings: 'Настройки',
sb: 'Усилитель щита',
scb: 'Батареи перезарядки щита',
sg: 'Генератор щита',
shields: 'Щиты',
ship: 'Корабль',
ships: 'Корабли',
shortened: 'Укороченный',
size: 'размер',
skip: 'пропустить',
small: 'Малый',
speed: 'скорость',
standard: 'Стандартный',
'Standard Docking Computer': 'Стандартный стыковочный компьютер',
Stock: 'Стандартная комплектация',
SYS: 'СИС',
T: 'Т',
T_LOAD: 'Тепл.',
'The Retributor': '"Возмездие"',
t: 'Двигатели',
time: 'Время',
tp: 'Торпедный аппарат',
total: 'Всего',
'total range': 'Общий радиус',
turret: 'Туррель',
type: 'Тип',
U: 'В',
unladen: 'Пустой',
PHRASE_UPDATE_RDY: 'Доступно обновление. Нажмите для обновления.',
URL: 'Ссылка',
utility: 'Вспомогательное',
'utility mounts': 'Вспомогательное оборудование',
version: 'Версия',
WEP: 'ОРУ',
yes: 'Да',
PHRASE_BACKUP_DESC: 'Сохраните все данные перед переносом в другой браузер или устройство'
});
}]);

View File

@@ -1,36 +0,0 @@
angular.module('app').provider('localeFormat', function localeFormatProvider() {
var formats = {
en: {
decimal: '.',
thousands: ',',
grouping: [3],
currency: ['$', ''],
dateTime: '%a %b %e %X %Y',
date: '%m/%d/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
}
};
function LocaleFormat(formatMap) {
this.formatMap = formatMap;
this.get = function(lang) {
return this.formatMap[lang] ? this.formatMap[lang] : this.formatMap.en;
};
}
this.addFormat = function(langCode, formatDetails) {
formats[langCode] = formatDetails;
};
this.$get = [function() {
return new LocaleFormat(formats);
}];
});

View File

@@ -1,314 +0,0 @@
/**
* [description]
*/
angular.module('app').service('Persist', ['$window', 'lodash', function($window, _) {
var LS_KEY_BUILDS = 'builds';
var LS_KEY_COMPARISONS = 'comparisons';
var LS_KEY_LANG = 'NG_TRANSLATE_LANG_KEY';
var LS_KEY_COST_TAB = 'costTab';
var LS_KEY_INSURANCE = 'insurance';
var LS_KEY_DISCOUNTS = 'discounts';
var localStorage = $window.localStorage;
var buildJson = null;
var comparisonJson = null;
// Safe check to determine if localStorage is enabled
try {
localStorage.setItem('s', 1);
localStorage.removeItem('s');
buildJson = localStorage.getItem(LS_KEY_BUILDS);
comparisonJson = localStorage.getItem(LS_KEY_COMPARISONS);
this.lsEnabled = true;
} catch(e) {
this.lsEnabled = false;
}
this.builds = buildJson ? angular.fromJson(buildJson) : {};
this.comparisons = comparisonJson ? angular.fromJson(comparisonJson) : {};
var buildCount = Object.keys(this.builds).length;
this.state = {
buildCount: buildCount,
hasBuilds: buildCount > 0,
hasComparisons: Object.keys(this.comparisons).length > 0
};
this.put = function(name, value) {
if (!this.lsEnabled) {
return;
}
localStorage.setItem(name, value);
};
this.get = function(name) {
return this.lsEnabled ? localStorage.getItem(name) : null;
};
this.getLangCode = function() {
return this.lsEnabled ? localStorage.getItem(LS_KEY_LANG) : null;
};
/**
* Persist a ship build in local storage.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @param {string} code The serialized code
*/
this.saveBuild = function(shipId, name, code) {
if (!this.lsEnabled) {
return;
}
if (!this.builds[shipId]) {
this.builds[shipId] = {};
}
if (!this.builds[shipId][name]) {
this.state.buildCount++;
this.state.hasBuilds = true;
}
this.builds[shipId][name] = code;
// Persist updated build collection to localStorage
localStorage.setItem(LS_KEY_BUILDS, angular.toJson(this.builds));
};
/**
* Get the serialized code/string for a build. Returns null if a
* build is not found.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @return {string} The serialized build string.
*/
this.getBuild = function(shipId, name) {
if (this.builds[shipId] && this.builds[shipId][name]) {
return this.builds[shipId][name];
}
return null;
};
/**
* Delete a build from local storage. It will also delete the ship build collection if
* it becomes empty
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
*/
this.deleteBuild = function(shipId, name) {
if (this.lsEnabled && this.builds[shipId][name]) {
delete this.builds[shipId][name];
if (Object.keys(this.builds[shipId]).length === 0) {
delete this.builds[shipId];
this.state.buildCount--;
this.state.hasBuilds = this.state.buildCount > 0;
}
// Persist updated build collection to localStorage
localStorage.setItem(LS_KEY_BUILDS, angular.toJson(this.builds));
// Check if the build was used in existing comparisons
var comps = this.comparisons;
for (var c in comps) {
for (var i = 0; i < comps[c].builds.length; i++) { // For all builds in the current comparison
if (comps[c].builds[i].shipId == shipId && comps[c].builds[i].buildName == name) {
comps[c].builds.splice(i, 1);
break; // A build is unique ber comparison
}
}
}
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
}
};
/**
* Persist a comparison in localstorage.
*
* @param {string} name The name of the comparison
* @param {array} builds Array of builds
* @param {array} facets Array of facet indices
*/
this.saveComparison = function(name, builds, facets) {
if (!this.lsEnabled) {
return;
}
if (!this.comparisons[name]) {
this.comparisons[name] = {};
}
this.comparisons[name] = {
facets: facets,
builds: _.map(builds, function(b) { return { shipId: b.id || b.shipId, buildName: b.buildName }; })
};
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
this.state.hasComparisons = true;
};
/**
* [getComparison description]
* @param {string} name [description]
* @return {object} Object containing array of facets and ship id + build names
*/
this.getComparison = function(name) {
if (this.comparisons[name]) {
return this.comparisons[name];
}
return null;
};
/**
* Removes the comparison from localstorage.
* @param {string} name Comparison name
*/
this.deleteComparison = function(name) {
if (this.lsEnabled && this.comparisons[name]) {
delete this.comparisons[name];
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
this.state.hasComparisons = Object.keys(this.comparisons).length > 0;
}
};
/**
* Delete all builds and comparisons from localStorage
*/
this.deleteAll = function() {
angular.copy({}, this.builds); // Empty object but keep original instance
angular.copy({}, this.comparisons);
this.state.hasBuilds = false;
this.state.buildCount = 0;
if (this.lsEnabled) {
localStorage.removeItem(LS_KEY_BUILDS);
localStorage.removeItem(LS_KEY_COMPARISONS);
}
};
this.getAll = function() {
var data = {};
data[LS_KEY_BUILDS] = this.builds;
data[LS_KEY_COMPARISONS] = this.comparisons;
data[LS_KEY_INSURANCE] = this.getInsurance();
data[LS_KEY_DISCOUNTS] = this.getDiscount();
return data;
};
/**
* Get the saved insurance type
* @return {string} The name of the saved insurance type of null
*/
this.getInsurance = function() {
if (this.lsEnabled) {
return localStorage.getItem(LS_KEY_INSURANCE);
}
return null;
};
/**
* Persist selected insurance type
* @param {string} name Insurance type name
*/
this.setInsurance = function(name) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_INSURANCE, name);
}
};
/**
* Persist selected discount
* @param {number} val Discount value/amount
*/
this.setDiscount = function(val) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_DISCOUNTS, angular.toJson(val));
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getDiscount = function() {
if (this.lsEnabled) {
return angular.fromJson(localStorage.getItem(LS_KEY_DISCOUNTS));
}
return null;
};
/**
* Persist selected cost tab
* @param {number} val Discount value/amount
*/
this.setCostTab = function(tabName) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_COST_TAB, tabName);
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getCostTab = function() {
if (this.lsEnabled) {
return localStorage.getItem(LS_KEY_COST_TAB);
}
return null;
};
/**
* Retrieve the last router state from local storage
* @return {object} state State object containing state name and params
*/
this.getState = function() {
if (this.lsEnabled) {
var state = localStorage.getItem('state');
if (state) {
return angular.fromJson(state);
}
}
return null;
};
/**
* Save the current router state to localstorage
* @param {object} state State object containing state name and params
*/
this.setState = function(state) {
if (this.lsEnabled) {
localStorage.setItem('state', angular.toJson(state));
}
};
/**
* Retrieve the last router state from local storage
* @return {number} size Ratio
*/
this.getSizeRatio = function() {
if (this.lsEnabled) {
var ratio = localStorage.getItem('sizeRatio');
if (!isNaN(ratio) && ratio > 0.6) {
return ratio;
}
}
return 1;
};
/**
* Save the current size ratio to localstorage
* @param {number} sizeRatio
*/
this.setSizeRatio = function(sizeRatio) {
if (this.lsEnabled) {
localStorage.setItem('sizeRatio', sizeRatio);
}
};
/**
* Check if localStorage is enabled/active
* @return {Boolean} True if localStorage is enabled
*/
this.isEnabled = function() {
return this.lsEnabled;
};
}]);

View File

@@ -1,245 +0,0 @@
/**
* Service managing seralization and deserialization of models for use in URLs and persistene.
*/
angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', 'ShipsDB', 'Ship', 'Components', '$state', function(_, GroupMap, MountMap, ShipsDB, Ship, Components, $state) {
/**
* Serializes the ships selected components for all slots to a URL friendly string.
* @param {Ship} ship The ship to be serialized.
* @return {string} Encoded string of components
*/
this.fromShip = function(ship) {
var power = {
enabled: [ship.cargoHatch.enabled ? 1 : 0],
priorities: [ship.cargoHatch.priority]
};
var data = [
ship.bulkheads.id,
_.map(ship.standard, mapGroup, power),
_.map(ship.hardpoints, mapGroup, power),
_.map(ship.internal, mapGroup, power),
'.',
LZString.compressToBase64(power.enabled.join('')).replace(/\//g, '-'),
'.',
LZString.compressToBase64(power.priorities.join('')).replace(/\//g, '-')
];
return _.flatten(data).join('');
};
/**
* Updates an existing ship instance's slots with components determined by the
* code.
*
* @param {Ship} ship The ship instance to be updated
* @param {string} dataString The string to deserialize
*/
this.toShip = function(ship, dataString) {
var standard = new Array(ship.standard.length),
hardpoints = new Array(ship.hardpoints.length),
internal = new Array(ship.internal.length),
parts = dataString.split('.'),
priorities = null,
enabled = null,
code = parts[0];
if (parts[1]) {
enabled = LZString.decompressFromBase64(parts[1].replace(/-/g, '/')).split('');
}
if (parts[2]) {
priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split('');
}
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, standard, 1)));
ship.buildWith(
{
bulkheads: code.charAt(0) * 1,
standard: standard,
hardpoints: hardpoints,
internal: internal
},
priorities,
enabled
);
};
this.toDetailedBuild = function(buildName, ship, code) {
var standard = ship.standard,
hardpoints = ship.hardpoints,
internal = ship.internal;
var data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/3.json#',
name: buildName,
ship: ship.name,
references: [{
name: 'Coriolis.io',
url: $state.href('outfit', { shipId: ship.id, code: code, bn: buildName }, { absolute: true }),
code: code,
shipId: ship.id
}],
components: {
standard: {
bulkheads: ship.bulkheads.c.name,
cargoHatch: { enabled: Boolean(ship.cargoHatch.enabled), priority: ship.cargoHatch.priority + 1 },
powerPlant: { class: standard[0].c.class, rating: standard[0].c.rating, enabled: Boolean(standard[0].enabled), priority: standard[0].priority + 1 },
thrusters: { class: standard[1].c.class, rating: standard[1].c.rating, enabled: Boolean(standard[1].enabled), priority: standard[1].priority + 1 },
frameShiftDrive: { class: standard[2].c.class, rating: standard[2].c.rating, enabled: Boolean(standard[2].enabled), priority: standard[2].priority + 1 },
lifeSupport: { class: standard[3].c.class, rating: standard[3].c.rating, enabled: Boolean(standard[3].enabled), priority: standard[3].priority + 1 },
powerDistributor: { class: standard[4].c.class, rating: standard[4].c.rating, enabled: Boolean(standard[4].enabled), priority: standard[4].priority + 1 },
sensors: { class: standard[5].c.class, rating: standard[5].c.rating, enabled: Boolean(standard[5].enabled), priority: standard[5].priority + 1 },
fuelTank: { class: standard[6].c.class, rating: standard[6].c.rating, enabled: Boolean(standard[6].enabled), priority: standard[6].priority + 1 }
},
hardpoints: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass > 0; }), slotToSchema),
utility: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass === 0; }), slotToSchema),
internal: _.map(internal, slotToSchema)
},
stats: {}
};
for (var stat in ship) {
if (!isNaN(ship[stat])) {
data.stats[stat] = Math.round(ship[stat] * 100) / 100;
}
}
return data;
};
this.fromDetailedBuild = function(detailedBuild) {
var shipId = _.findKey(ShipsDB, { properties: { name: detailedBuild.ship } });
if (!shipId) {
throw 'No such ship: ' + detailedBuild.ship;
}
var comps = detailedBuild.components;
var standard = comps.standard;
var priorities = [ standard.cargoHatch && standard.cargoHatch.priority !== undefined ? standard.cargoHatch.priority - 1 : 0 ];
var enabled = [ standard.cargoHatch && standard.cargoHatch.enabled !== undefined ? standard.cargoHatch.enabled : true ];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
var bulkheads = Components.bulkheadIndex(standard.bulkheads);
if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + standard.bulkheads;
}
var standardIds = _.map(
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
function(c) {
if (!standard[c].class || !standard[c].rating) {
throw 'Invalid value for ' + c;
}
priorities.push(standard[c].priority === undefined ? 0 : standard[c].priority - 1);
enabled.push(standard[c].enabled === undefined ? true : standard[c].enabled);
return standard[c].class + standard[c].rating;
}
);
var internal = _.map(comps.internal, function(c) { return c ? Components.findInternalId(c.group, c.class, c.rating, c.name) : 0; });
var hardpoints = _.map(comps.hardpoints, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount], c.missile) : 0;
}).concat(_.map(comps.utility, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
}));
// The ordering of these arrays must match the order in which they are read in Ship.buildWith
priorities = priorities.concat(_.map(comps.hardpoints, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.utility, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.internal, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }));
enabled = enabled.concat(_.map(comps.hardpoints, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.utility, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.internal, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }));
ship.buildWith({ bulkheads: bulkheads, standard: standardIds, hardpoints: hardpoints, internal: internal }, priorities, enabled);
return ship;
};
this.toDetailedExport = function(builds) {
var data = [];
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
this.toShip(ship, code);
data.push(this.toDetailedBuild(buildName, ship, code));
}
}
return data;
};
this.fromComparison = function(name, builds, facets, predicate, desc) {
var shipBuilds = [];
builds.forEach(function(b) {
shipBuilds.push({ s: b.id, n: b.buildName, c: this.fromShip(b) });
}.bind(this));
return LZString.compressToBase64(angular.toJson({
n: name,
b: shipBuilds,
f: facets,
p: predicate,
d: desc ? 1 : 0
})).replace(/\//g, '-');
};
this.toComparison = function(code) {
return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g, '/')));
};
/**
* Utility function to retrieve a safe string for selected component for a slot.
* Used for serialization to code only.
*
* @private
* @param {object} slot The slot object.
* @return {string} The id of the selected component or '-' if none selected
*/
function mapGroup(slot) {
this.enabled.push(slot.enabled ? 1 : 0);
this.priorities.push(slot.priority);
return slot.id === null ? '-' : slot.id;
}
function decodeToArray(code, arr, codePos) {
for (var i = 0; i < arr.length; i++) {
if (code.charAt(codePos) == '-') {
arr[i] = 0;
codePos++;
} else {
arr[i] = code.substring(codePos, codePos + 2);
codePos += 2;
}
}
return codePos;
}
function slotToSchema(slot) {
if (slot.c) {
var o = { class: slot.c.class, rating: slot.c.rating, enabled: Boolean(slot.enabled), priority: slot.priority + 1, group: GroupMap[slot.c.grp] };
if (slot.c.name) {
o.name = slot.c.name;
}
if (slot.c.mode) {
o.mount = MountMap[slot.c.mode];
}
if (slot.c.missile) {
o.missile = slot.c.missile;
}
return o;
}
return null;
}
}]);

View File

@@ -1,145 +0,0 @@
angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
function filter(data, maxClass, minClass, mass) {
return _.filter(data, function(c) {
return c.class <= maxClass && c.class >= minClass && (c.maxmass === undefined || mass <= c.maxmass);
});
}
function getKey(maxClass, eligible) {
if (eligible) {
return maxClass + Object.keys(eligible).join('-');
}
return maxClass;
}
function ComponentSet(components, mass, maxStandardArr, maxInternal, maxHardPoint) {
this.mass = mass;
this.standard = {};
this.internal = {};
this.hardpoints = {};
this.hpClass = {};
this.intClass = {};
this.standard[0] = filter(components.standard[0], maxStandardArr[0], 0, mass); // Power Plant
this.standard[2] = filter(components.standard[2], maxStandardArr[2], 0, mass); // FSD
this.standard[4] = filter(components.standard[4], maxStandardArr[4], 0, mass); // Power Distributor
this.standard[6] = filter(components.standard[6], maxStandardArr[6], 0, mass); // Fuel Tank
// Thrusters, filter components by class only (to show full list of ratings for that class)
var minThrusterClass = _.reduce(components.standard[1], function(minClass, thruster) {
return (thruster.maxmass >= mass && thruster.class < minClass) ? thruster.class : minClass;
}, maxStandardArr[1]);
this.standard[1] = filter(components.standard[1], maxStandardArr[1], minThrusterClass, 0); // Thrusters
// Slots where component class must be equal to slot class
this.standard[3] = filter(components.standard[3], maxStandardArr[3], maxStandardArr[3], 0); // Life Supprt
this.standard[5] = filter(components.standard[5], maxStandardArr[5], maxStandardArr[5], mass); // Sensors
for (var h in components.hardpoints) {
this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, mass);
}
for (var g in components.internal) {
this.internal[g] = filter(components.internal[g], maxInternal, 0, mass);
}
/**
* Create a memoized function for determining the components that are
* eligible for an internal slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible internal groups
* @return {object} A map of all eligible components by group
*/
this.getInts = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.internal) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
/**
* Create a memoized function for determining the components that are
* eligible for an hardpoint slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible hardpoint groups
* @return {object} A map of all eligible components by group
*/
this.getHps = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.hardpoints) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
}
ComponentSet.prototype.lightestPowerDist = function(boostEnergy) {
var pds = this.standard[4];
var pd = pds[0];
for (var i = 1; i < pds.length; i++) {
if (pds[i].mass < pd.mass && pds[i].enginecapacity >= boostEnergy) {
pd = pds[i];
}
}
return pd.class + pd.rating;
};
ComponentSet.prototype.lightestThruster = function(ladenMass) {
var ths = this.standard[1];
var th = ths[0];
for (var i = 1; i < ths.length; i++) {
if (ths[i].mass < th.mass && ths[i].maxmass >= ladenMass) {
th = ths[i];
}
}
return th.class + th.rating;
};
ComponentSet.prototype.lightestShieldGenerator = function(hullMass) {
var sg = null;
_.forEach(this.internal.sg, function(s) {
if (sg == null || (s.mass < sg.mass && s.minmass <= hullMass && s.maxmass > hullMass)) {
sg = s;
}
});
return sg.id;
};
ComponentSet.prototype.lightestPowerPlant = function(powerUsed, rating) {
var pps = this.standard[0];
var pp = null;
for (var i = 0; i < pps.length; i++) {
if (pp == null || (pps[i].mass < pp.mass && pps[i].pGen >= powerUsed)) {
pp = pps[i];
}
}
return pp.class + (pp.rating != 'D' || rating == 'A' ? 'A' : 'D'); // Use A rated if C,E
};
return ComponentSet;
}]);

View File

@@ -1,600 +0,0 @@
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'calcSpeed', 'lodash', 'ArmourMultiplier', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, calcSpeed, _, ArmourMultiplier) {
/**
* Returns the power usage type of a slot and it's particular component
* @param {object} slot The Slot
* @param {object} component The component in the slot
* @return {string} The key for the power usage type
*/
function powerUsageType(slot, component) {
if (component) {
if (component.passive) {
return 'retracted';
}
}
return slot.cat != 1 ? 'retracted' : 'deployed';
}
/**
* Ship model used to track all ship components and properties.
*
* @param {string} id Unique ship Id / Key
* @param {object} properties Basic ship properties such as name, manufacturer, mass, etc
* @param {object} slots Collection of slot groups (standard/standard, internal, hardpoints) with their max class size.
*/
function Ship(id, properties, slots) {
this.id = id;
this.cargoHatch = { c: Components.cargoHatch(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8 };
this.availCS = Components.forShip(id);
for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData
for (var slotType in slots) { // Initialize all slots
var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Standard, Hardpoints, Internal)
for (var i = 0; i < slotGroup.length; i++) {
if (typeof slotGroup[i] == 'object') {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i].class, eligible: slotGroup[i].eligible });
} else {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] });
}
}
}
// Make a Ship 'slot'/item similar to other slots
this.c = { incCost: true, type: 'SHIP', discountedCost: this.hullCost, c: { name: this.name, cost: this.hullCost } };
this.costList = _.union(this.internal, this.standard, this.hardpoints);
this.costList.push(this.bulkheads); // Add The bulkheads
this.costList.unshift(this.c); // Add the ship itself to the list
this.powerList = _.union(this.internal, this.hardpoints);
this.powerList.unshift(this.cargoHatch);
this.powerList.unshift(this.standard[1]); // Add Thrusters
this.powerList.unshift(this.standard[5]); // Add Sensors
this.powerList.unshift(this.standard[4]); // Add Power Distributor
this.powerList.unshift(this.standard[3]); // Add Life Support
this.powerList.unshift(this.standard[2]); // Add FSD
this.powerList.unshift(this.standard[0]); // Add Power Plant
this.shipCostMultiplier = 1;
this.componentCostMultiplier = 1;
this.priorityBands = [
{ deployed: 0, retracted: 0, retOnly: 0 },
{ deployed: 0, retracted: 0, retOnly: 0 },
{ deployed: 0, retracted: 0, retOnly: 0 },
{ deployed: 0, retracted: 0, retOnly: 0 },
{ deployed: 0, retracted: 0, retOnly: 0 }
];
}
//*********//
// GETTERS //
//*********//
Ship.prototype.getAvailableComponents = function() {
return this.availCS;
};
Ship.prototype.getSlotStatus = function(slot, deployed) {
if (!slot.c) { // Empty Slot
return 0; // No Status (Not possible to be active in this state)
} else if (!slot.enabled) {
return 1; // Disabled
} else if (deployed) {
return this.priorityBands[slot.priority].deployedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
// Active hardpoints have no retracted status
} else if ((slot.cat === 1 && !slot.c.passive)) {
return 0; // No Status (Not possible to be active in this state)
}
return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
};
/**
* Calculate jump range using the installed FSD and the
* specified mass which can be more or less than ships actual mass
* @param {number} mass Mass in tons
* @param {number} fuel Fuel available in tons
* @return {number} Jump range in Light Years
*/
Ship.prototype.getJumpRangeForMass = function(mass, fuel) {
return calcJumpRange(mass, this.standard[2].c, fuel);
};
/**
* Find an internal slot that has an installed component of the specific group.
*
* @param {string} group Component group/type
* @return {number} The index of the slot in ship.internal
*/
Ship.prototype.findInternalByGroup = function(group) {
var index;
if (group == 'sg' || group == 'psg' || group == 'bsg') {
index = _.findIndex(this.internal, function(slot) {
return slot.c && (slot.c.grp == 'sg' || slot.c.grp == 'psg' || slot.c.grp == 'bsg');
});
} else {
index = _.findIndex(this.internal, function(slot) {
return slot.c && slot.c.grp == group;
});
}
if (index !== -1) {
return this.internal[index];
}
return null;
};
//**********************//
// Mutate / Update Ship //
//**********************//
/**
* Recalculate all item costs and total based on discounts.
* @param {number} shipCostMultiplier Ship cost multiplier discount (e.g. 0.9 === 10% discount)
* @param {number} componentCostMultiplier Component cost multiplier discount (e.g. 0.75 === 25% discount)
*/
Ship.prototype.applyDiscounts = function(shipCostMultiplier, componentCostMultiplier) {
var total = 0;
var costList = this.costList;
for (var i = 0, l = costList.length; i < l; i++) {
var item = costList[i];
if (item.c && item.c.cost) {
item.discountedCost = item.c.cost * (item.type == 'SHIP' ? shipCostMultiplier : componentCostMultiplier);
if (item.incCost) {
total += item.discountedCost;
}
}
}
this.shipCostMultiplier = shipCostMultiplier;
this.componentCostMultiplier = componentCostMultiplier;
this.totalCost = total;
return this;
};
/**
* Builds/Updates the ship instance with the components[comps] passed in.
* @param {object} comps Collection of components used to build the ship
*/
Ship.prototype.buildWith = function(comps, priorities, enabled) {
var internal = this.internal,
standard = this.standard,
hps = this.hardpoints,
bands = this.priorityBands,
cl = standard.length,
i, l;
// Reset Cumulative stats
this.fuelCapacity = 0;
this.cargoCapacity = 0;
this.ladenMass = 0;
this.armourAdded = 0;
this.armourMultiplier = 1;
this.shieldMultiplier = 1;
this.totalCost = this.c.incCost ? this.c.discountedCost : 0;
this.unladenMass = this.hullMass;
this.totalDps = 0;
this.bulkheads.c = null;
this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true);
this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0;
this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true;
for (i = 0, l = this.priorityBands.length; i < l; i++) {
this.priorityBands[i].deployed = 0;
this.priorityBands[i].retracted = 0;
this.priorityBands[i].retOnly = 0;
}
if (this.cargoHatch.enabled) {
bands[this.cargoHatch.priority].retracted += this.cargoHatch.c.power;
}
for (i = 0; i < cl; i++) {
standard[i].cat = 0;
standard[i].enabled = enabled ? enabled[i + 1] * 1 : true;
standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0;
standard[i].type = 'SYS';
standard[i].c = standard[i].id = null; // Resetting 'old' component if there was one
standard[i].discountedCost = 0;
if (comps) {
this.use(standard[i], comps.standard[i], Components.standard(i, comps.standard[i]), true);
}
}
standard[1].type = 'ENG'; // Thrusters
standard[2].type = 'ENG'; // FSD
cl++; // Increase accounts for Cargo Scoop
for (i = 0, l = hps.length; i < l; i++) {
hps[i].cat = 1;
hps[i].enabled = enabled ? enabled[cl + i] * 1 : true;
hps[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS';
hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one
hps[i].discountedCost = 0;
if (comps && comps.hardpoints[i] !== 0) {
this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true);
}
}
cl += hps.length; // Increase accounts for hardpoints
for (i = 0, l = internal.length; i < l; i++) {
internal[i].cat = 2;
internal[i].enabled = enabled ? enabled[cl + i] * 1 : true;
internal[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
internal[i].type = 'SYS';
internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one
internal[i].discountedCost = 0;
if (comps && comps.internal[i] !== 0) {
this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true);
}
}
// Update aggragated stats
if (comps) {
this.updatePower()
.updateJumpStats()
.updateShieldStrength()
.updateTopSpeed();
}
return this;
};
Ship.prototype.emptyHardpoints = function() {
for (var i = this.hardpoints.length; i--; ) {
this.use(this.hardpoints[i], null, null);
}
return this;
};
Ship.prototype.emptyInternal = function() {
for (var i = this.internal.length; i--; ) {
this.use(this.internal[i], null, null);
}
return this;
};
Ship.prototype.emptyUtility = function() {
for (var i = this.hardpoints.length; i--; ) {
if (!this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null);
}
}
return this;
};
Ship.prototype.emptyWeapons = function() {
for (var i = this.hardpoints.length; i--; ) {
if (this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null);
}
}
return this;
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
* @param {object} c Standard Component overrides
*/
Ship.prototype.optimizeMass = function(c) {
return this.emptyHardpoints().emptyInternal().useLightestStandard(c);
};
Ship.prototype.setCostIncluded = function(item, included) {
if (item.incCost != included && item.c) {
this.totalCost += included ? item.discountedCost : -item.discountedCost;
}
item.incCost = included;
return this;
};
Ship.prototype.setSlotEnabled = function(slot, enabled) {
if (slot.enabled != enabled) { // Enabled state is changing
slot.enabled = enabled;
if (slot.c) {
this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power;
if (slot.c.grp == 'sg' || slot.c.grp == 'psg' || slot.c.grp == 'bsg') {
this.updateShieldStrength();
} else if (slot.c.grp == 'sb') {
this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1);
this.updateShieldStrength();
} else if (slot.c.dps) {
this.totalDps += slot.c.dps * (enabled ? 1 : -1);
}
this.updatePower();
}
}
return this;
};
/**
* Updates the ship's cumulative and aggregated stats based on the component change.
*/
Ship.prototype.updateStats = function(slot, n, old, preventUpdate) {
var powerChange = slot == this.standard[0];
if (old) { // Old component now being removed
switch (old.grp) {
case 'ft':
this.fuelCapacity -= old.capacity;
break;
case 'cr':
this.cargoCapacity -= old.capacity;
break;
case 'hr':
this.armourAdded -= old.armouradd;
break;
case 'sb':
this.shieldMultiplier -= slot.enabled ? old.shieldmul : 0;
break;
}
if (slot.incCost && old.cost) {
this.totalCost -= old.cost * this.componentCostMultiplier;
}
if (old.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, old)] -= old.power;
powerChange = true;
if (old.dps) {
this.totalDps -= old.dps;
}
}
this.unladenMass -= old.mass || 0;
}
if (n) {
switch (n.grp) {
case 'ft':
this.fuelCapacity += n.capacity;
break;
case 'cr':
this.cargoCapacity += n.capacity;
break;
case 'hr':
this.armourAdded += n.armouradd;
break;
case 'sb':
this.shieldMultiplier += slot.enabled ? n.shieldmul : 0;
break;
}
if (slot.incCost && n.cost) {
this.totalCost += n.cost * this.componentCostMultiplier;
}
if (n.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, n)] += n.power;
powerChange = true;
if (n.dps) {
this.totalDps += n.dps;
}
}
this.unladenMass += n.mass || 0;
}
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
this.armour = this.armourAdded + Math.round(this.baseArmour * this.armourMultiplier);
if (!preventUpdate) {
if (powerChange) {
this.updatePower();
}
this.updateTopSpeed();
this.updateJumpStats();
this.updateShieldStrength();
}
return this;
};
Ship.prototype.updatePower = function() {
var bands = this.priorityBands;
var prevRetracted = 0, prevDeployed = 0;
for (var i = 0, l = bands.length; i < l; i++) {
var band = bands[i];
prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly;
prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted;
}
this.powerAvailable = this.standard[0].c.pGen;
this.powerRetracted = prevRetracted;
this.powerDeployed = prevDeployed;
return this;
};
Ship.prototype.updateTopSpeed = function() {
var speeds = calcSpeed(this.unladenMass + this.fuelCapacity, this.speed, this.boost, this.standard[1].c, this.pipSpeed);
this.topSpeed = speeds['4 Pips'];
this.topBoost = speeds.boost;
return this;
};
Ship.prototype.updateShieldStrength = function() {
var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.hullMass, this.baseShieldStrength, sgSlot.c, this.shieldMultiplier) : 0;
return this;
};
/**
* Jump Range and total range calculations
*/
Ship.prototype.updateJumpStats = function() {
var fsd = this.standard[2].c; // Frame Shift Drive;
this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump
this.fullTankRange = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke
this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity);
this.unladenTotalRange = calcTotalRange(this.unladenMass, fsd, this.fuelCapacity);
this.ladenTotalRange = calcTotalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity);
this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel);
return this;
};
/**
* Update a slot with a the component if the id is different from the current id for this slot.
* Has logic handling components that you may only have 1 of (Shield Generator or Refinery).
*
* @param {object} slot The component slot
* @param {string} id Unique ID for the selected component
* @param {object} component Properties for the selected component
* @param {boolean} preventUpdate If true, do not update aggregated stats
*/
Ship.prototype.use = function(slot, id, component, preventUpdate) {
if (slot.id != id) { // Selecting a different component
// Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique
if (slot.cat == 2 && component && _.includes(['bsg', 'psg', 'sg', 'rf', 'fs'], component.grp)) {
// Find another internal slot that already has this type/group installed
var similarSlot = this.findInternalByGroup(component.grp);
// If another slot has an installed component with of the same type
if (!preventUpdate && similarSlot && similarSlot !== slot) {
this.updateStats(similarSlot, null, similarSlot.c);
similarSlot.id = similarSlot.c = null; // Empty the slot
similarSlot.discountedCost = 0;
}
}
var oldComponent = slot.c;
slot.id = id;
slot.c = component;
slot.discountedCost = (component && component.cost) ? component.cost * this.componentCostMultiplier : 0;
this.updateStats(slot, component, oldComponent, preventUpdate);
}
return this;
};
/**
* [useBulkhead description]
* @param {[type]} index [description]
* @param {[type]} preventUpdate [description]
* @return {[type]} [description]
*/
Ship.prototype.useBulkhead = function(index, preventUpdate) {
var oldBulkhead = this.bulkheads.c;
this.bulkheads.id = index;
this.bulkheads.c = Components.bulkheads(this.id, index);
this.bulkheads.discountedCost = this.bulkheads.c.cost * this.componentCostMultiplier;
this.armourMultiplier = ArmourMultiplier[index];
this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate);
return this;
};
/**
* [useStandard description]
* @param {[type]} rating [description]
* @return {[type]} [description]
*/
Ship.prototype.useStandard = function(rating) {
for (var i = this.standard.length - 1; i--; ) { // All except Fuel Tank
var id = this.standard[i].maxClass + rating;
this.use(this.standard[i], id, Components.standard(i, id));
}
return this;
};
/**
* Use the lightest standard components unless otherwise specified
* @param {object} c Component overrides
*/
Ship.prototype.useLightestStandard = function(c) {
c = c || {};
var standard = this.standard,
pd = c.pd || this.availCS.lightestPowerDist(this.boostEnergy), // Find lightest Power Distributor that can still boost;
fsd = c.fsd || standard[2].maxClass + 'A',
ls = c.ls || standard[3].maxClass + 'D',
s = c.s || standard[5].maxClass + 'D',
updated;
this.useBulkhead(0)
.use(standard[2], fsd, Components.standard(2, fsd)) // FSD
.use(standard[3], ls, Components.standard(3, ls)) // Life Support
.use(standard[5], s, Components.standard(5, s)) // Sensors
.use(standard[4], pd, Components.standard(4, pd)); // Power Distributor
// Thrusters and Powerplant must be determined after all other components are mounted
// Loop at least once to determine absolute lightest PD and TH
do {
updated = false;
// Find lightest Thruster that still works for the ship at max mass
var th = c.th || this.availCS.lightestThruster(this.ladenMass);
if (th != standard[1].id) {
this.use(standard[1], th, Components.standard(1, th));
updated = true;
}
// Find lightest Power plant that can power the ship
var pp = c.pp || this.availCS.lightestPowerPlant(Math.max(this.powerRetracted, this.powerDeployed), c.ppRating);
if (pp != standard[0].id) {
this.use(standard[0], pp, Components.standard(0, pp));
updated = true;
}
} while (updated);
return this;
};
Ship.prototype.useUtility = function(group, rating, name, clobber) {
var component = Components.findHardpoint(group, 0, rating, name);
for (var i = this.hardpoints.length; i--; ) {
if ((clobber || !this.hardpoints[i].c) && !this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], component.id, component);
}
}
return this;
};
Ship.prototype.useWeapon = function(group, mount, clobber, missile) {
var hps = this.hardpoints;
for (var i = hps.length; i--; ) {
if (hps[i].maxClass) {
var size = hps[i].maxClass, component;
do {
component = Components.findHardpoint(group, size, null, null, mount, missile);
if ((clobber || !hps[i].c) && component) {
this.use(hps[i], component.id, component);
break;
}
} while (!component && (--size > 0));
}
}
return this;
};
/**
* Will change the priority of the specified slot if the new priority is valid
* @param {object} slot The slot to be updated
* @param {number} newPriority The new priority to be set
* @return {boolean} Returns true if the priority was changed (within range)
*/
Ship.prototype.changePriority = function(slot, newPriority) {
if (newPriority >= 0 && newPriority < this.priorityBands.length) {
var oldPriority = slot.priority;
slot.priority = newPriority;
if (slot.enabled) { // Only update power if the slot is enabled
var usage = powerUsageType(slot, slot.c);
this.priorityBands[oldPriority][usage] -= slot.c.power;
this.priorityBands[newPriority][usage] += slot.c.power;
this.updatePower();
}
return true;
}
return false;
};
return Ship;
}]);

View File

@@ -1,255 +0,0 @@
/**
* This module contains all of the logic and models corresponding to
* information or behavoir in Elite Dangerous.
*
* This file contains values and functions that can be reused across the app.
*
* @requires ngLodash
*/
angular.module('shipyard', ['ngLodash'])
// Create 'angularized' references to DB. This will aid testing
.constant('ShipsDB', DB.ships)
.constant('ComponentsDB', DB.components)
.constant('ArmourMultiplier', [
1, // Lightweight
1.4, // Reinforced
1.945, // Military
1.945, // Mirrored
1.945 // Reactive
])
.constant('SizeMap', ['', 'small', 'medium', 'large', 'capital'])
// Map to lookup group labels/names for component grp, used for JSON Serialization
.constant('GroupMap', {
// Standard
pp: 'Power Plant',
t: 'Thrusters',
fsd: 'Frame Shift Drive',
ls: 'Life Support',
pd: 'Power Distributor',
s: 'Sensors',
ft: 'Fuel Tank',
// Internal
fs: 'Fuel Scoop',
sc: 'Scanner',
am: 'Auto Field-Maintenance Unit',
cr: 'Cargo Rack',
fi: 'Frame Shift Drive Interdictor',
hb: 'Hatch Breaker Limpet Controller',
hr: 'Hull Reinforcement Package',
rf: 'Refinery',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
psg: 'Prismatic Shield Generator',
bsg: 'Bi-Weave Shield Generator',
dc: 'Docking Computer',
fx: 'Fuel Transfer Limpet Controller',
pc: 'Prospector Limpet Controller',
cc: 'Collector Limpet Controller',
pv: 'Planetary Vehicle Hangar',
// Hard Points
bl: 'Beam Laser',
ul: 'Burst Laser',
c: 'Cannon',
cs: 'Cargo Scanner',
cm: 'Countermeasure',
fc: 'Fragment Cannon',
ws: 'Frame Shift Wake Scanner',
kw: 'Kill Warrant Scanner',
nl: 'Mine Launcher',
ml: 'Mining Laser',
mr: 'Missile Rack',
pa: 'Plasma Accelerator',
mc: 'Multi-cannon',
pl: 'Pulse Laser',
rg: 'Rail Gun',
sb: 'Shield Booster',
tp: 'Torpedo Pylon'
})
.constant('MountMap', {
'F': 'Fixed',
'G': 'Gimballed',
'T': 'Turret',
'Fixed': 'F',
'Gimballed': 'G',
'Turret': 'T'
})
/**
* Array of all Ship properties (facets) organized into groups
* used for ship comparisons.
*
* @type {Array}
*/
.constant('ShipFacets', [
{ // 0
title: 'agility',
props: ['agility'],
unit: '',
fmt: 'fCrd'
},
{ // 1
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'fCrd'
},
{ // 2
title: 'armour',
props: ['armour'],
unit: '',
fmt: 'fCrd'
},
{ // 3
title: 'shields',
props: ['shieldStrength'],
unit: 'MJ',
fmt: 'fRound'
},
{ // 4
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 5
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'fRound'
},
{ // 6
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 7
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 8
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'fPwr'
},
{ // 9
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'fCrd'
},
{ // 10
title: 'total range',
props: ['unladenTotalRange', 'ladenTotalRange'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 11
title: 'DPS',
props: ['totalDps'],
lbls: ['DPS'],
unit: '',
fmt: 'fRound'
}
])
/**
* Set of all available / theoretical discounts
*/
.constant('Discounts', {
'0%': 1,
'2.5%': 0.975,
'5%': 0.95,
'10%': 0.90,
'15%': 0.85,
'20%': 0.80,
'25%': 0.75
})
/**
* Calculate the maximum single jump range based on mass and a specific FSD
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump)
* @return {number} Distance in Light Years
*/
.value('calcJumpRange', function(mass, fsd, fuel) {
return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
})
/**
* Calculate the total range based on mass and a specific FSD, and all fuel available
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel The total fuel available
* @return {number} Distance in Light Years
*/
.value('calcTotalRange', function(mass, fsd, fuel) {
var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = Math.floor(fuel / fsd.maxfuel);
mass += fuelRemaining;
// Going backwards, start with the last jump using the remaining fuel
var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0;
// For each max fuel jump, calculate the max jump range based on fuel mass left in the tank
for (var j = 0; j < jumps; j++) {
mass += fsd.maxfuel;
totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
}
return totalRange;
})
/**
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
*
* @param {number} mass Current mass of the ship
* @param {number} shields Base Shield strength MJ for ship
* @param {object} sg The shield generator used
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
* @return {number} Approximate shield strengh in MJ
*/
.value('calcShieldStrength', function(mass, shields, sg, multiplier) {
var opt;
if (mass < sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass > sg.maxmass) {
return shields * multiplier * sg.maxmul;
}
if (mass < sg.optmass) {
opt = (sg.optmass - mass) / (sg.optmass - sg.minmass);
opt = 1 - Math.pow(1 - opt, 0.87);
return shields * multiplier * ((opt * sg.minmul) + ((1 - opt) * sg.optmul));
} else {
opt = (sg.optmass - mass) / (sg.maxmass - sg.optmass);
opt = -1 + Math.pow(1 + opt, 2.425);
return shields * multiplier * ( (-1 * opt * sg.maxmul) + ((1 + opt) * sg.optmul) );
}
})
/**
* Calculate the a ships speed based on mass, and thrusters.
*
* @param {number} mass Current mass of the ship
* @param {number} baseSpeed Base speed m/s for ship
* @param {number} baseBoost Base boost speed m/s for ship
* @param {object} thrusters The Thrusters used
* @param {number} pipSpeed Speed pip multiplier
* @return {object} Approximate speed by pips
*/
.value('calcSpeed', function(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
var multiplier = mass > thrusters.maxmass ? 0 : ((1 - thrusters.M) + (thrusters.M * Math.pow(3 - (2 * Math.max(0.5, mass / thrusters.optmass)), thrusters.P)));
var speed = baseSpeed * multiplier;
return {
'0 Pips': speed * (1 - (pipSpeed * 4)),
'2 Pips': speed * (1 - (pipSpeed * 2)),
'4 Pips': speed,
'boost': baseBoost * multiplier
};
});

View File

@@ -1,181 +0,0 @@
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', 'GroupMap', function(_, C, Ships, ComponentSet, GroupMap) {
var GrpNameToCodeMap = {};
for (var grp in GroupMap) {
GrpNameToCodeMap[GroupMap[grp]] = grp;
}
this.cargoHatch = function() {
return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6 };
};
this.standard = function(typeIndex, componentId) {
return C.standard[typeIndex][componentId];
};
this.hardpoints = function(id) {
for (var n in C.hardpoints) {
var group = C.hardpoints[n];
for (var i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
this.internal = function(id) {
for (var n in C.internal) {
var group = C.internal[n];
for (var i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternal = function(groupName, clss, rating, name) {
var groups = {};
if (groupName) {
if (C.internal[groupName]) {
groups[groupName] = C.internal[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.internal[grpCode]) {
groups[grpCode] = C.internal[grpCode];
}
}
} else if (name) {
groups = C.internal;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component ID based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternalId = function(groupName, clss, rating, name) {
var i = this.findInternal(groupName, clss, rating, name);
return i ? i.id : 0;
};
/**
* Finds a hardpoint Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating [Optional] Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpoint = function(groupName, clss, rating, name, mode, missile) {
var groups = {};
if (groupName) {
if (C.hardpoints[groupName]) {
groups[groupName] = C.hardpoints[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.hardpoints[grpCode]) {
groups[grpCode] = C.hardpoints[grpCode];
}
}
} else if (name) {
groups = C.hardpoints;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && (!rating || group[i].rating == rating) && group[i].mode == mode
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i];
}
}
}
return null;
};
/**
* Finds a hardpoint Component ID based on Class, Rating, Group and/or name.
* At least one of Group name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpointId = function(groupName, clss, rating, name, mode, missile) {
var h = this.findHardpoint(groupName, clss, rating, name, mode, missile);
return h ? h.id : 0;
};
/**
* Looks up the bulkhead component for a specific ship and bulkhead
* @param {string} shipId Unique ship Id/Key
* @param {number} bulkheadsId Id/Index for the specified bulkhead
* @return {object} The bulkhead component object
*/
this.bulkheads = function(shipId, bulkheadsId) {
return C.bulkheads[shipId][bulkheadsId];
};
this.bulkheadIndex = function(bulkheadName) {
return ['Lightweight Alloy', 'Reinforced Alloy', 'Military Grade Composite', 'Mirrored Surface Composite', 'Reactive Surface Composite'].indexOf(bulkheadName);
};
/**
* Creates a new ComponentSet that contains all available components
* that the specified ship is eligible to use.
*
* @param {string} shipId Unique ship Id/Key
* @return {ComponentSet} The set of components the ship can install
*/
this.forShip = function(shipId) {
var ship = Ships[shipId];
var maxInternal = isNaN(ship.slots.internal[0]) ? ship.slots.internal[0].class : ship.slots.internal[0];
return new ComponentSet(C, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.standard, maxInternal, ship.slots.hardpoints[0]);
};
}]);

View File

@@ -1,8 +0,0 @@
.deep-space {
background-image: url(images/deep-space-1920x1080.jpg);
}
.docking-bay {
background-image: url(images/bay-1920x1080.jpg);
}

View File

@@ -1,63 +0,0 @@
.d3-tip {
font-size: 0.8em;
padding: 0.25em 0.5em;
background: @primary-disabled;
text-transform: capitalize;
color: @primary-bg;
pointer-events: none;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: @primary-disabled;
position: absolute;
pointer-events: none;
}
/* Northward tooltips */
.d3-tip.n {
margin-top: -7px;
&:after {
content: "\25BC";
margin: -1px 0 0 0;
top: 100%;
left: 0;
text-align: center;
}
}
/* Eastward tooltips */
.d3-tip.e {
margin-left: 8px;
&:after {
content: "\25C0";
margin: -4px 0 0 0;
top: 50%;
left: -8px;
}
}
/* Southward tooltips */
.d3-tip.s {
margin-top: 8px;
&:after {
content: "\25B2";
margin: 0 0 1px 0;
top: -7px;
left: 0;
text-align: center;
}
}
/* Westward tooltips */
.d3-tip.w:after {
content: "\25B6";
margin: -4px 0 0 -1px;
top: 50%;
left: 100%;
}

View File

@@ -1,26 +0,0 @@
@font-face {
font-family: 'Orbitron-Regular';
src: url('fonts/orbitron-regular-webfont.eot');
src: url('fonts/orbitron-regular-webfont.eot?#iefix') format('embedded-opentype'),
url('fonts/orbitron-regular-webfont.woff2') format('woff2'),
url('fonts/orbitron-regular-webfont.woff') format('woff'),
url('fonts/orbitron-regular-webfont.ttf') format('truetype'),
url('fonts/orbitron-regular-webfont.svg#orbitronregular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Eurostile';
src: url('fonts/eurostile.eot');
src: url('fonts/eurostile.eot?#iefix') format('embedded-opentype'),
url('fonts/eurostile.woff2') format('woff2'),
url('fonts/eurostile.woff') format('woff'),
url('fonts/eurostile.ttf') format('truetype'),
url('fonts/eurostile.svg#euro_capsregular') format('svg');
font-weight: normal;
font-style: normal;
}
@fStandard: 'Eurostile', Helvetica, sans-serif;
@fTitle: 'Orbitron-Regular', Arial, sans-serif;

View File

@@ -1,98 +0,0 @@
.slider-axis {
line, path {
fill: none;
stroke: @primary-disabled;
}
text {
font-size: 0.7em;
fill: @primary-disabled;
}
.domain {
fill: none;
stroke: @primary;
stroke-opacity: .3;
stroke-width: 0.7em;
stroke-linecap: round;
}
}
.slider {
text {
dominant-baseline: central;
fill: @primary;
font-size: 0.8em;
}
.filled {
stroke-width: 0.3em;
stroke-linecap: round;
stroke: @primary-disabled;
}
.handle {
fill: @primary;
stroke-opacity: .5;
cursor: crosshair;
}
}
input[type=range] {
-webkit-appearance: none;
border: 1px solid @bgBlack;
/*required for proper track sizing in FF*/
width: 300px;
&::-moz-range-track, &::-webkit-slider-runnable-track {
width: 300px;
height: 5px;
background: @primary;
border: none;
border-radius: 3px;
}
&::-moz-range-thumb, &::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 1em;
width: 1em;
border-radius: 50%;
background: @primary;
}
&:focus {
outline: none;
}
/*hide the outline behind the border*/
&:-moz-focusring{
outline: 1px solid @bgBlack;
outline-offset: -1px;
}
&::-ms-track {
width: 300px;
height: 5px;
background: transparent;
border-color: transparent;
border-width: 6px 0;
color: transparent;
}
&::-ms-fill-lower {
background: @primary;
border-radius: 10px;
}
&::-ms-fill-upper {
background: @primary;
border-radius: 10px;
}
&::-ms-thumb {
border: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: goldenrod;
}
}

View File

@@ -1,30 +0,0 @@
.sortable {
.user-select-none();
}
.as-sortable-item, .as-sortable-placeholder {
display: inline-block;
float: left;
}
.as-sortable-item {
-ms-touch-action: none;
touch-action: none;
}
.as-sortable-item-handle {
display: block;
}
.as-sortable-drag {
margin: 0;
padding:0;
opacity: .8;
position: absolute;
pointer-events: none;
z-index: 9999;
}
.as-sortable-hidden {
display: none !important;
}

View File

@@ -1,91 +0,0 @@
<div id="app-update" ng-show="appCacheUpdate">
<a href="#" onclick="window.location.reload()">{{ 'PHRASE_UPDATE_RDY' | translate }}</a>
</div>
<header>
<a class="l" ui-sref="shipyard" style="margin-right: 1em;" title="Ships"><svg class="icon xl"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#coriolis"></use></svg></a>
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='s'}" ng-click="openMenu($event,'s')">
<svg class="icon warning"><use xlink:href="#rocket"></use></svg><span class="menu-item-label"> {{'ships' | translate}}</span>
</div>
<div class="menu-list dbl no-wrap" ng-if="openedMenu=='s'">
<a class="block" ng-repeat="(shipId,ship) in ships" ui-sref-active="active" ui-sref="outfit({shipId:shipId, code:null, bn:null})">{{::ship.properties.name}}</a>
</div>
</div>
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='b', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'b')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#hammer"></use></svg><span class="menu-item-label"> {{'builds' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='b'" ng-click="$event.stopPropagation();">
<div class="dbl" >
<div><ul ng-repeat="shipId in buildsList">
{{ships[shipId].properties.name}}
<li ng-repeat="(i, name) in cleanedBuildList(shipId)">
<a ui-sref-active="active" class="name" ui-sref="outfit({shipId:shipId, code:allBuilds[shipId][name], bn:name})" ng-bind="name"></a>
</li>
</ul></div>
</div>
</div>
</div>
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='comp', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'comp')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#stats-bars"></use></svg><span class="menu-item-label"> {{'compare' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='comp'" ng-click="$event.stopPropagation();" style="white-space: nowrap;">
<span class="cap" ng-if="!bs.hasComparisons" translate="none created"></span>
<a ng-repeat="(i, name) in allComparisons" ui-sref-active="active" class="block name" ui-sref="compare({name:name})" ng-bind="name"></a>
<hr />
<a ui-sref="compare({name: 'all'})" class="block cap" translate="compare all"></a>
<a ui-sref="compare({name: null})" class="block cap" translate="create new"></a>
</div>
</div>
<div class="r menu">
<div class="menu-header" ng-class="{selected: openedMenu=='settings'}" ng-click="openMenu($event,'settings')">
<svg class="icon xl warning"><use xlink:href="#cogs"></use></svg><span class="menu-item-label"> {{'settings' | translate}}</span>
</div>
<div class="menu-list no-wrap cap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<ul>
{{'language' | translate}}
<li><select class="cap" ng-model="language.current" ng-options="langCode as langName for (langCode,langName) in language.opts" ng-change="changeLanguage()"></select></li>
</ul><br>
<ul>
{{'insurance' | translate}}
<li><select class="cap" ng-model="insurance.current" ng-options="ins.name | translate for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
</ul><br>
<ul>
{{'ship' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.ship" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul><br>
<ul>
{{'component' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.components" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul>
<hr />
<ul>
{{'builds' | translate}} & {{'comparisons' | translate}}
<li><a href="#" class="block" ng-click="backup($event)" translate="backup"></a></li>
<li><a href="#" class="block" ng-click="detailedExport($event)" translate="detailed export"></a></li>
<li><a href="#" class="block" ui-sref="modal.import" translate="import"></a></li>
<li><a href="#" class="block" ui-sref="modal.delete" translate="delete all"></a></li>
</ul>
<hr />
<table style="width: 300px;background-color:transparent">
<tr>
<td style="width: 20px"><u>A</u></td>
<td slider min="0.65" def="sizeRatio" max="1.2" on-change="textSizeChange(val)" ignore-resize="true"></td>
<td style="width: 20px"><span style="font-size: 30px">A</span></td>
</tr>
<tr>
<td></td><td style="text-align:center" class="primary-disabled cap" ng-click="resetTextSize()" translate="reset"></td><td></td>
</tr>
</table>
<hr />
<a href="#" ui-sref="modal.about" class="block" translate="about"></a>
</div>
</div>
</header>

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