Merge pull request #3270 from balena-io/remove-bluebird

Remove bluebird
This commit is contained in:
bulldozer-balena[bot] 2020-08-19 11:55:07 +00:00 committed by GitHub
commit b2c4f7a250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 4084 additions and 6483 deletions

View File

@ -17,7 +17,7 @@
"appId": "io.balena.etcher",
"copyright": "Copyright 2016-2020 Balena Ltd",
"productName": "balenaEtcher",
"nodeGypRebuild": true,
"nodeGypRebuild": false,
"afterPack": "./afterPack.js",
"asar": false,
"files": [

View File

@ -122,56 +122,20 @@ TARGETS = \
help \
info \
lint \
lint-ts \
lint-css \
lint-cpp \
lint-spell \
test-spectron \
test-gui \
test \
sanity-checks \
clean \
distclean \
webpack \
electron-develop \
electron-test \
electron-build
webpack:
npx webpack
.PHONY: $(TARGETS)
lint-ts:
npx balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts
lint:
npm run lint
lint-css:
npx prettier --write lib/**/*.css
lint-cpp:
cpplint --recursive src
lint-spell:
codespell \
--dictionary - \
--dictionary dictionary.txt \
--skip *.svg *.gz,*.bz2,*.xz,*.zip,*.img,*.dmg,*.iso,*.rpi-sdcard,*.wic,.DS_Store,*.dtb,*.dtbo,*.dat,*.elf,*.bin,*.foo,xz-without-extension \
lib tests docs Makefile *.md LICENSE
lint: lint-ts lint-css lint-cpp lint-spell
MOCHA_OPTIONS=--recursive --reporter spec --require ts-node/register --require-main "tests/gui/allow-renderer-process-reuse.ts"
test-spectron:
npx mocha $(MOCHA_OPTIONS) tests/spectron/runner.spec.ts
test-gui:
npx electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox --renderer tests/gui/**/*.ts
test-sdk:
npx electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox tests/shared/**/*.ts
test: test-gui test-sdk test-spectron
test:
npm run test
help:
@echo "Available targets: $(TARGETS)"
@ -181,15 +145,11 @@ info:
@echo "Host arch : $(HOST_ARCH)"
@echo "Target arch : $(TARGET_ARCH)"
sanity-checks:
./scripts/ci/ensure-all-file-extensions-in-gitattributes.sh
clean:
rm -rf $(BUILD_DIRECTORY)
distclean: clean
rm -rf node_modules
rm -rf build
rm -rf dist
rm -rf generated
rm -rf $(BUILD_TEMPORARY_DIRECTORY)

View File

@ -1,35 +0,0 @@
{
"targets": [
{
"target_name": "elevator",
"include_dirs" : [
"src",
"<!(node -e \"require('nan')\")"
],
'conditions': [
[ 'OS=="win"', {
"sources": [
"src/utils/v8utils.cpp",
"src/os/win32/elevate.cpp",
"src/elevator_init.cpp",
],
"libraries": [
"-lShell32.lib",
],
} ],
[ 'OS=="mac"', {
"xcode_settings": {
"OTHER_CPLUSPLUSFLAGS": [
"-stdlib=libc++"
],
"OTHER_LDFLAGS": [
"-stdlib=libc++"
]
}
} ]
],
}
],
}

View File

@ -2,7 +2,7 @@ appId: io.balena.etcher
copyright: Copyright 2016-2020 Balena Ltd
productName: balenaEtcher
npmRebuild: true
nodeGypRebuild: true
nodeGypRebuild: false
publish: null
beforeBuild: "./beforeBuild.js"
afterPack: "./afterPack.js"

View File

@ -43,10 +43,8 @@ window.addEventListener(
'unhandledrejection',
(event: PromiseRejectionEvent | any) => {
// Promise: event.reason
// Bluebird: event.detail.reason
// Anything else: event
const error =
event.reason || (event.detail && event.detail.reason) || event;
const error = event.reason || event;
analytics.logException(error);
event.preventDefault();
},

View File

@ -16,7 +16,7 @@
import * as _ from 'lodash';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import { Flex } from 'rendition';
import { v4 as uuidV4 } from 'uuid';
import * as flashState from '../../models/flash-state';

View File

@ -19,8 +19,7 @@ import CheckCircleSvg from '@fortawesome/fontawesome-free/svgs/solid/check-circl
import * as _ from 'lodash';
import outdent from 'outdent';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, Txt } from 'rendition';
import { progress } from '../../../../shared/messages';
import { bytesToMegabytes } from '../../../../shared/units';

View File

@ -15,10 +15,7 @@
*/
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import Button from 'rendition/dist_esm5/components/Button';
import ProgressBar from 'rendition/dist_esm5/components/ProgressBar';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, Button, ProgressBar, Txt } from 'rendition';
import { default as styled } from 'styled-components';
import { fromFlashState } from '../../modules/progress-status';

View File

@ -15,8 +15,7 @@
*/
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, Txt } from 'rendition';
import DriveSvg from '../../../assets/drive.svg';
import ImageSvg from '../../../assets/image.svg';

View File

@ -18,9 +18,7 @@ import GithubSvg from '@fortawesome/fontawesome-free/svgs/brands/github.svg';
import * as _ from 'lodash';
import * as os from 'os';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import Checkbox from 'rendition/dist_esm5/components/Checkbox';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, Checkbox, Txt } from 'rendition';
import { version, packageType } from '../../../../../package.json';
import * as settings from '../../models/settings';

View File

@ -23,12 +23,14 @@ import * as _ from 'lodash';
import { GPTPartition, MBRPartition } from 'partitioninfo';
import * as path from 'path';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import { ButtonProps } from 'rendition/dist_esm5/components/Button';
import SmallModal from 'rendition/dist_esm5/components/Modal';
import Txt from 'rendition/dist_esm5/components/Txt';
import BaseCard from 'rendition/dist_esm5/components/Card';
import Input from 'rendition/dist_esm5/components/Input';
import {
Flex,
ButtonProps,
Modal as SmallModal,
Txt,
Card as BaseCard,
Input,
} from 'rendition';
import styled from 'styled-components';
import * as errors from '../../../../shared/errors';

View File

@ -17,8 +17,7 @@
import ExclamationTriangleSvg from '@fortawesome/fontawesome-free/svgs/solid/exclamation-triangle.svg';
import { Drive as DrivelistDrive } from 'drivelist';
import * as React from 'react';
import { Flex, FlexProps } from 'rendition/dist_esm5/components/Flex';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, FlexProps, Txt } from 'rendition';
import {
getDriveImageCompatibilityStatuses,

View File

@ -18,12 +18,15 @@ import ExclamationTriangleSvg from '@fortawesome/fontawesome-free/svgs/solid/exc
import ChevronDownSvg from '@fortawesome/fontawesome-free/svgs/solid/chevron-down.svg';
import { scanner, sourceDestination } from 'etcher-sdk';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import { ModalProps } from 'rendition/dist_esm5/components/Modal';
import Txt from 'rendition/dist_esm5/components/Txt';
import Badge from 'rendition/dist_esm5/components/Badge';
import Link from 'rendition/dist_esm5/components/Link';
import Table, { TableColumn } from 'rendition/dist_esm5/components/Table';
import {
Flex,
ModalProps,
Txt,
Badge,
Link,
Table,
TableColumn,
} from 'rendition';
import styled from 'styled-components';
import {

View File

@ -86,8 +86,7 @@ const settings = _.cloneDeep(DEFAULT_SETTINGS);
async function load(): Promise<void> {
debug('load');
// Use exports.readAll() so it can be mocked in tests
const loadedSettings = await exports.readAll();
const loadedSettings = await readAll();
_.assign(settings, loadedSettings);
}

View File

@ -136,16 +136,13 @@ interface FlashResults {
/**
* @summary Perform write operation
*
* @description
* This function is extracted for testing purposes.
*/
export async function performWrite(
async function performWrite(
image: string,
drives: DrivelistDrive[],
onProgress: sdk.multiWrite.OnProgressFunction,
source: SourceOptions,
): Promise<{ cancelled?: boolean }> {
): Promise<FlashResults> {
let cancelled = false;
ipc.serve();
const {
@ -244,7 +241,6 @@ export async function performWrite(
title: 'The writer process ended unexpectedly',
description:
'Please try again, and contact the Etcher team if the problem persists',
code: 'ECHILDDIED',
}),
);
return;
@ -265,6 +261,8 @@ export async function flash(
image: string,
drives: DrivelistDrive[],
source: SourceOptions,
// This function is a parameter so it can be mocked in tests
write = performWrite,
): Promise<void> {
if (flashState.isFlashing()) {
throw new Error('There is already a flash in progress');
@ -289,8 +287,7 @@ export async function flash(
analytics.logEvent('Flash', analyticsData);
try {
// Using it from exports so it can be mocked during tests
const result = await exports.performWrite(
const result = await write(
image,
drives,
flashState.setProgressState,

View File

@ -50,9 +50,9 @@ export const currentWindow = electron.remote.getCurrentWindow();
*/
export function set(state: FlashState) {
if (state.percentage != null) {
exports.currentWindow.setProgressBar(percentageToFloat(state.percentage));
currentWindow.setProgressBar(percentageToFloat(state.percentage));
}
exports.currentWindow.setTitle(getWindowTitle(state));
currentWindow.setTitle(getWindowTitle(state));
}
/**
@ -60,6 +60,6 @@ export function set(state: FlashState) {
*/
export function clear() {
// Passing 0 or null/undefined doesn't work.
exports.currentWindow.setProgressBar(-1);
exports.currentWindow.setTitle(getWindowTitle(undefined));
currentWindow.setProgressBar(-1);
currentWindow.setTitle(getWindowTitle(undefined));
}

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
import { using } from 'bluebird';
import { exec } from 'child_process';
import { readFile } from 'fs';
import { chain, trim } from 'lodash';
@ -23,7 +22,7 @@ import { join } from 'path';
import { env } from 'process';
import { promisify } from 'util';
import { tmpFileDisposer } from '../../../shared/tmp';
import { withTmpFile } from '../../../shared/tmp';
const readFileAsync = promisify(readFile);
@ -32,8 +31,7 @@ const execAsync = promisify(exec);
/**
* @summary Returns wmic's output for network drives
*/
export async function getWmicNetworkDrivesOutput(): Promise<string> {
// Exported for tests.
async function getWmicNetworkDrivesOutput(): Promise<string> {
// When trying to read wmic's stdout directly from node, it is encoded with the current
// console codepage (depending on the computer).
// Decoding this would require getting this codepage somehow and using iconv as node
@ -47,7 +45,7 @@ export async function getWmicNetworkDrivesOutput(): Promise<string> {
// Wmic fails with "Invalid global switch" when the "/output:" switch filename contains a dash ("-")
prefix: 'tmp',
};
return using(tmpFileDisposer(options), async ({ path }) => {
return withTmpFile(options, async (path) => {
const command = [
join(env.SystemRoot as string, 'System32', 'Wbem', 'wmic'),
'path',
@ -67,9 +65,10 @@ export async function getWmicNetworkDrivesOutput(): Promise<string> {
/**
* @summary returns a Map of drive letter -> network locations on Windows: 'Z:' -> '\\\\192.168.0.1\\Public'
*/
async function getWindowsNetworkDrives(): Promise<Map<string, string>> {
// Use getWindowsNetworkDrives from "exports." so it can be mocked in tests
const result = await exports.getWmicNetworkDrivesOutput();
async function getWindowsNetworkDrives(
getWmicOutput: () => Promise<string>,
): Promise<Map<string, string>> {
const result = await getWmicOutput();
const couples: Array<[string, string]> = chain(result)
.split('\n')
// Remove header line
@ -98,13 +97,15 @@ async function getWindowsNetworkDrives(): Promise<Map<string, string>> {
*/
export async function replaceWindowsNetworkDriveLetter(
filePath: string,
// getWmicOutput is a parameter so it can be replaced in tests
getWmicOutput = getWmicNetworkDrivesOutput,
): Promise<string> {
let result = filePath;
if (platform() === 'win32') {
const matches = /^([A-Z]+:)\\(.*)$/.exec(filePath);
if (matches !== null) {
const [, drive, relativePath] = matches;
const drives = await getWindowsNetworkDrives();
const drives = await getWindowsNetworkDrives(getWmicOutput);
const location = drives.get(drive);
if (location !== undefined) {
result = `${location}\\${relativePath}`;

View File

@ -16,7 +16,7 @@
import { scanner } from 'etcher-sdk';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import { Flex } from 'rendition';
import { TargetSelector } from '../../components/target-selector/target-selector-button';
import { TargetSelectorModal } from '../../components/target-selector/target-selector-modal';
import {

View File

@ -18,9 +18,7 @@ import CircleSvg from '@fortawesome/fontawesome-free/svgs/solid/circle.svg';
import * as _ from 'lodash';
import * as path from 'path';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import Modal from 'rendition/dist_esm5/components/Modal';
import Txt from 'rendition/dist_esm5/components/Txt';
import { Flex, Modal, Txt } from 'rendition';
import * as constraints from '../../../../shared/drive-constraints';
import * as messages from '../../../../shared/messages';

View File

@ -21,7 +21,7 @@ import { sourceDestination } from 'etcher-sdk';
import * as _ from 'lodash';
import * as path from 'path';
import * as React from 'react';
import { Flex } from 'rendition/dist_esm5/components/Flex';
import { Flex } from 'rendition';
import styled from 'styled-components';
import { FeaturedProject } from '../../components/featured-project/featured-project';

View File

@ -15,12 +15,16 @@
*/
import * as React from 'react';
import { Flex, FlexProps } from 'rendition/dist_esm5/components/Flex';
import Button, { ButtonProps } from 'rendition/dist_esm5/components/Button';
import ModalBase from 'rendition/dist_esm5/components/Modal';
import Provider from 'rendition/dist_esm5/components/Provider';
import Txt from 'rendition/dist_esm5/components/Txt';
import renditionTheme from 'rendition/dist_esm5/theme';
import {
Flex,
FlexProps,
Button,
ButtonProps,
Modal as ModalBase,
Provider,
Txt,
Theme as renditionTheme,
} from 'rendition';
import styled from 'styled-components';
import { space } from 'styled-system';

View File

@ -1,68 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 260.9 74" style="enable-background:new 0 0 260.9 74;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{fill:#FFFFFF;}
.st3{fill:#FFC100;}
.st4{fill:#F6EB61;}
.st5{fill:#439879;}
.st6{fill:#28CDFB;}
.st7{fill:#FDD757;}
.st8{fill:#EC8B00;}
</style>
<g id="type" class="st0">
<text transform="matrix(1 0 0 1 264.4807 53.6223)" class="st1" style="font-family:'ITCAvantGardeStd-Bold'; font-size:46.2px;">Fin</text>
</g>
<g id="Ebene_1">
<g>
<path class="st2" d="M88.8,19.7h6.7v11.1h0.1c0.7-1,1.7-1.7,2.9-2.3c1.2-0.5,2.5-0.9,3.8-1.1c0.3,0,0.7-0.1,1-0.1
c0.3,0,0.6,0,0.9,0c4.1,0,7.5,1.4,10.1,4.1c2.6,2.7,3.9,5.9,3.9,9.4c0,0.5,0,1.1-0.1,1.6c-0.1,0.6-0.2,1.1-0.4,1.7
c-0.3,1.1-0.7,2.2-1.2,3.2c-0.5,1-1.2,2-1.9,2.7c-1.2,1.4-2.8,2.4-4.6,3.1c-1.8,0.7-3.7,1.1-5.6,1.1c-1.9,0-3.7-0.3-5.3-1
c-1.6-0.7-3-1.7-4.1-3.2l-0.1,0v3.4h-6.2V19.7z M97.6,35.4c-1.7,1.4-2.5,3.1-2.5,5.2c0,2.2,0.8,4.1,2.3,5.6
c1.5,1.5,3.6,2.3,6.1,2.3c2.4,0,4.3-0.7,5.8-2.2c1.5-1.4,2.2-3.2,2.2-5.4c0-2.1-0.7-3.9-2.2-5.4c-1.5-1.5-3.4-2.2-5.8-2.2
C101.2,33.3,99.3,34,97.6,35.4z"/>
<path class="st2" d="M150.3,53.6h-6.2v-3.4h-0.1c-0.8,1.1-1.9,2-3.3,2.7c-1.4,0.7-2.8,1.2-4.3,1.4c-0.3,0-0.6,0.1-0.9,0.1
c-0.3,0-0.6,0-0.9,0c-2.2,0-4.1-0.4-5.8-1.1c-1.7-0.7-3.2-1.8-4.4-3.1c-1.1-1.2-2-2.6-2.6-4.2c-0.6-1.6-0.9-3.3-0.9-5
c0-1.8,0.3-3.4,0.8-4.9c0.6-1.5,1.5-2.9,2.7-4.2c1.4-1.5,3-2.6,4.7-3.3c1.7-0.7,3.6-1.1,5.7-1.1c1.9,0,3.7,0.4,5.3,1.1
c1.6,0.7,3,1.8,4.1,3.3v-3.6h6.2V53.6z M144,40.8c0-2.1-0.7-3.9-2.2-5.3c-1.5-1.5-3.4-2.2-5.8-2.1c-2.5,0-4.5,0.7-6,2.2
c-1.6,1.5-2.3,3.4-2.3,5.6c0,2.1,0.8,3.8,2.4,5.2c1.6,1.4,3.6,2.1,5.8,2.1c2.4,0,4.4-0.7,5.9-2.2C143.2,44.9,144,43,144,40.8
L144,40.8z"/>
<path class="st2" d="M155.3,19.7h6.7v33.9h-6.7V19.7z"/>
<path class="st2" d="M173.3,43.6c0.5,1.5,1.4,2.7,2.8,3.6c1.4,0.9,2.9,1.3,4.6,1.3c1.3,0,2.5-0.2,3.6-0.6c1.1-0.4,2-0.9,2.6-1.6
l7.4,0c-0.8,2.3-2.5,4.2-5.1,5.8c-2.6,1.6-5.3,2.4-8.3,2.4c-4.1,0-7.5-1.3-10.4-3.9c-2.9-2.6-4.3-5.7-4.3-9.4c0-3.8,1.4-7,4.3-9.7
c2.9-2.7,6.4-4,10.5-4c4,0,7.4,1.3,10.2,4c2.8,2.7,4.2,5.8,4.2,9.3c0,0.4,0,0.8-0.1,1.2c-0.1,0.4-0.1,0.8-0.2,1.1
c0,0.1-0.1,0.2-0.1,0.3c0,0.1,0,0.2,0,0.3H173.3z M188.6,38.2c-0.5-1.5-1.5-2.7-2.9-3.5c-1.4-0.9-3-1.3-4.7-1.3
c-0.1,0-0.1,0-0.2,0c-0.1,0-0.1,0-0.2,0c-1.6,0.1-3.1,0.6-4.5,1.4c-1.4,0.9-2.4,2-2.8,3.4H188.6z"/>
<path class="st2" d="M199.7,28.2h6.2v2.3h0.1c0.8-0.9,1.8-1.7,3-2.2c1.3-0.5,2.6-0.8,4-0.9c0.1,0,0.2,0,0.3,0c0.1,0,0.2,0,0.3,0
c0.1,0,0.3,0,0.4,0c0.1,0,0.3,0,0.4,0c1.3,0.1,2.6,0.4,3.9,1c1.3,0.5,2.3,1.3,3.3,2.2c0.1,0.1,0.3,0.2,0.4,0.3
c0.1,0.1,0.2,0.2,0.3,0.4c1.1,1.4,1.7,2.8,1.9,4.4s0.3,3.1,0.3,4.8v13.1h-6.7v-12c0-0.4,0-0.8,0-1.2c0-0.4,0-0.9-0.1-1.3
c-0.1-0.7-0.2-1.3-0.4-1.9c-0.2-0.6-0.4-1.2-0.8-1.7c-0.4-0.6-1-1.1-1.8-1.5c-0.8-0.4-1.5-0.6-2.3-0.6c0,0-0.1,0-0.1,0
c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.4,0c-0.8,0.1-1.5,0.3-2.3,0.7c-0.7,0.4-1.3,0.9-1.7,1.5
c-0.3,0.5-0.6,1.1-0.8,1.7c-0.2,0.7-0.3,1.3-0.3,2c0,0.4,0,0.8,0,1.2c0,0.4,0,0.8,0,1.1c0,0.1,0,0.2,0,0.3c0,0.1,0,0.1,0,0.2v11.5
h-6.7V28.2z"/>
<path class="st2" d="M258.2,53.6H252v-3.4h-0.1c-0.8,1.1-1.9,2-3.3,2.7c-1.4,0.7-2.8,1.2-4.3,1.4c-0.3,0-0.6,0.1-0.9,0.1
c-0.3,0-0.6,0-0.9,0c-2.2,0-4.1-0.4-5.8-1.1c-1.7-0.7-3.2-1.8-4.4-3.1c-1.1-1.2-2-2.6-2.6-4.2c-0.6-1.6-0.9-3.3-0.9-5
c0-1.8,0.3-3.4,0.8-4.9c0.6-1.5,1.5-2.9,2.7-4.2c1.4-1.5,3-2.6,4.7-3.3c1.7-0.7,3.6-1.1,5.7-1.1c1.9,0,3.7,0.4,5.3,1.1
c1.6,0.7,3,1.8,4.1,3.3v-3.6h6.2V53.6z M251.8,40.8c0-2.1-0.7-3.9-2.2-5.3c-1.5-1.5-3.4-2.2-5.8-2.1c-2.5,0-4.5,0.7-6,2.2
c-1.6,1.5-2.3,3.4-2.3,5.6c0,2.1,0.8,3.8,2.4,5.2c1.6,1.4,3.6,2.1,5.8,2.1c2.4,0,4.4-0.7,5.9-2.2C251.1,44.9,251.8,43,251.8,40.8
L251.8,40.8z"/>
</g>
<g>
<path class="st3" d="M34.9,43.9v20.6c0.9-0.2,1.7-0.4,2.5-0.9l17.1-9.8c2.5-1.4,4-4.1,4-7V27.3c0-0.8-0.1-1.6-0.4-2.3L39.6,35.7
C35.7,38.4,34.9,40.9,34.9,43.9z"/>
<path class="st4" d="M64.9,21l-6.8,3.9c0.2,0.7,0.4,1.5,0.4,2.3v19.6c0,2.9-1.6,5.6-4,7l-17.1,9.8c-0.8,0.4-1.6,0.7-2.5,0.9v7.8
c1.2-0.2,2.4-0.6,3.4-1.2l22.2-12.7c3.1-1.8,5-5.1,5-8.7V24.3C65.5,23.2,65.3,22.1,64.9,21z"/>
<path class="st5" d="M33.3,37.4c1-1.6,2.5-3.1,4.7-4.4l18.7-10.8c-0.6-0.8-1.4-1.5-2.2-2l-17.1-9.8c-2.5-1.4-5.6-1.4-8.1,0
l-17,9.8c-0.9,0.5-1.6,1.2-2.3,2L28.6,33C30.8,34.4,32.3,35.8,33.3,37.4z"/>
<path class="st6" d="M12.3,20.3l17-9.8c2.5-1.4,5.6-1.4,8.1,0l17.1,9.8c0.9,0.5,1.6,1.2,2.2,2l6.8-3.9c-0.8-1.1-1.8-2-3-2.6
L38.3,2.9c-3.1-1.8-6.9-1.8-10,0L6.3,15.7c-1.2,0.7-2.2,1.6-3,2.7l6.8,3.9C10.6,21.5,11.4,20.8,12.3,20.3z"/>
<path class="st7" d="M29.3,63.6l-17-9.8c-2.5-1.4-4-4.1-4-7V27.2c0-0.8,0.1-1.5,0.3-2.2l-6.8-3.9c-0.4,1.1-0.6,2.1-0.6,3.2v25.5
c0,3.6,1.9,6.9,5,8.6l22.1,12.7c1,0.6,2.2,1,3.4,1.2v-7.8C30.9,64.4,30.1,64.1,29.3,63.6z"/>
<path class="st8" d="M27,35.6L8.6,25c-0.2,0.7-0.3,1.5-0.3,2.2v19.6c0,2.9,1.5,5.6,4,7l17,9.8c0.8,0.4,1.6,0.7,2.5,0.9V43.9
C31.7,40.9,30.9,38.4,27,35.6z"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260.9 74"><style>.st2{fill:#fff}</style><g id="Ebene_1"><path class="st2" d="M88.8 19.7h6.7v11.1h.1c.7-1 1.7-1.7 2.9-2.3 1.2-.5 2.5-.9 3.8-1.1.3 0 .7-.1 1-.1h.9c4.1 0 7.5 1.4 10.1 4.1 2.6 2.7 3.9 5.9 3.9 9.4 0 .5 0 1.1-.1 1.6-.1.6-.2 1.1-.4 1.7-.3 1.1-.7 2.2-1.2 3.2s-1.2 2-1.9 2.7c-1.2 1.4-2.8 2.4-4.6 3.1-1.8.7-3.7 1.1-5.6 1.1-1.9 0-3.7-.3-5.3-1-1.6-.7-3-1.7-4.1-3.2h-.1v3.4h-6.2V19.7zm8.8 15.7c-1.7 1.4-2.5 3.1-2.5 5.2 0 2.2.8 4.1 2.3 5.6 1.5 1.5 3.6 2.3 6.1 2.3 2.4 0 4.3-.7 5.8-2.2 1.5-1.4 2.2-3.2 2.2-5.4 0-2.1-.7-3.9-2.2-5.4-1.5-1.5-3.4-2.2-5.8-2.2-2.3 0-4.2.7-5.9 2.1zM150.3 53.6h-6.2v-3.4h-.1c-.8 1.1-1.9 2-3.3 2.7-1.4.7-2.8 1.2-4.3 1.4-.3 0-.6.1-.9.1h-.9c-2.2 0-4.1-.4-5.8-1.1-1.7-.7-3.2-1.8-4.4-3.1-1.1-1.2-2-2.6-2.6-4.2-.6-1.6-.9-3.3-.9-5 0-1.8.3-3.4.8-4.9.6-1.5 1.5-2.9 2.7-4.2 1.4-1.5 3-2.6 4.7-3.3 1.7-.7 3.6-1.1 5.7-1.1 1.9 0 3.7.4 5.3 1.1 1.6.7 3 1.8 4.1 3.3v-3.6h6.2v25.3zM144 40.8c0-2.1-.7-3.9-2.2-5.3-1.5-1.5-3.4-2.2-5.8-2.1-2.5 0-4.5.7-6 2.2-1.6 1.5-2.3 3.4-2.3 5.6 0 2.1.8 3.8 2.4 5.2 1.6 1.4 3.6 2.1 5.8 2.1 2.4 0 4.4-.7 5.9-2.2 1.4-1.4 2.2-3.3 2.2-5.5zM155.3 19.7h6.7v33.9h-6.7V19.7zM173.3 43.6c.5 1.5 1.4 2.7 2.8 3.6 1.4.9 2.9 1.3 4.6 1.3 1.3 0 2.5-.2 3.6-.6 1.1-.4 2-.9 2.6-1.6h7.4c-.8 2.3-2.5 4.2-5.1 5.8-2.6 1.6-5.3 2.4-8.3 2.4-4.1 0-7.5-1.3-10.4-3.9-2.9-2.6-4.3-5.7-4.3-9.4 0-3.8 1.4-7 4.3-9.7 2.9-2.7 6.4-4 10.5-4 4 0 7.4 1.3 10.2 4 2.8 2.7 4.2 5.8 4.2 9.3 0 .4 0 .8-.1 1.2-.1.4-.1.8-.2 1.1 0 .1-.1.2-.1.3v.3h-21.7zm15.3-5.4c-.5-1.5-1.5-2.7-2.9-3.5-1.4-.9-3-1.3-4.7-1.3h-.4c-1.6.1-3.1.6-4.5 1.4-1.4.9-2.4 2-2.8 3.4h15.3zM199.7 28.2h6.2v2.3h.1c.8-.9 1.8-1.7 3-2.2 1.3-.5 2.6-.8 4-.9h1.4c1.3.1 2.6.4 3.9 1 1.3.5 2.3 1.3 3.3 2.2.1.1.3.2.4.3.1.1.2.2.3.4 1.1 1.4 1.7 2.8 1.9 4.4s.3 3.1.3 4.8v13.1h-6.7v-12-1.2c0-.4 0-.9-.1-1.3-.1-.7-.2-1.3-.4-1.9-.2-.6-.4-1.2-.8-1.7-.4-.6-1-1.1-1.8-1.5-.8-.4-1.5-.6-2.3-.6h-1c-.8.1-1.5.3-2.3.7-.7.4-1.3.9-1.7 1.5-.3.5-.6 1.1-.8 1.7-.2.7-.3 1.3-.3 2v14.3h-6.7V28.2zM258.2 53.6H252v-3.4h-.1c-.8 1.1-1.9 2-3.3 2.7-1.4.7-2.8 1.2-4.3 1.4-.3 0-.6.1-.9.1h-.9c-2.2 0-4.1-.4-5.8-1.1-1.7-.7-3.2-1.8-4.4-3.1-1.1-1.2-2-2.6-2.6-4.2-.6-1.6-.9-3.3-.9-5 0-1.8.3-3.4.8-4.9.6-1.5 1.5-2.9 2.7-4.2 1.4-1.5 3-2.6 4.7-3.3 1.7-.7 3.6-1.1 5.7-1.1 1.9 0 3.7.4 5.3 1.1 1.6.7 3 1.8 4.1 3.3v-3.6h6.2v25.3zm-6.4-12.8c0-2.1-.7-3.9-2.2-5.3-1.5-1.5-3.4-2.2-5.8-2.1-2.5 0-4.5.7-6 2.2-1.6 1.5-2.3 3.4-2.3 5.6 0 2.1.8 3.8 2.4 5.2 1.6 1.4 3.6 2.1 5.8 2.1 2.4 0 4.4-.7 5.9-2.2 1.5-1.4 2.2-3.3 2.2-5.5z"/><g><path d="M34.9 43.9v20.6c.9-.2 1.7-.4 2.5-.9l17.1-9.8c2.5-1.4 4-4.1 4-7V27.3c0-.8-.1-1.6-.4-2.3L39.6 35.7c-3.9 2.7-4.7 5.2-4.7 8.2z" fill="#ffc100"/><path d="M64.9 21l-6.8 3.9c.2.7.4 1.5.4 2.3v19.6c0 2.9-1.6 5.6-4 7l-17.1 9.8c-.8.4-1.6.7-2.5.9v7.8c1.2-.2 2.4-.6 3.4-1.2l22.2-12.7c3.1-1.8 5-5.1 5-8.7V24.3c0-1.1-.2-2.2-.6-3.3z" fill="#f6eb61"/><path d="M33.3 37.4c1-1.6 2.5-3.1 4.7-4.4l18.7-10.8c-.6-.8-1.4-1.5-2.2-2l-17.1-9.8c-2.5-1.4-5.6-1.4-8.1 0l-17 9.8c-.9.5-1.6 1.2-2.3 2L28.6 33c2.2 1.4 3.7 2.8 4.7 4.4z" fill="#439879"/><path d="M12.3 20.3l17-9.8c2.5-1.4 5.6-1.4 8.1 0l17.1 9.8c.9.5 1.6 1.2 2.2 2l6.8-3.9c-.8-1.1-1.8-2-3-2.6L38.3 2.9c-3.1-1.8-6.9-1.8-10 0l-22 12.8c-1.2.7-2.2 1.6-3 2.7l6.8 3.9c.5-.8 1.3-1.5 2.2-2z" fill="#28cdfb"/><path d="M29.3 63.6l-17-9.8c-2.5-1.4-4-4.1-4-7V27.2c0-.8.1-1.5.3-2.2l-6.8-3.9c-.4 1.1-.6 2.1-.6 3.2v25.5c0 3.6 1.9 6.9 5 8.6l22.1 12.7c1 .6 2.2 1 3.4 1.2v-7.8c-.8-.1-1.6-.4-2.4-.9z" fill="#fdd757"/><path d="M27 35.6L8.6 25c-.2.7-.3 1.5-.3 2.2v19.6c0 2.9 1.5 5.6 4 7l17 9.8c.8.4 1.6.7 2.5.9V43.9c-.1-3-.9-5.5-4.8-8.3z" fill="#ec8b00"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,18 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 134.229 134.229" enable-background="new 0 0 134.229 134.229"
xml:space="preserve">
<g>
<g>
<path fill="#FFFFFF" d="M21.343,112.528c2.317,0,4.195,1.875,4.195,4.189c0,2.319-1.878,4.201-4.195,4.201
c-2.32,0-4.199-1.882-4.199-4.201C17.144,114.403,19.022,112.528,21.343,112.528z"/>
<path fill="#FFFFFF" d="M131.246,110.53L119.604,5.8C119.25,2.615,116.047,0,112.48,0H21.754c-3.568,0-6.777,2.615-7.127,5.8
L2.984,110.53c0,0.129-0.061,0.232-0.061,0.359v11.667c0,6.437,5.237,11.673,11.667,11.673h105.05
c6.431,0,11.667-5.236,11.667-11.673v-11.667C131.307,110.762,131.246,110.652,131.246,110.53z M125.474,122.556
c0,3.222-2.631,5.84-5.84,5.84H14.59c-3.206,0-5.836-2.618-5.836-5.84v-11.667c0-3.221,2.63-5.839,5.836-5.839h105.05
c3.203,0,5.834,2.618,5.834,5.839V122.556L125.474,122.556z"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 134.229 134.229"><g fill="#FFF"><path d="M21.343 112.528a4.192 4.192 0 014.195 4.189 4.199 4.199 0 01-4.195 4.201 4.2 4.2 0 01-4.199-4.201 4.192 4.192 0 014.199-4.189z"/><path d="M131.246 110.53L119.604 5.8c-.354-3.185-3.557-5.8-7.124-5.8H21.754c-3.568 0-6.777 2.615-7.127 5.8L2.984 110.53c0 .129-.061.232-.061.359v11.667c0 6.437 5.237 11.673 11.667 11.673h105.05c6.431 0 11.667-5.236 11.667-11.673v-11.667c0-.127-.061-.237-.061-.359zm-5.772 12.026c0 3.222-2.631 5.84-5.84 5.84H14.59c-3.206 0-5.836-2.618-5.836-5.84v-11.667c0-3.221 2.63-5.839 5.836-5.839h105.05c3.203 0 5.834 2.618 5.834 5.839v11.667z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 667 B

View File

@ -1,79 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 412.1 74" style="enable-background:new 0 0 412.1 74;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{font-family:'ITCAvantGardeStd-Bold';}
.st3{font-size:46.2px;}
.st4{fill:#FFFFFF;}
.st5{fill:#A5DE37;}
.st6{fill:#C8F178;}
</style>
<g id="type" class="st0">
<text transform="matrix(1 0 0 1 264.4807 53.6223)" class="st1 st2 st3">Etcher</text>
</g>
<g id="Ebene_1">
<g>
<g>
<path class="st4" d="M88.8,19.7h6.7v11.1h0.1c0.7-1,1.7-1.7,2.9-2.3c1.2-0.5,2.5-0.9,3.8-1.1c0.3,0,0.7-0.1,1-0.1
c0.3,0,0.6,0,0.9,0c4.1,0,7.5,1.4,10.1,4.1c2.6,2.7,3.9,5.9,3.9,9.4c0,0.5,0,1.1-0.1,1.6c-0.1,0.6-0.2,1.1-0.4,1.7
c-0.3,1.1-0.7,2.2-1.2,3.2c-0.5,1-1.2,2-1.9,2.7c-1.2,1.4-2.8,2.4-4.6,3.1c-1.8,0.7-3.7,1.1-5.6,1.1c-1.9,0-3.7-0.3-5.3-1
c-1.6-0.7-3-1.7-4.1-3.2l-0.1,0v3.4h-6.2V19.7z M97.6,35.4c-1.7,1.4-2.5,3.1-2.5,5.2c0,2.2,0.8,4.1,2.3,5.6
c1.5,1.5,3.6,2.3,6.1,2.3c2.4,0,4.3-0.7,5.8-2.2c1.5-1.4,2.2-3.2,2.2-5.4c0-2.1-0.7-3.9-2.2-5.4c-1.5-1.5-3.4-2.2-5.8-2.2
C101.2,33.3,99.3,34,97.6,35.4z"/>
<path class="st4" d="M150.3,53.6h-6.2v-3.4h-0.1c-0.8,1.1-1.9,2-3.3,2.7c-1.4,0.7-2.8,1.2-4.3,1.4c-0.3,0-0.6,0.1-0.9,0.1
c-0.3,0-0.6,0-0.9,0c-2.2,0-4.1-0.4-5.8-1.1c-1.7-0.7-3.2-1.8-4.4-3.1c-1.1-1.2-2-2.6-2.6-4.2c-0.6-1.6-0.9-3.3-0.9-5
c0-1.8,0.3-3.4,0.8-4.9c0.6-1.5,1.5-2.9,2.7-4.2c1.4-1.5,3-2.6,4.7-3.3c1.7-0.7,3.6-1.1,5.7-1.1c1.9,0,3.7,0.4,5.3,1.1
c1.6,0.7,3,1.8,4.1,3.3v-3.6h6.2V53.6z M144,40.8c0-2.1-0.7-3.9-2.2-5.3c-1.5-1.5-3.4-2.2-5.8-2.1c-2.5,0-4.5,0.7-6,2.2
c-1.6,1.5-2.3,3.4-2.3,5.6c0,2.1,0.8,3.8,2.4,5.2c1.6,1.4,3.6,2.1,5.8,2.1c2.4,0,4.4-0.7,5.9-2.2C143.2,44.9,144,43,144,40.8
L144,40.8z"/>
<path class="st4" d="M155.3,19.7h6.7v33.9h-6.7V19.7z"/>
<path class="st4" d="M173.3,43.6c0.5,1.5,1.4,2.7,2.8,3.6c1.4,0.9,2.9,1.3,4.6,1.3c1.3,0,2.5-0.2,3.6-0.6c1.1-0.4,2-0.9,2.6-1.6
l7.4,0c-0.8,2.3-2.5,4.2-5.1,5.8c-2.6,1.6-5.3,2.4-8.3,2.4c-4.1,0-7.5-1.3-10.4-3.9c-2.9-2.6-4.3-5.7-4.3-9.4
c0-3.8,1.4-7,4.3-9.7c2.9-2.7,6.4-4,10.5-4c4,0,7.4,1.3,10.2,4c2.8,2.7,4.2,5.8,4.2,9.3c0,0.4,0,0.8-0.1,1.2
c-0.1,0.4-0.1,0.8-0.2,1.1c0,0.1-0.1,0.2-0.1,0.3c0,0.1,0,0.2,0,0.3H173.3z M188.6,38.2c-0.5-1.5-1.5-2.7-2.9-3.5
c-1.4-0.9-3-1.3-4.7-1.3c-0.1,0-0.1,0-0.2,0c-0.1,0-0.1,0-0.2,0c-1.6,0.1-3.1,0.6-4.5,1.4c-1.4,0.9-2.4,2-2.8,3.4H188.6z"/>
<path class="st4" d="M199.7,28.2h6.2v2.3h0.1c0.8-0.9,1.8-1.7,3-2.2c1.3-0.5,2.6-0.8,4-0.9c0.1,0,0.2,0,0.3,0c0.1,0,0.2,0,0.3,0
c0.1,0,0.3,0,0.4,0c0.1,0,0.3,0,0.4,0c1.3,0.1,2.6,0.4,3.9,1c1.3,0.5,2.3,1.3,3.3,2.2c0.1,0.1,0.3,0.2,0.4,0.3
c0.1,0.1,0.2,0.2,0.3,0.4c1.1,1.4,1.7,2.8,1.9,4.4s0.3,3.1,0.3,4.8v13.1h-6.7v-12c0-0.4,0-0.8,0-1.2c0-0.4,0-0.9-0.1-1.3
c-0.1-0.7-0.2-1.3-0.4-1.9c-0.2-0.6-0.4-1.2-0.8-1.7c-0.4-0.6-1-1.1-1.8-1.5c-0.8-0.4-1.5-0.6-2.3-0.6c0,0-0.1,0-0.1,0
c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.4,0c-0.8,0.1-1.5,0.3-2.3,0.7c-0.7,0.4-1.3,0.9-1.7,1.5
c-0.3,0.5-0.6,1.1-0.8,1.7c-0.2,0.7-0.3,1.3-0.3,2c0,0.4,0,0.8,0,1.2c0,0.4,0,0.8,0,1.1c0,0.1,0,0.2,0,0.3c0,0.1,0,0.1,0,0.2
v11.5h-6.7V28.2z"/>
<path class="st4" d="M258.2,53.6H252v-3.4h-0.1c-0.8,1.1-1.9,2-3.3,2.7c-1.4,0.7-2.8,1.2-4.3,1.4c-0.3,0-0.6,0.1-0.9,0.1
c-0.3,0-0.6,0-0.9,0c-2.2,0-4.1-0.4-5.8-1.1c-1.7-0.7-3.2-1.8-4.4-3.1c-1.1-1.2-2-2.6-2.6-4.2c-0.6-1.6-0.9-3.3-0.9-5
c0-1.8,0.3-3.4,0.8-4.9c0.6-1.5,1.5-2.9,2.7-4.2c1.4-1.5,3-2.6,4.7-3.3c1.7-0.7,3.6-1.1,5.7-1.1c1.9,0,3.7,0.4,5.3,1.1
c1.6,0.7,3,1.8,4.1,3.3v-3.6h6.2V53.6z M251.8,40.8c0-2.1-0.7-3.9-2.2-5.3c-1.5-1.5-3.4-2.2-5.8-2.1c-2.5,0-4.5,0.7-6,2.2
c-1.6,1.5-2.3,3.4-2.3,5.6c0,2.1,0.8,3.8,2.4,5.2c1.6,1.4,3.6,2.1,5.8,2.1c2.4,0,4.4-0.7,5.9-2.2C251.1,44.9,251.8,43,251.8,40.8
L251.8,40.8z"/>
</g>
<g>
<path class="st5" d="M34.9,43.9v20.6c0.9-0.2,1.7-0.4,2.5-0.9l17.1-9.8c2.5-1.4,4-4.1,4-7V27.3c0-0.8-0.1-1.6-0.4-2.3L39.6,35.7
C35.7,38.4,34.9,40.9,34.9,43.9z"/>
<path class="st6" d="M64.9,21l-6.8,3.9c0.2,0.7,0.4,1.5,0.4,2.3v19.6c0,2.9-1.6,5.6-4,7l-17.1,9.8c-0.8,0.4-1.6,0.7-2.5,0.9v7.8
c1.2-0.2,2.4-0.6,3.4-1.2l22.2-12.7c3.1-1.8,5-5.1,5-8.7V24.3C65.5,23.2,65.3,22.1,64.9,21z"/>
<path class="st5" d="M33.3,37.4c1-1.6,2.5-3.1,4.7-4.4l18.7-10.8c-0.6-0.8-1.4-1.5-2.2-2l-17.1-9.8c-2.5-1.4-5.6-1.4-8.1,0
l-17,9.8c-0.9,0.5-1.6,1.2-2.3,2L28.6,33C30.8,34.4,32.3,35.8,33.3,37.4z"/>
<path class="st6" d="M12.3,20.3l17-9.8c2.5-1.4,5.6-1.4,8.1,0l17.1,9.8c0.9,0.5,1.6,1.2,2.2,2l6.8-3.9c-0.8-1.1-1.8-2-3-2.6
L38.3,2.9c-3.1-1.8-6.9-1.8-10,0L6.3,15.7c-1.2,0.7-2.2,1.6-3,2.7l6.8,3.9C10.6,21.5,11.4,20.8,12.3,20.3z"/>
<path class="st6" d="M29.3,63.6l-17-9.8c-2.5-1.4-4-4.1-4-7V27.2c0-0.8,0.1-1.5,0.3-2.2l-6.8-3.9c-0.4,1.1-0.6,2.1-0.6,3.2v25.5
c0,3.6,1.9,6.9,5,8.6l22.1,12.7c1,0.6,2.2,1,3.4,1.2v-7.8C30.9,64.4,30.1,64.1,29.3,63.6z"/>
<path class="st5" d="M27,35.6L8.6,25c-0.2,0.7-0.3,1.5-0.3,2.2v19.6c0,2.9,1.5,5.6,4,7l17,9.8c0.8,0.4,1.6,0.7,2.5,0.9V43.9
C31.7,40.9,30.9,38.4,27,35.6z"/>
</g>
<path class="st5" d="M267.6,19.4h19.4v7.7h-10.6v5.3h10.3v7.7h-10.3V46h10.6v7.7h-19.4V19.4z"/>
<path class="st5" d="M294.3,33.8h-3.8V28h3.8v-8.5h7.7V28h3.7v5.8H302v19.8h-7.7V33.8z"/>
<path class="st5" d="M334.5,43.9c-1.4,5.8-6.5,10.6-13.4,10.6c-7.8,0-13.7-6.1-13.7-13.7c0-7.5,5.9-13.6,13.5-13.6
c6.8,0,12.3,4.5,13.6,10.8h-7.8c-0.8-1.8-2.4-3.6-5.5-3.6c-1.8-0.1-3.3,0.6-4.4,1.8c-1.1,1.2-1.7,2.9-1.7,4.7
c0,3.7,2.4,6.5,6.1,6.5c3.2,0,4.7-1.8,5.5-3.4H334.5z"/>
<path class="st5" d="M338,19.4h7.7v7.7v3.2c1.4-2.3,4-3.2,6.7-3.2c3.9,0,6.2,1.4,7.6,3.6c1.4,2.2,1.8,5.3,1.8,8.5v14.3h-7.7v-14
c0-1.4-0.2-2.8-0.8-3.7c-0.6-1-1.7-1.6-3.3-1.6c-2.1,0-3.2,1-3.7,2.1c-0.6,1.1-0.6,2.4-0.6,3v14.2H338V19.4z"/>
<path class="st5" d="M373.5,43.5c0.3,2.7,2.9,4.5,5.9,4.5c2.4,0,3.7-1.1,4.7-2.4h7.9c-1.2,2.9-3,5.1-5.2,6.6
c-2.1,1.5-4.7,2.3-7.3,2.3c-7.3,0-13.6-6-13.6-13.6c0-7.2,5.6-13.8,13.4-13.8c3.9,0,7.3,1.5,9.7,4.1c3.2,3.5,4.2,7.6,3.6,12.3
H373.5z M385,37.6c-0.2-1.2-1.8-4.1-5.7-4.1c-4,0-5.5,2.9-5.7,4.1H385z"/>
<path class="st5" d="M397,28h7.2v2.9c0.7-1.4,2.1-3.7,6.5-3.7v7.7h-0.3c-3.9,0-5.8,1.4-5.8,5v13.8H397V28z"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 412.1 74"><style>.st4{fill:#fff}.st5{fill:#a5de37}.st6{fill:#c8f178}</style><g id="Ebene_1"><path class="st4" d="M88.8 19.7h6.7v11.1h.1c.7-1 1.7-1.7 2.9-2.3 1.2-.5 2.5-.9 3.8-1.1.3 0 .7-.1 1-.1h.9c4.1 0 7.5 1.4 10.1 4.1 2.6 2.7 3.9 5.9 3.9 9.4 0 .5 0 1.1-.1 1.6-.1.6-.2 1.1-.4 1.7-.3 1.1-.7 2.2-1.2 3.2s-1.2 2-1.9 2.7c-1.2 1.4-2.8 2.4-4.6 3.1-1.8.7-3.7 1.1-5.6 1.1-1.9 0-3.7-.3-5.3-1-1.6-.7-3-1.7-4.1-3.2h-.1v3.4h-6.2V19.7zm8.8 15.7c-1.7 1.4-2.5 3.1-2.5 5.2 0 2.2.8 4.1 2.3 5.6 1.5 1.5 3.6 2.3 6.1 2.3 2.4 0 4.3-.7 5.8-2.2 1.5-1.4 2.2-3.2 2.2-5.4 0-2.1-.7-3.9-2.2-5.4-1.5-1.5-3.4-2.2-5.8-2.2-2.3 0-4.2.7-5.9 2.1zM150.3 53.6h-6.2v-3.4h-.1c-.8 1.1-1.9 2-3.3 2.7-1.4.7-2.8 1.2-4.3 1.4-.3 0-.6.1-.9.1h-.9c-2.2 0-4.1-.4-5.8-1.1-1.7-.7-3.2-1.8-4.4-3.1-1.1-1.2-2-2.6-2.6-4.2-.6-1.6-.9-3.3-.9-5 0-1.8.3-3.4.8-4.9.6-1.5 1.5-2.9 2.7-4.2 1.4-1.5 3-2.6 4.7-3.3 1.7-.7 3.6-1.1 5.7-1.1 1.9 0 3.7.4 5.3 1.1 1.6.7 3 1.8 4.1 3.3v-3.6h6.2v25.3zM144 40.8c0-2.1-.7-3.9-2.2-5.3-1.5-1.5-3.4-2.2-5.8-2.1-2.5 0-4.5.7-6 2.2-1.6 1.5-2.3 3.4-2.3 5.6 0 2.1.8 3.8 2.4 5.2 1.6 1.4 3.6 2.1 5.8 2.1 2.4 0 4.4-.7 5.9-2.2 1.4-1.4 2.2-3.3 2.2-5.5zM155.3 19.7h6.7v33.9h-6.7V19.7zM173.3 43.6c.5 1.5 1.4 2.7 2.8 3.6 1.4.9 2.9 1.3 4.6 1.3 1.3 0 2.5-.2 3.6-.6 1.1-.4 2-.9 2.6-1.6h7.4c-.8 2.3-2.5 4.2-5.1 5.8-2.6 1.6-5.3 2.4-8.3 2.4-4.1 0-7.5-1.3-10.4-3.9-2.9-2.6-4.3-5.7-4.3-9.4 0-3.8 1.4-7 4.3-9.7 2.9-2.7 6.4-4 10.5-4 4 0 7.4 1.3 10.2 4 2.8 2.7 4.2 5.8 4.2 9.3 0 .4 0 .8-.1 1.2-.1.4-.1.8-.2 1.1 0 .1-.1.2-.1.3v.3h-21.7zm15.3-5.4c-.5-1.5-1.5-2.7-2.9-3.5-1.4-.9-3-1.3-4.7-1.3h-.4c-1.6.1-3.1.6-4.5 1.4-1.4.9-2.4 2-2.8 3.4h15.3zM199.7 28.2h6.2v2.3h.1c.8-.9 1.8-1.7 3-2.2 1.3-.5 2.6-.8 4-.9h1.4c1.3.1 2.6.4 3.9 1 1.3.5 2.3 1.3 3.3 2.2.1.1.3.2.4.3.1.1.2.2.3.4 1.1 1.4 1.7 2.8 1.9 4.4s.3 3.1.3 4.8v13.1h-6.7v-12-1.2c0-.4 0-.9-.1-1.3-.1-.7-.2-1.3-.4-1.9-.2-.6-.4-1.2-.8-1.7-.4-.6-1-1.1-1.8-1.5-.8-.4-1.5-.6-2.3-.6h-1c-.8.1-1.5.3-2.3.7-.7.4-1.3.9-1.7 1.5-.3.5-.6 1.1-.8 1.7-.2.7-.3 1.3-.3 2v14.3h-6.7V28.2zM258.2 53.6H252v-3.4h-.1c-.8 1.1-1.9 2-3.3 2.7-1.4.7-2.8 1.2-4.3 1.4-.3 0-.6.1-.9.1h-.9c-2.2 0-4.1-.4-5.8-1.1-1.7-.7-3.2-1.8-4.4-3.1-1.1-1.2-2-2.6-2.6-4.2-.6-1.6-.9-3.3-.9-5 0-1.8.3-3.4.8-4.9.6-1.5 1.5-2.9 2.7-4.2 1.4-1.5 3-2.6 4.7-3.3 1.7-.7 3.6-1.1 5.7-1.1 1.9 0 3.7.4 5.3 1.1 1.6.7 3 1.8 4.1 3.3v-3.6h6.2v25.3zm-6.4-12.8c0-2.1-.7-3.9-2.2-5.3-1.5-1.5-3.4-2.2-5.8-2.1-2.5 0-4.5.7-6 2.2-1.6 1.5-2.3 3.4-2.3 5.6 0 2.1.8 3.8 2.4 5.2 1.6 1.4 3.6 2.1 5.8 2.1 2.4 0 4.4-.7 5.9-2.2 1.5-1.4 2.2-3.3 2.2-5.5z"/><path class="st5" d="M34.9 43.9v20.6c.9-.2 1.7-.4 2.5-.9l17.1-9.8c2.5-1.4 4-4.1 4-7V27.3c0-.8-.1-1.6-.4-2.3L39.6 35.7c-3.9 2.7-4.7 5.2-4.7 8.2z"/><path class="st6" d="M64.9 21l-6.8 3.9c.2.7.4 1.5.4 2.3v19.6c0 2.9-1.6 5.6-4 7l-17.1 9.8c-.8.4-1.6.7-2.5.9v7.8c1.2-.2 2.4-.6 3.4-1.2l22.2-12.7c3.1-1.8 5-5.1 5-8.7V24.3c0-1.1-.2-2.2-.6-3.3z"/><path class="st5" d="M33.3 37.4c1-1.6 2.5-3.1 4.7-4.4l18.7-10.8c-.6-.8-1.4-1.5-2.2-2l-17.1-9.8c-2.5-1.4-5.6-1.4-8.1 0l-17 9.8c-.9.5-1.6 1.2-2.3 2L28.6 33c2.2 1.4 3.7 2.8 4.7 4.4z"/><path class="st6" d="M12.3 20.3l17-9.8c2.5-1.4 5.6-1.4 8.1 0l17.1 9.8c.9.5 1.6 1.2 2.2 2l6.8-3.9c-.8-1.1-1.8-2-3-2.6L38.3 2.9c-3.1-1.8-6.9-1.8-10 0l-22 12.8c-1.2.7-2.2 1.6-3 2.7l6.8 3.9c.5-.8 1.3-1.5 2.2-2zM29.3 63.6l-17-9.8c-2.5-1.4-4-4.1-4-7V27.2c0-.8.1-1.5.3-2.2l-6.8-3.9c-.4 1.1-.6 2.1-.6 3.2v25.5c0 3.6 1.9 6.9 5 8.6l22.1 12.7c1 .6 2.2 1 3.4 1.2v-7.8c-.8-.1-1.6-.4-2.4-.9z"/><path class="st5" d="M27 35.6L8.6 25c-.2.7-.3 1.5-.3 2.2v19.6c0 2.9 1.5 5.6 4 7l17 9.8c.8.4 1.6.7 2.5.9V43.9c-.1-3-.9-5.5-4.8-8.3zM267.6 19.4H287v7.7h-10.6v5.3h10.3v7.7h-10.3V46H287v7.7h-19.4V19.4zM294.3 33.8h-3.8V28h3.8v-8.5h7.7V28h3.7v5.8H302v19.8h-7.7V33.8zM334.5 43.9c-1.4 5.8-6.5 10.6-13.4 10.6-7.8 0-13.7-6.1-13.7-13.7 0-7.5 5.9-13.6 13.5-13.6 6.8 0 12.3 4.5 13.6 10.8h-7.8c-.8-1.8-2.4-3.6-5.5-3.6-1.8-.1-3.3.6-4.4 1.8-1.1 1.2-1.7 2.9-1.7 4.7 0 3.7 2.4 6.5 6.1 6.5 3.2 0 4.7-1.8 5.5-3.4h7.8zM338 19.4h7.7v10.9c1.4-2.3 4-3.2 6.7-3.2 3.9 0 6.2 1.4 7.6 3.6 1.4 2.2 1.8 5.3 1.8 8.5v14.3h-7.7v-14c0-1.4-.2-2.8-.8-3.7-.6-1-1.7-1.6-3.3-1.6-2.1 0-3.2 1-3.7 2.1-.6 1.1-.6 2.4-.6 3v14.2H338V19.4zM373.5 43.5c.3 2.7 2.9 4.5 5.9 4.5 2.4 0 3.7-1.1 4.7-2.4h7.9c-1.2 2.9-3 5.1-5.2 6.6-2.1 1.5-4.7 2.3-7.3 2.3-7.3 0-13.6-6-13.6-13.6 0-7.2 5.6-13.8 13.4-13.8 3.9 0 7.3 1.5 9.7 4.1 3.2 3.5 4.2 7.6 3.6 12.3h-19.1zm11.5-5.9c-.2-1.2-1.8-4.1-5.7-4.1-4 0-5.5 2.9-5.7 4.1H385zM397 28h7.2v2.9c.7-1.4 2.1-3.7 6.5-3.7v7.7h-.3c-3.9 0-5.8 1.4-5.8 5v13.8H397V28z"/></g></svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,18 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="40px" viewBox="0 0 27 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
<title>Combined Shape</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Steps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Step-3/flash-image/flash-default-Copy" transform="translate(-692.000000, -168.000000)" fill="#FFFFFF">
<g id="main-UI" transform="translate(62.000000, 55.000000)">
<g id="Group-2" transform="translate(91.000000, 111.000000)">
<g id="Group-8" transform="translate(467.000000, 2.000000)">
<path d="M88.0046509,10.6971076 L93.1286727,0 L80.7751206,0 L72,18.3192841 L83.6485427,18.3192841 L80.1109889,40 L98.9145135,10.6334372 L88.0046509,10.6971076 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
<svg width="27" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M16.005 10.697L21.129 0H8.775L0 18.32h11.649L8.11 40l18.804-29.367-10.91.064z" fill="#FFF" fill-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 190 B

View File

@ -1,14 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 21 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
<title>Combined Shape</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="select-image/-category-copy-12" transform="translate(-407.000000, -109.000000)" fill-rule="nonzero" fill="#FFFFFF">
<g id="Group-7" transform="translate(407.000000, 109.000000)">
<path d="M21,7.51607355 L21,15.4875215 C21,16.7481894 20.3246037,17.9129891 19.2246726,18.5409264 L12.2777395,22.529047 C11.1778084,23.1569843 9.82701583,23.1569843 8.72708475,22.529047 L1.78015162,18.5409264 C0.680220536,17.9129891 0,16.7481894 0,15.4875215 L0,7.51607355 C0,6.2554056 0.680220536,5.09060595 1.78015162,4.46266868 L8.72708475,0.474548012 C9.82701583,-0.158182671 11.1778084,-0.158182671 12.2777395,0.474548012 L19.2246726,4.46266868 C20.3246037,5.09060595 21,6.2554056 21,7.51607355 Z M9.26574803,15.3966378 C9.26574803,16.0895512 9.80708661,16.6308898 10.5,16.6308898 C11.1712598,16.6308898 11.734252,16.0895512 11.734252,15.3966378 L11.734252,12.3867953 L14.8090551,12.3867953 C15.4586614,12.3867953 16,11.8671102 16,11.1958504 C16,10.5462441 15.4586614,10.0049055 14.8090551,10.0049055 L11.734252,10.0049055 L11.734252,6.99506299 C11.734252,6.30214961 11.1712598,5.76081102 10.5,5.76081102 C9.80708661,5.76081102 9.26574803,6.30214961 9.26574803,6.99506299 L9.26574803,10.0049055 L6.19094488,10.0049055 C5.54133858,10.0049055 5,10.5462441 5,11.1958504 C5,11.8671102 5.54133858,12.3867953 6.19094488,12.3867953 L9.26574803,12.3867953 L9.26574803,15.3966378 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</svg>
<svg viewBox="0 0 21 23" xmlns="http://www.w3.org/2000/svg"><path d="M21 7.516v7.972c0 1.26-.675 2.425-1.775 3.053l-6.947 3.988c-1.1.628-2.451.628-3.55 0L1.78 18.541A3.52 3.52 0 010 15.488V7.516c0-1.26.68-2.425 1.78-3.053L8.727.475a3.558 3.558 0 013.55 0l6.948 3.988A3.515 3.515 0 0121 7.516zm-11.734 7.88a1.22 1.22 0 001.234 1.235c.671 0 1.234-.541 1.234-1.234v-3.01h3.075c.65 0 1.191-.52 1.191-1.191 0-.65-.541-1.191-1.19-1.191h-3.076v-3.01c0-.693-.563-1.234-1.234-1.234a1.22 1.22 0 00-1.234 1.234v3.01H6.19c-.65 0-1.191.541-1.191 1.19 0 .672.541 1.192 1.19 1.192h3.076v3.01z" fill-rule="nonzero" fill="#FFF"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 618 B

View File

@ -1,12 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 50 46" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
<title>like</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Steps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="like" fill-rule="nonzero" fill="#F55F50">
<path d="M24.85,8.126 C26.868,3.343 31.478,0.001 36.84,0.001 C44.063,0.001 49.265,6.18 49.919,13.544 C49.919,13.544 50.272,15.372 49.495,18.663 C48.437,23.145 45.95,27.127 42.597,30.166 L24.85,46 L7.402,30.165 C4.049,27.127 1.562,23.144 0.504,18.662 C-0.273,15.371 0.08,13.543 0.08,13.543 C0.734,6.179 5.936,0 13.159,0 C18.522,0 22.832,3.343 24.85,8.126 Z" id="Shape"></path>
</g>
</g>
</svg>
<svg viewBox="0 0 50 46" xmlns="http://www.w3.org/2000/svg"><path d="M24.85 8.126C26.868 3.343 31.478.001 36.84.001c7.223 0 12.425 6.179 13.079 13.543 0 0 .353 1.828-.424 5.119-1.058 4.482-3.545 8.464-6.898 11.503L24.85 46 7.402 30.165c-3.353-3.038-5.84-7.021-6.898-11.503-.777-3.291-.424-5.119-.424-5.119C.734 6.179 5.936 0 13.159 0c5.363 0 9.673 3.343 11.691 8.126z" fill-rule="nonzero" fill="#F55F50"/></svg>

Before

Width:  |  Height:  |  Size: 876 B

After

Width:  |  Height:  |  Size: 411 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,12 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="39" height="90" viewBox="0 0 39 90">
<g fill="none" fill-rule="evenodd">
<path fill="#2A506F" fill-rule="nonzero" d="M30.88 39.87H7.517v23.21c0 .69.561 1.25 1.251 1.25H29.63c.692 0 1.251-.56 1.251-1.25V39.87zm-22.363 1H29.88v22.21c0 .138-.112.25-.25.25H8.767l-.057-.007c-.11-.026-.194-.125-.194-.244V40.87z" transform="translate(.5)"/>
<path fill="#2A506F" fill-rule="nonzero" d="M16.558 48.925H12.59c-.583 0-1.055.471-1.055 1.055v2.732c0 .582.472 1.054 1.055 1.054h3.967c.582 0 1.054-.472 1.054-1.054v-2.733c0-.582-.472-1.054-1.054-1.054zm-3.967 1h3.967c.03 0 .054.024.054.055v2.732c0 .03-.025.054-.054.054H12.59c-.03 0-.055-.024-.055-.054v-2.733c0-.03.024-.054.055-.054zM25.97 48.925h-3.967c-.583 0-1.055.471-1.055 1.055v2.732c0 .582.472 1.054 1.055 1.054h3.967c.582 0 1.054-.472 1.054-1.054v-2.733c0-.582-.472-1.054-1.054-1.054zm-3.967 1h3.967c.03 0 .054.024.054.055v2.732c0 .03-.025.054-.054.054h-3.967c-.03 0-.055-.024-.055-.054v-2.733c0-.03.024-.054.055-.054z" transform="translate(.5)"/>
<path fill="#2A506F" d="M37.398 35.952c0 2.43-1.988 4.418-4.418 4.418H5.418C2.988 40.37 1 38.382 1 35.952V5.418C1 2.988 2.988 1 5.418 1H32.98c2.43 0 4.418 1.988 4.418 4.418v30.534z" transform="translate(.5)"/>
<path fill="#2A506F" fill-rule="nonzero" d="M32.98 0H5.418C2.436 0 0 2.436 0 5.418v30.534c0 2.982 2.436 5.418 5.418 5.418H32.98c2.982 0 5.418-2.436 5.418-5.418V5.418C38.398 2.436 35.962 0 32.98 0zM5.418 2H32.98c1.878 0 3.418 1.54 3.418 3.418v30.534c0 1.878-1.54 3.418-3.418 3.418H5.418C3.54 39.37 2 37.83 2 35.952V5.418C2 3.54 3.54 2 5.418 2z" transform="translate(.5)"/>
<path fill="#FFF" fill-rule="nonzero" d="M13.567 25v-8.634h2.918v-1.031H9.413v1.031h2.917V25h1.237zm5.869 3.3c.56 0 1.063-.066 1.51-.199.447-.132.828-.311 1.142-.537.314-.226.555-.489.722-.789.167-.3.25-.616.25-.95 0-.6-.208-1.034-.626-1.304-.417-.27-1.043-.405-1.878-.405H19.17c-.491 0-.825-.074-1.002-.221-.177-.147-.265-.334-.265-.56 0-.196.044-.36.132-.493.089-.133.197-.253.324-.361.167.078.344.14.53.184.187.044.37.066.546.066.363 0 .705-.059 1.024-.177.32-.118.597-.282.832-.493.236-.211.423-.472.56-.781.138-.31.207-.656.207-1.039 0-.304-.057-.584-.17-.84-.113-.255-.253-.466-.42-.633h1.474v-.928h-2.49c-.138-.05-.293-.091-.465-.126-.171-.034-.356-.051-.552-.051-.363 0-.71.059-1.039.177-.329.117-.616.287-.862.508-.245.22-.44.489-.582.803-.142.314-.213.668-.213 1.06 0 .433.096.813.287 1.142.192.33.405.592.641.789v.059c-.187.127-.363.304-.53.53-.167.226-.25.491-.25.796 0 .285.06.523.183.714.123.192.273.342.45.45v.059c-.324.225-.58.476-.766.75-.187.276-.28.566-.28.87 0 .315.07.59.213.825.143.236.344.437.604.604.26.167.572.293.936.376.363.084.766.125 1.208.125zm0-6.38c-.206 0-.4-.039-.582-.117-.182-.079-.344-.192-.486-.339-.143-.147-.253-.327-.332-.538-.078-.211-.118-.45-.118-.714 0-.53.148-.94.442-1.23.295-.29.654-.435 1.076-.435.422 0 .78.145 1.076.434.294.29.442.7.442 1.23 0 .266-.04.504-.118.715-.079.211-.19.39-.332.538-.142.147-.304.26-.486.339-.182.078-.376.118-.582.118zm.177 5.54c-.648 0-1.157-.112-1.525-.338-.368-.226-.553-.53-.553-.914 0-.206.06-.412.177-.619.118-.206.305-.402.56-.589.157.05.317.081.479.096.162.015.312.022.45.022h1.237c.471 0 .83.064 1.075.191.246.128.369.359.369.693 0 .186-.054.368-.162.545-.108.177-.26.332-.457.464-.197.133-.435.24-.715.324-.28.084-.591.125-.935.125zm7.077-2.283c.225 0 .454-.027.685-.081.23-.054.444-.116.64-.184l-.235-.914c-.118.05-.25.093-.398.133-.147.039-.285.059-.413.059-.412 0-.7-.12-.861-.361-.162-.241-.244-.582-.244-1.024v-3.978h1.93v-.987h-1.93v-2.004h-1.016L24.7 17.84l-1.12.073v.914h1.06v3.963c0 .354.035.678.104.972.068.295.184.546.346.752.162.206.373.368.634.486.26.118.581.177.965.177z" transform="translate(.5)"/>
<path fill="#2A506F" fill-rule="nonzero" d="M19.147 73.55c.245 0 .45.178.492.41l.008.09v14.883c0 .276-.224.5-.5.5-.245 0-.45-.177-.492-.41l-.008-.09V74.05c0-.276.224-.5.5-.5z" transform="translate(.5)"/>
<path fill="#2A506F" fill-rule="nonzero" d="M14.182 83.856c.176-.171.446-.188.639-.05l.068.058 4.615 4.719c.194.197.19.514-.007.707-.176.172-.446.188-.639.05l-.068-.058-4.615-4.719c-.194-.197-.19-.514.007-.707z" transform="translate(.5)"/>
<path fill="#2A506F" fill-rule="nonzero" d="M23.516 83.96c.198-.193.514-.19.707.008.172.175.188.445.051.638l-.058.07-4.72 4.614c-.197.193-.513.19-.706-.008-.172-.175-.188-.445-.051-.638l.058-.069 4.72-4.615z" transform="translate(.5)"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="39" height="90"><g fill="none" fill-rule="evenodd"><path fill="#2A506F" fill-rule="nonzero" d="M31.38 39.87H8.017v23.21c0 .69.561 1.25 1.251 1.25H30.13a1.25 1.25 0 001.251-1.25V39.87zm-22.363 1H30.38v22.21a.25.25 0 01-.25.25H9.267l-.057-.007a.252.252 0 01-.194-.244V40.87z"/><path fill="#2A506F" fill-rule="nonzero" d="M17.058 48.925H13.09c-.583 0-1.055.471-1.055 1.055v2.732c0 .582.472 1.054 1.055 1.054h3.967c.582 0 1.054-.472 1.054-1.054v-2.733c0-.582-.472-1.054-1.054-1.054zm-3.967 1h3.967c.03 0 .054.024.054.055v2.732c0 .03-.025.054-.054.054H13.09a.055.055 0 01-.055-.054v-2.733c0-.03.024-.054.055-.054zm13.379-1h-3.967c-.583 0-1.055.471-1.055 1.055v2.732c0 .582.472 1.054 1.055 1.054h3.967c.582 0 1.054-.472 1.054-1.054v-2.733c0-.582-.472-1.054-1.054-1.054zm-3.967 1h3.967c.03 0 .054.024.054.055v2.732c0 .03-.025.054-.054.054h-3.967a.055.055 0 01-.055-.054v-2.733c0-.03.024-.054.055-.054z"/><path fill="#2A506F" d="M37.898 35.952a4.43 4.43 0 01-4.418 4.418H5.918A4.43 4.43 0 011.5 35.952V5.418A4.43 4.43 0 015.918 1H33.48a4.43 4.43 0 014.418 4.418v30.534z"/><path fill="#2A506F" fill-rule="nonzero" d="M33.48 0H5.918A5.431 5.431 0 00.5 5.418v30.534a5.431 5.431 0 005.418 5.418H33.48a5.431 5.431 0 005.418-5.418V5.418A5.431 5.431 0 0033.48 0zM5.918 2H33.48a3.43 3.43 0 013.418 3.418v30.534a3.43 3.43 0 01-3.418 3.418H5.918A3.43 3.43 0 012.5 35.952V5.418A3.43 3.43 0 015.918 2z"/><path fill="#FFF" fill-rule="nonzero" d="M14.067 25v-8.634h2.918v-1.031H9.913v1.031h2.917V25h1.237zm5.869 3.3a5.29 5.29 0 001.51-.199 3.765 3.765 0 001.142-.537c.314-.226.555-.489.722-.789.167-.3.25-.616.25-.95 0-.6-.208-1.034-.626-1.304-.417-.27-1.043-.405-1.878-.405H19.67c-.491 0-.825-.074-1.002-.221a.697.697 0 01-.265-.56c0-.196.044-.36.132-.493.089-.133.197-.253.324-.361.167.078.344.14.53.184.187.044.37.066.546.066a2.93 2.93 0 001.024-.177 2.55 2.55 0 00.832-.493c.236-.211.423-.472.56-.781.138-.31.207-.656.207-1.039 0-.304-.057-.584-.17-.84a2.068 2.068 0 00-.42-.633h1.474v-.928h-2.49a3.308 3.308 0 00-.465-.126 3.057 3.057 0 00-1.591.126 2.557 2.557 0 00-.862.508c-.245.22-.44.489-.582.803a2.547 2.547 0 00-.213 1.06c0 .433.096.813.287 1.142.192.33.405.592.641.789v.059a2.234 2.234 0 00-.53.53c-.167.226-.25.491-.25.796 0 .285.06.523.183.714a1.4 1.4 0 00.45.45v.059a2.93 2.93 0 00-.766.75c-.187.276-.28.566-.28.87 0 .315.07.59.213.825.143.236.344.437.604.604.26.167.572.293.936.376a5.37 5.37 0 001.208.125zm0-6.38a1.462 1.462 0 01-1.068-.456 1.528 1.528 0 01-.332-.538 2.052 2.052 0 01-.118-.714c0-.53.148-.94.442-1.23.295-.29.654-.435 1.076-.435.422 0 .78.145 1.076.434.294.29.442.7.442 1.23 0 .266-.04.504-.118.715a1.503 1.503 0 01-.818.877 1.462 1.462 0 01-.582.118zm.177 5.54c-.648 0-1.157-.112-1.525-.338-.368-.226-.553-.53-.553-.914 0-.206.06-.412.177-.619.118-.206.305-.402.56-.589.157.05.317.081.479.096.162.015.312.022.45.022h1.237c.471 0 .83.064 1.075.191.246.128.369.359.369.693 0 .186-.054.368-.162.545-.108.177-.26.332-.457.464-.197.133-.435.24-.715.324-.28.084-.591.125-.935.125zm7.077-2.283c.225 0 .454-.027.685-.081.23-.054.444-.116.64-.184l-.235-.914c-.118.05-.25.093-.398.133a1.619 1.619 0 01-.413.059c-.412 0-.7-.12-.861-.361-.162-.241-.244-.582-.244-1.024v-3.978h1.93v-.987h-1.93v-2.004h-1.016L25.2 17.84l-1.12.073v.914h1.06v3.963c0 .354.035.678.104.972.068.295.184.546.346.752.162.206.373.368.634.486.26.118.581.177.965.177z"/><path fill="#2A506F" fill-rule="nonzero" d="M19.647 73.55c.245 0 .45.178.492.41l.008.09v14.883a.5.5 0 01-.992.09l-.008-.09V74.05a.5.5 0 01.5-.5z"/><path fill="#2A506F" fill-rule="nonzero" d="M14.682 83.856a.5.5 0 01.639-.05l.068.058 4.615 4.719a.5.5 0 01-.646.757l-.068-.058-4.615-4.719a.5.5 0 01.007-.707z"/><path fill="#2A506F" fill-rule="nonzero" d="M24.016 83.96a.5.5 0 01.758.646l-.058.07-4.72 4.614a.5.5 0 01-.757-.646l.058-.069 4.72-4.615z"/></g></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -17,8 +17,8 @@
import { Drive as DrivelistDrive } from 'drivelist';
import * as sdk from 'etcher-sdk';
import { cleanupTmpFiles } from 'etcher-sdk/build/tmp';
import * as _ from 'lodash';
import * as ipc from 'node-ipc';
import { totalmem } from 'os';
import { toJSON } from '../../shared/errors';
import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes';
@ -118,7 +118,11 @@ async function writeAndValidate({
onProgress,
verify,
trim: autoBlockmapping,
numBuffers: Math.min(2 + (destinations.length - 1) * 32, 256),
numBuffers: Math.min(
2 + (destinations.length - 1) * 32,
256,
Math.floor(totalmem() / 1024 ** 2 / 8),
),
decompressFirst,
});
const result: WriteResult = {
@ -223,14 +227,14 @@ ipc.connectTo(IPC_SERVER_ID, () => {
});
};
const destinations = _.map(options.destinations, 'device');
const destinations = options.destinations.map((d) => d.device);
log(`Image: ${options.imagePath}`);
log(`Devices: ${destinations.join(', ')}`);
log(`Umount on success: ${options.unmountOnSuccess}`);
log(`Validate on success: ${options.validateWriteOnSuccess}`);
log(`Auto blockmapping: ${options.autoBlockmapping}`);
log(`Decompress first: ${options.decompressFirst}`);
const dests = _.map(options.destinations, (destination) => {
const dests = options.destinations.map((destination) => {
return new sdk.sourceDestination.BlockDevice({
drive: destination,
unmountOnSuccess: options.unmountOnSuccess,
@ -261,7 +265,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
onFail,
});
log(`Finish: ${results.bytesWritten}`);
results.errors = _.map(results.errors, (error) => {
results.errors = results.errors.map((error) => {
return toJSON(error);
});
ipc.of[IPC_SERVER_ID].emit('done', { results });

View File

@ -14,48 +14,37 @@
* limitations under the License.
*/
import * as _ from 'lodash';
function createErrorDetails(options: {
title: string | ((error: Error & { path: string }) => string);
description: string;
}): {
title: (error: Error & { path: string }) => string;
description: (error: Error & { path: string }) => string;
} {
return _.pick(
_.mapValues(options, (value) => {
return _.isFunction(value) ? value : _.constant(value);
}),
['title', 'description'],
);
}
export type ErrorWithPath = Error & {
path?: string;
code?: keyof typeof HUMAN_FRIENDLY;
};
/**
* @summary Human-friendly error messages
*/
export const HUMAN_FRIENDLY = {
ENOENT: createErrorDetails({
title: (error: Error & { path: string }) => {
ENOENT: {
title: (error: ErrorWithPath) => {
return `No such file or directory: ${error.path}`;
},
description: "The file you're trying to access doesn't exist",
}),
EPERM: createErrorDetails({
title: "You're not authorized to perform this operation",
description: 'Please ensure you have necessary permissions for this task',
}),
EACCES: createErrorDetails({
title: "You don't have access to this resource",
description:
description: () => "The file you're trying to access doesn't exist",
},
EPERM: {
title: () => "You're not authorized to perform this operation",
description: () =>
'Please ensure you have necessary permissions for this task',
},
EACCES: {
title: () => "You don't have access to this resource",
description: () =>
'Please ensure you have necessary permissions to access this resource',
}),
ENOMEM: createErrorDetails({
title: 'Your system ran out of memory',
description:
},
ENOMEM: {
title: () => 'Your system ran out of memory',
description: () =>
'Please make sure your system has enough available memory for this task',
}),
};
},
} as const;
/**
* @summary Get user friendly property from an error
@ -71,19 +60,21 @@ export const HUMAN_FRIENDLY = {
* }
*/
function getUserFriendlyMessageProperty(
error: Error,
error: ErrorWithPath,
property: 'title' | 'description',
): string | null {
const code = _.get(error, ['code']);
if (_.isNil(code) || !_.isString(code)) {
return null;
): string | undefined {
if (typeof error.code !== 'string') {
return undefined;
}
return _.invoke(HUMAN_FRIENDLY, [code, property], error);
return HUMAN_FRIENDLY[error.code]?.[property]?.(error);
}
const isBlank = _.flow([_.trim, _.isEmpty]);
function isBlank(s: string | number | null | undefined) {
if (typeof s === 'number') {
s = s.toString();
}
return (s ?? '').trim() === '';
}
/**
* @summary Get the title of an error
@ -92,23 +83,19 @@ const isBlank = _.flow([_.trim, _.isEmpty]);
* Try to get as much information as possible about the error
* rather than falling back to generic messages right away.
*/
export function getTitle(error: Error): string {
if (!_.isError(error) && !_.isPlainObject(error) && !_.isNil(error)) {
return _.toString(error);
}
export function getTitle(error: ErrorWithPath): string {
const codeTitle = getUserFriendlyMessageProperty(error, 'title');
if (!_.isNil(codeTitle)) {
if (codeTitle !== undefined) {
return codeTitle;
}
const message = _.get(error, ['message']);
const message = error.message;
if (!isBlank(message)) {
return message;
}
const code = _.get(error, ['code']);
if (!_.isNil(code) && !isBlank(code)) {
const code = error.code;
if (!isBlank(code)) {
return `Error code: ${code}`;
}
@ -119,40 +106,19 @@ export function getTitle(error: Error): string {
* @summary Get the description of an error
*/
export function getDescription(
error: Error & { description?: string },
options: { userFriendlyDescriptionsOnly?: boolean } = {},
error: ErrorWithPath & { description?: string },
): string {
_.defaults(options, {
userFriendlyDescriptionsOnly: false,
});
if (!_.isError(error) && !_.isPlainObject(error)) {
return '';
}
if (!isBlank(error.description)) {
return error.description as string;
}
const codeDescription = getUserFriendlyMessageProperty(error, 'description');
if (!_.isNil(codeDescription)) {
if (codeDescription !== undefined) {
return codeDescription;
}
if (options.userFriendlyDescriptionsOnly) {
return '';
}
if (error.stack) {
return error.stack;
}
if (_.isEmpty(error)) {
return '';
}
const INDENTATION_SPACES = 2;
return JSON.stringify(error, null, INDENTATION_SPACES);
return JSON.stringify(error, null, 2);
}
/**
@ -162,24 +128,24 @@ export function createError(options: {
title: string;
description?: string;
report?: boolean;
code?: string;
}): Error & { description?: string; report?: boolean; code?: string } {
code?: keyof typeof HUMAN_FRIENDLY;
}): ErrorWithPath & { description?: string; report?: boolean } {
if (isBlank(options.title)) {
throw new Error(`Invalid error title: ${options.title}`);
}
const error: Error & {
const error: ErrorWithPath & {
description?: string;
report?: boolean;
code?: string;
} = new Error(options.title);
error.description = options.description;
if (!_.isNil(options.report) && !options.report) {
if (options.report === false) {
error.report = false;
}
if (!_.isNil(options.code)) {
if (options.code !== undefined) {
error.code = options.code;
}
@ -198,7 +164,7 @@ export function createError(options: {
export function createUserError(options: {
title: string;
description: string;
code?: string;
code?: keyof typeof HUMAN_FRIENDLY;
}): Error {
return createError({
title: options.title,
@ -208,13 +174,6 @@ export function createUserError(options: {
});
}
/**
* @summary Check if an error is an user error
*/
export function isUserError(error: Error & { report?: boolean }): boolean {
return _.isNil(error.report) ? false : !error.report;
}
/**
* @summary Convert an Error object to a JSON object
* @function
@ -260,5 +219,5 @@ export function toJSON(
* @summary Convert a JSON object to an Error object
*/
export function fromJSON(json: any): Error {
return _.assign(new Error(json.message), json);
return Object.assign(new Error(json.message), json);
}

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
import * as Bluebird from 'bluebird';
import * as childProcess from 'child_process';
import { promises as fs } from 'fs';
import * as _ from 'lodash';
@ -25,14 +24,29 @@ import { promisify } from 'util';
import { sudo as catalinaSudo } from './catalina-sudo/sudo';
import * as errors from './errors';
import { tmpFileDisposer } from './tmp';
import { withTmpFile } from './tmp';
const execAsync = promisify(childProcess.exec);
const execFileAsync = promisify(childProcess.execFile);
// sudo-prompt's exec callback is function(error, stdout, stderr) so we need multiArgs
const sudoExecAsync = Bluebird.promisify(sudoPrompt.exec, {
multiArgs: true,
}) as (cmd: string, options: any) => Bluebird<[string, string]>;
function sudoExecAsync(
cmd: string,
options: { name: string },
): Promise<{ stdout: string; stderr: string }> {
return new Promise((resolve, reject) => {
sudoPrompt.exec(
cmd,
options,
(error: Error | null, stdout: string, stderr: string) => {
if (error != null) {
reject(error);
} else {
resolve({ stdout, stderr });
}
},
);
});
}
/**
* @summary The user id of the UNIX "superuser"
@ -108,17 +122,12 @@ export function createLaunchScript(
async function elevateScriptWindows(
path: string,
): Promise<{ cancelled: boolean }> {
// 'elevator' imported here as it only exists on windows
// TODO: replace this with sudo-prompt once https://github.com/jorangreef/sudo-prompt/issues/96 is fixed
// @ts-ignore this is a native module
const { elevate } = await import('../../build/Release/elevator.node');
const elevateAsync = promisify(elevate);
name: string,
): Promise<{ cancelled: false }> {
// '&' needs to be escaped here (but not when written to a .cmd file)
const cmd = ['cmd', '/c', escapeParamCmd(path).replace(/&/g, '^&')];
const { cancelled } = await elevateAsync(cmd);
return { cancelled };
const cmd = ['cmd', '/c', escapeParamCmd(path).replace(/&/g, '^&')].join(' ');
await sudoExecAsync(cmd, { name });
return { cancelled: false };
}
async function elevateScriptUnix(
@ -161,15 +170,15 @@ export async function elevateCommand(
command.slice(1),
options.environment,
);
return Bluebird.using(
tmpFileDisposer({
return await withTmpFile(
{
prefix: 'balena-etcher-electron-',
postfix: '.cmd',
}),
async ({ path }) => {
},
async (path) => {
await fs.writeFile(path, launchScript);
if (isWindows) {
return elevateScriptWindows(path);
return elevateScriptWindows(path, options.applicationName);
}
if (
os.platform() === 'darwin' &&

View File

@ -1,4 +1,3 @@
import * as Bluebird from 'bluebird';
import * as tmp from 'tmp';
function tmpFileAsync(
@ -15,10 +14,14 @@ function tmpFileAsync(
});
}
export function tmpFileDisposer(
export async function withTmpFile<T>(
options: tmp.FileOptions,
): Bluebird.Disposer<{ path: string; cleanup: () => void }> {
return Bluebird.resolve(tmpFileAsync(options)).disposer(({ cleanup }) => {
fn: (path: string) => Promise<T>,
): Promise<T> {
const { path, cleanup } = await tmpFileAsync(options);
try {
return await fn(path);
} finally {
cleanup();
});
}
}

9003
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,21 +8,25 @@
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
"productDescription": "Etcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more.",
"homepage": "https://github.com/balena-io/etcher",
"gypfile": true,
"repository": {
"type": "git",
"url": "git@github.com:balena-io/etcher.git"
},
"scripts": {
"test": "make lint test sanity-checks",
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
"lint-css": "prettier --write lib/**/*.css",
"lint-spell": "codespell --dictionary - --dictionary dictionary.txt --skip *.ttf *.svg *.gz,*.bz2,*.xz,*.zip,*.img,*.dmg,*.iso,*.rpi-sdcard,*.wic,.DS_Store,*.dtb,*.dtbo,*.dat,*.elf,*.bin,*.foo,xz-without-extension lib tests docs Makefile *.md LICENSE",
"lint": "npm run lint-ts && npm run lint-css && npm run lint-spell",
"test-spectron": "mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts",
"test-gui": "electron-mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox --renderer tests/gui/**/*.ts",
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
"test": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
"start": "./node_modules/.bin/electron .",
"postshrinkwrap": "ts-node ./scripts/clean-shrinkwrap.ts",
"configure": "node-gyp configure",
"build": "node-gyp build",
"install": "node-gyp rebuild",
"webpack": "webpack",
"watch": "webpack --watch",
"concourse-build-electron": "make webpack",
"concourse-build-electron": "npm run webpack",
"concourse-test": "npx npm@6.14.5 test",
"concourse-test-electron": "npx npm@6.14.5 test"
},
@ -33,10 +37,10 @@
},
"lint-staged": {
"./**/*.{ts,tsx}": [
"make lint-ts"
"npm run lint-ts"
],
"./**/*.css": [
"make lint-css"
"npm run lint-css"
]
},
"author": "Balena Inc. <hello@etcher.io>",
@ -54,39 +58,37 @@
"@types/copy-webpack-plugin": "^6.0.0",
"@types/mime-types": "^2.1.0",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/mocha": "^7.0.2",
"@types/mocha": "^8.0.3",
"@types/node": "^12.12.39",
"@types/node-ipc": "^9.1.2",
"@types/react-dom": "^16.8.4",
"@types/request": "^2.48.4",
"@types/semver": "^7.1.0",
"@types/sinon": "^9.0.0",
"@types/terser-webpack-plugin": "^3.0.0",
"@types/terser-webpack-plugin": "^4.1.0",
"@types/tmp": "^0.2.0",
"@types/webpack-node-externals": "^1.7.0",
"bluebird": "^3.7.2",
"@types/webpack-node-externals": "^2.5.0",
"chai": "^4.2.0",
"copy-webpack-plugin": "^6.0.1",
"css-loader": "^3.5.3",
"css-loader": "^4.2.1",
"d3": "^4.13.0",
"debug": "^4.2.0",
"electron": "9.1.1",
"electron": "9.2.0",
"electron-builder": "^22.7.0",
"electron-mocha": "^8.2.0",
"electron-mocha": "^9.1.0",
"electron-notarize": "^1.0.0",
"electron-rebuild": "^1.11.0",
"electron-updater": "^4.3.2",
"etcher-sdk": "^4.1.19",
"etcher-sdk": "^4.1.23",
"file-loader": "^6.0.0",
"husky": "^4.2.5",
"immutable": "^3.8.1",
"lint-staged": "^10.2.2",
"lodash": "^4.17.10",
"mini-css-extract-plugin": "^0.9.0",
"mini-css-extract-plugin": "^0.10.0",
"mocha": "^8.0.1",
"nan": "^2.14.0",
"native-addon-loader": "^2.0.1",
"node-gyp": "^7.0.0",
"node-ipc": "^9.1.1",
"omit-deep-lodash": "1.1.4",
"outdent": "^0.7.1",
@ -95,7 +97,7 @@
"react": "^16.8.5",
"react-dom": "^16.8.5",
"redux": "^4.0.5",
"rendition": "^16.1.1",
"rendition": "^17.0.0",
"resin-corvus": "^2.0.5",
"semver": "^7.3.2",
"simple-progress-webpack-plugin": "^1.1.2",

View File

@ -1,4 +1,3 @@
codespell==1.12.0
cpplint==1.3.0
awscli==1.11.87
shyaml==0.5.0

View File

@ -1,83 +0,0 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <vector>
#include "os/elevate.h"
#include "utils/v8utils.h"
class ElevateWorker : public Nan::AsyncWorker {
public:
ElevateWorker(Nan::Callback *callback,
const std::vector<std::wstring> &arguments)
: Nan::AsyncWorker(callback) {
this->arguments = arguments;
}
~ElevateWorker() {}
void Execute() {
etcher::ELEVATE_RESULT result = etcher::Elevate(
this->arguments.front(),
std::vector<std::wstring>(this->arguments.begin() + 1,
this->arguments.end()));
switch (result) {
case etcher::ELEVATE_RESULT::ELEVATE_SUCCESS:
cancelled = false;
break;
case etcher::ELEVATE_RESULT::ELEVATE_CANCELLED:
cancelled = true;
break;
default:
this->SetErrorMessage(etcher::ElevateResultToString(result).c_str());
}
}
void HandleOKCallback() {
v8::Local<v8::Object> results = Nan::New<v8::Object>();
Nan::Set(results, Nan::New<v8::String>("cancelled").ToLocalChecked(),
this->cancelled ? Nan::True() : Nan::False());
v8::Local<v8::Value> argv[2] = { Nan::Null(), results };
callback->Call(2, argv);
}
private:
std::vector<std::wstring> arguments;
v8::Local<v8::Object> results;
bool cancelled;
};
NAN_METHOD(elevate) {
if (!info[0]->IsArray()) {
return Nan::ThrowError("This function expects an array");
}
if (!info[1]->IsFunction()) {
return Nan::ThrowError("Callback must be a function");
}
std::vector<std::wstring> arguments =
etcher::v8utils::GetArguments(info[0].As<v8::Array>());
Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());
Nan::AsyncQueueWorker(new ElevateWorker(callback, arguments));
info.GetReturnValue().SetUndefined();
}
NAN_MODULE_INIT(ElevatorInit) { NAN_EXPORT(target, elevate); }
NODE_MODULE(elevator, ElevatorInit)

View File

@ -1,63 +0,0 @@
#ifndef SRC_OS_ELEVATE_H_
#define SRC_OS_ELEVATE_H_
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef _WIN32
// Fix winsock.h redefinition errors
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// Note that windows.h has to be included before any
// other Windows library to avoid declaration issues
#include <windows.h>
#include <shellapi.h>
#endif
#include <algorithm>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
namespace etcher {
enum class ELEVATE_RESULT {
ELEVATE_SUCCESS,
ELEVATE_FILE_NOT_FOUND,
ELEVATE_PATH_NOT_FOUND,
ELEVATE_DDE_FAIL,
ELEVATE_NO_ASSOCIATION,
ELEVATE_ACCESS_DENIED,
ELEVATE_DLL_NOT_FOUND,
ELEVATE_CANCELLED,
ELEVATE_NOT_ENOUGH_MEMORY,
ELEVATE_SHARING_VIOLATION,
ELEVATE_UNKNOWN_ERROR
};
ELEVATE_RESULT Elevate(const std::wstring &command,
std::vector<std::wstring> arguments);
std::string ElevateResultToString(const ELEVATE_RESULT &result);
} // namespace etcher
#endif // SRC_OS_ELEVATE_H_

View File

@ -1,158 +0,0 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "os/elevate.h"
static std::wstring JoinArguments(std::vector<std::wstring> arguments) {
std::wostringstream result;
std::copy(arguments.begin(), arguments.end(),
std::ostream_iterator<std::wstring, wchar_t>(result, L" "));
return result.str();
}
// Make sure to delete the result after you're done
// with it by calling `delete[] result;`.
// See http://stackoverflow.com/a/1201471
static LPCWSTR ConvertStringToLPCWSTR(const std::wstring &string) {
wchar_t *result = new wchar_t[string.size() + 1];
std::copy(string.begin(), string.end(), result);
result[string.size()] = 0;
return result;
}
etcher::ELEVATE_RESULT etcher::Elevate(const std::wstring &command,
std::vector<std::wstring> arguments) {
// Initialize the SHELLEXECUTEINFO structure. We zero it out
// in order to be on the safe side, and set cbSize to the size
// of the structure as recommend by MSDN
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/bb759784(v=vs.85).aspx
SHELLEXECUTEINFOW shellExecuteInfo;
ZeroMemory(&shellExecuteInfo, sizeof(shellExecuteInfo));
shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
// Flags that indicate the content and validity of the other structure member.
shellExecuteInfo.fMask =
// Used to indicate that the hProcess member receives the process handle.
// This handle is typically used to allow an application to find out
// when a process created with ShellExecuteEx terminates.
SEE_MASK_NOCLOSEPROCESS |
// Wait for the execute operation to complete before returning.
SEE_MASK_NOASYNC |
// Do not display an error message box if an error occurs.
SEE_MASK_FLAG_NO_UI;
// The action to be performed.
shellExecuteInfo.lpVerb = L"runas";
// Run the file in the background
shellExecuteInfo.nShow = SW_HIDE;
// Use the current directory as the working directory
shellExecuteInfo.lpDirectory = NULL;
// Set file and parameters
// We can't just assign the result of `.c_str()`, since
// that pointer is owned by the `std::wstring` instance,
// and will not be safe after the instance is destroyed.
LPCWSTR file = ConvertStringToLPCWSTR(command);
LPCWSTR argv = ConvertStringToLPCWSTR(JoinArguments(arguments));
shellExecuteInfo.lpFile = file;
shellExecuteInfo.lpParameters = argv;
BOOL executeResult = ShellExecuteExW(&shellExecuteInfo);
delete[] file;
delete[] argv;
// Finally, let's try to elevate the command
if (!executeResult) {
DWORD executeError = GetLastError();
// We map Windows error codes to our own enum class
// so we can normalize all Windows error handling mechanisms.
switch (executeError) {
case ERROR_FILE_NOT_FOUND:
return etcher::ELEVATE_RESULT::ELEVATE_FILE_NOT_FOUND;
case ERROR_PATH_NOT_FOUND:
return etcher::ELEVATE_RESULT::ELEVATE_PATH_NOT_FOUND;
case ERROR_DDE_FAIL:
return etcher::ELEVATE_RESULT::ELEVATE_DDE_FAIL;
case ERROR_NO_ASSOCIATION:
return etcher::ELEVATE_RESULT::ELEVATE_NO_ASSOCIATION;
case ERROR_ACCESS_DENIED:
return etcher::ELEVATE_RESULT::ELEVATE_ACCESS_DENIED;
case ERROR_DLL_NOT_FOUND:
return etcher::ELEVATE_RESULT::ELEVATE_DLL_NOT_FOUND;
case ERROR_CANCELLED:
return etcher::ELEVATE_RESULT::ELEVATE_CANCELLED;
case ERROR_NOT_ENOUGH_MEMORY:
return etcher::ELEVATE_RESULT::ELEVATE_NOT_ENOUGH_MEMORY;
case ERROR_SHARING_VIOLATION:
return etcher::ELEVATE_RESULT::ELEVATE_SHARING_VIOLATION;
default:
return etcher::ELEVATE_RESULT::ELEVATE_UNKNOWN_ERROR;
}
}
// Since we passed SEE_MASK_NOCLOSEPROCESS, the
// process handle is accessible from hProcess.
if (shellExecuteInfo.hProcess) {
// Wait for the process to exit before continuing.
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
WaitForSingleObject(shellExecuteInfo.hProcess, INFINITE);
if (!CloseHandle(shellExecuteInfo.hProcess)) {
return etcher::ELEVATE_RESULT::ELEVATE_UNKNOWN_ERROR;
}
}
return etcher::ELEVATE_RESULT::ELEVATE_SUCCESS;
}
std::string
etcher::ElevateResultToString(const etcher::ELEVATE_RESULT &result) {
switch (result) {
case etcher::ELEVATE_RESULT::ELEVATE_SUCCESS:
return "Success";
case etcher::ELEVATE_RESULT::ELEVATE_CANCELLED:
return "The user cancelled the elevation request";
case etcher::ELEVATE_RESULT::ELEVATE_FILE_NOT_FOUND:
return "The specified file was not found";
case etcher::ELEVATE_RESULT::ELEVATE_PATH_NOT_FOUND:
return "The specified path was not found";
case etcher::ELEVATE_RESULT::ELEVATE_DDE_FAIL:
return "The Dynamic Data Exchange (DDE) transaction failed";
case etcher::ELEVATE_RESULT::ELEVATE_NO_ASSOCIATION:
return "There is no application associated with the "
"specified file name extension";
case etcher::ELEVATE_RESULT::ELEVATE_ACCESS_DENIED:
return "Access to the specified file is denied";
case etcher::ELEVATE_RESULT::ELEVATE_DLL_NOT_FOUND:
return "One of the library files necessary to run the "
"application can't be found";
case etcher::ELEVATE_RESULT::ELEVATE_NOT_ENOUGH_MEMORY:
return "There is not enough memory to perform the specified action";
case etcher::ELEVATE_RESULT::ELEVATE_SHARING_VIOLATION:
return "A sharing violation occurred";
default:
return "Unknown error";
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils/v8utils.h"
std::vector<std::wstring>
etcher::v8utils::GetArguments(v8::Local<v8::Array> arguments) {
std::vector<std::wstring> result(0);
for (uint32_t index = 0; index < arguments->Length(); index++) {
// See https://stackoverflow.com/q/15615136/1641422
std::string stringArgument(
*Nan::Utf8String(
arguments->Get(
Nan::GetCurrentContext(),
index).ToLocalChecked()));
std::wstring_convert<std::codecvt_utf8<wchar_t>> conversion;
result.push_back(conversion.from_bytes(stringArgument));
}
return result;
}

View File

@ -1,59 +0,0 @@
#ifndef SRC_UTILS_V8UTILS_H_
#define SRC_UTILS_V8UTILS_H_
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nan.h>
#include <string>
#include <vector>
#include <codecvt>
namespace etcher {
namespace v8utils {
std::vector<std::wstring> GetArguments(v8::Local<v8::Array> arguments);
} // namespace v8utils
} // namespace etcher
#define YIELD_ERROR(CALLBACK, ERROR) \
{ \
const wchar_t *message = (ERROR).c_str(); \
v8::Local<v8::Value> argv[1] = { \
Nan::Error(v8::String::NewFromTwoByte(isolate, \
(const uint16_t *)message)) \
}; \
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (CALLBACK), \
1, argv); \
} \
return;
#define YIELD_OBJECT(CALLBACK, OBJECT) \
{ \
v8::Local<v8::Value> argv[2] = {Nan::Null(), (OBJECT)}; \
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (CALLBACK), 2, \
argv); \
} \
return;
#define YIELD_NOTHING(CALLBACK) \
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (CALLBACK), 0, 0);
#define NAN_SET_FUNCTION(JSSYMBOL, FUNCTION) \
Nan::Set(target, Nan::New((JSSYMBOL)).ToLocalChecked(), \
Nan::GetFunction(Nan::New<v8::FunctionTemplate>((FUNCTION))) \
.ToLocalChecked());
#endif // SRC_UTILS_V8UTILS_H_

View File

@ -1,3 +1,5 @@
// tslint:disable-next-line:no-var-requires
const { app } = require('electron');
app.allowRendererProcessReuse = false;
if (app !== undefined) {
app.allowRendererProcessReuse = false;
}

View File

@ -17,7 +17,6 @@
import { expect } from 'chai';
import { Drive as DrivelistDrive } from 'drivelist';
import { sourceDestination } from 'etcher-sdk';
import * as _ from 'lodash';
import * as ipc from 'node-ipc';
import { assert, SinonStub, stub } from 'sinon';
@ -39,7 +38,7 @@ describe('Browser: imageWriter', () => {
let performWriteStub: SinonStub;
beforeEach(() => {
performWriteStub = stub(imageWriter, 'performWrite');
performWriteStub = stub();
performWriteStub.returns(
Promise.resolve({
cancelled: false,
@ -49,52 +48,56 @@ describe('Browser: imageWriter', () => {
});
afterEach(() => {
performWriteStub.restore();
performWriteStub.reset();
});
it('should set flashing to false when done', () => {
it('should set flashing to false when done', async () => {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234',
});
imageWriter.flash(imagePath, [fakeDrive], sourceOptions).finally(() => {
try {
await imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
);
} catch {
// noop
} finally {
expect(flashState.isFlashing()).to.be.false;
});
}
});
it('should prevent writing more than once', () => {
it('should prevent writing more than once', async () => {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234',
});
const writing = imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
);
imageWriter.flash(imagePath, [fakeDrive], sourceOptions).catch(_.noop);
writing.finally(() => {
assert.calledOnce(performWriteStub);
});
});
it('should reject the second flash attempt', () => {
imageWriter.flash(imagePath, [fakeDrive], sourceOptions);
let rejectError: Error;
imageWriter
.flash(imagePath, [fakeDrive], sourceOptions)
.catch((error) => {
rejectError = error;
})
.finally(() => {
expect(rejectError).to.be.an.instanceof(Error);
expect(rejectError!.message).to.equal(
'There is already a flash in progress',
);
});
try {
await Promise.all([
imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
),
imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
),
]);
assert.fail('Writing twice should fail');
} catch (error) {
expect(error.message).to.equal(
'There is already a flash in progress',
);
}
});
});
@ -102,51 +105,63 @@ describe('Browser: imageWriter', () => {
let performWriteStub: SinonStub;
beforeEach(() => {
performWriteStub = stub(imageWriter, 'performWrite');
performWriteStub = stub();
const error: Error & { code?: string } = new Error('write error');
error.code = 'FOO';
performWriteStub.returns(Promise.reject(error));
});
afterEach(() => {
performWriteStub.restore();
performWriteStub.reset();
});
it('should set flashing to false when done', () => {
imageWriter
.flash(imagePath, [fakeDrive], sourceOptions)
.catch(_.noop)
.finally(() => {
expect(flashState.isFlashing()).to.be.false;
});
it('should set flashing to false when done', async () => {
try {
await imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
);
} catch {
// noop
} finally {
expect(flashState.isFlashing()).to.be.false;
}
});
it('should set the error code in the flash results', () => {
imageWriter
.flash(imagePath, [fakeDrive], sourceOptions)
.catch(_.noop)
.finally(() => {
const flashResults = flashState.getFlashResults();
expect(flashResults.errorCode).to.equal('FOO');
});
it('should set the error code in the flash results', async () => {
try {
await imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
);
} catch {
// noop
} finally {
const flashResults = flashState.getFlashResults();
expect(flashResults.errorCode).to.equal('FOO');
}
});
it('should be rejected with the error', () => {
it('should be rejected with the error', async () => {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234',
});
let rejection: Error;
imageWriter
.flash(imagePath, [fakeDrive], sourceOptions)
.catch((error) => {
rejection = error;
})
.finally(() => {
expect(rejection).to.be.an.instanceof(Error);
expect(rejection!.message).to.equal('write error');
});
try {
await imageWriter.flash(
imagePath,
[fakeDrive],
sourceOptions,
performWriteStub,
);
} catch (error) {
expect(error).to.be.an.instanceof(Error);
expect(error.message).to.equal('write error');
}
});
});
});

View File

@ -17,37 +17,34 @@
import { expect } from 'chai';
import { promises as fs } from 'fs';
import * as os from 'os';
import { env } from 'process';
import { SinonStub, stub } from 'sinon';
import * as wnd from '../../../lib/gui/app/os/windows-network-drives';
function mockGetWmicOutput() {
return fs.readFile('tests/data/wmic-output.txt', {
encoding: 'ucs2',
});
}
describe('Network drives on Windows', () => {
let osPlatformStub: SinonStub;
let outputStub: SinonStub;
let oldSystemRoot: string | undefined;
before(async () => {
osPlatformStub = stub(os, 'platform');
osPlatformStub.returns('win32');
const wmicOutput = await fs.readFile('tests/data/wmic-output.txt', {
encoding: 'ucs2',
});
outputStub = stub(wnd, 'getWmicNetworkDrivesOutput');
outputStub.resolves(wmicOutput);
oldSystemRoot = env.SystemRoot;
env.SystemRoot = 'C:\\Windows';
});
it('should parse network drive mapping on Windows', async () => {
expect(
await wnd.replaceWindowsNetworkDriveLetter('Z:\\some-folder\\some-file'),
await wnd.replaceWindowsNetworkDriveLetter(
'Z:\\some-folder\\some-file',
mockGetWmicOutput,
),
).to.equal('\\\\192.168.1.1\\Publicé\\some-folder\\some-file');
});
after(() => {
osPlatformStub.restore();
outputStub.restore();
env.SystemRoot = oldSystemRoot;
});
});

View File

@ -37,54 +37,12 @@ describe('Shared: Errors', function () {
});
describe('.getTitle()', function () {
it('should accept a string', function () {
const error = 'This is an error';
// @ts-ignore
expect(errors.getTitle(error)).to.equal('This is an error');
});
it('should accept a number 0', function () {
const error = 0;
// @ts-ignore
expect(errors.getTitle(error)).to.equal('0');
});
it('should accept a number 1', function () {
const error = 1;
// @ts-ignore
expect(errors.getTitle(error)).to.equal('1');
});
it('should accept a number -1', function () {
const error = -1;
// @ts-ignore
expect(errors.getTitle(error)).to.equal('-1');
});
it('should accept an array', function () {
const error = [0, 1, 2];
// @ts-ignore
expect(errors.getTitle(error)).to.equal('0,1,2');
});
it('should return a generic error message if the error is an empty object', function () {
const error = {};
// @ts-ignore
expect(errors.getTitle(error)).to.equal('An error ocurred');
});
it('should return a generic error message if the error is undefined', function () {
const error = undefined;
// @ts-ignore
expect(errors.getTitle(error)).to.equal('An error ocurred');
});
it('should return a generic error message if the error is null', function () {
const error = null;
// @ts-ignore
expect(errors.getTitle(error)).to.equal('An error ocurred');
});
it('should return the error message', function () {
const error = new Error('This is an error');
expect(errors.getTitle(error)).to.equal('This is an error');
@ -234,42 +192,6 @@ describe('Shared: Errors', function () {
});
describe('.getDescription()', function () {
it('should return an empty string if the error is a string', function () {
const error = 'My error';
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should return an empty string if the error is a number', function () {
const error = 0;
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should return an empty string if the error is an array', function () {
const error = [1, 2, 3];
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should return an empty string if the error is undefined', function () {
const error = undefined;
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should return an empty string if the error is null', function () {
const error = null;
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should return an empty string if the error is an empty object', function () {
const error = {};
// @ts-ignore
expect(errors.getDescription(error)).to.equal('');
});
it('should understand an error-like object with a description', function () {
const error = {
description: 'My description',
@ -384,122 +306,26 @@ describe('Shared: Errors', function () {
describe('given userFriendlyDescriptionsOnly is false', function () {
it('should return the stack for a basic error', function () {
const error = new Error('Foo');
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: false,
}),
).to.equal(error.stack);
expect(errors.getDescription(error)).to.equal(error.stack);
});
it('should return the stack if the description is an empty string', function () {
const error = new Error('Foo');
// @ts-ignore
error.description = '';
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: false,
}),
).to.equal(error.stack);
expect(errors.getDescription(error)).to.equal(error.stack);
});
it('should return the stack if the description is a blank string', function () {
const error = new Error('Foo');
// @ts-ignore
error.description = ' ';
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: false,
}),
).to.equal(error.stack);
});
});
describe('given userFriendlyDescriptionsOnly is true', function () {
it('should return an empty string for a basic error', function () {
const error = new Error('Foo');
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: true,
}),
).to.equal('');
});
it('should return an empty string if the description is an empty string', function () {
const error = new Error('Foo');
// @ts-ignore
error.description = '';
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: true,
}),
).to.equal('');
});
it('should return an empty string if the description is a blank string', function () {
const error = new Error('Foo');
// @ts-ignore
error.description = ' ';
expect(
errors.getDescription(error, {
userFriendlyDescriptionsOnly: true,
}),
).to.equal('');
expect(errors.getDescription(error)).to.equal(error.stack);
});
});
});
describe('.createError()', function () {
it('should not be a user error', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
});
expect(errors.isUserError(error)).to.be.false;
});
it('should be a user error if `options.report` is false', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
report: false,
});
expect(errors.isUserError(error)).to.be.true;
});
it('should be a user error if `options.report` evaluates to false', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
// @ts-ignore
report: 0,
});
expect(errors.isUserError(error)).to.be.true;
});
it('should not be a user error if `options.report` is true', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
report: true,
});
expect(errors.isUserError(error)).to.be.false;
});
it('should not be a user error if `options.report` evaluates to true', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
// @ts-ignore
report: 1,
});
expect(errors.isUserError(error)).to.be.false;
});
it('should be an instance of Error', function () {
const error = errors.createError({
title: 'Foo',
@ -523,10 +349,10 @@ describe('Shared: Errors', function () {
const error = errors.createError({
title: 'Foo',
description: 'Something happened',
code: 'HELLO',
code: 'ENOENT',
});
expect(error.code).to.equal('HELLO');
expect(error.code).to.equal('ENOENT');
});
it('should correctly add only a title', function () {
@ -590,15 +416,6 @@ describe('Shared: Errors', function () {
});
describe('.createUserError()', function () {
it('should be a user error', function () {
const error = errors.createUserError({
title: 'Foo',
description: 'Something happened',
});
expect(errors.isUserError(error)).to.be.true;
});
it('should be an instance of Error', function () {
const error = errors.createUserError({
title: 'Foo',
@ -632,11 +449,11 @@ describe('Shared: Errors', function () {
// @ts-ignore
const error = errors.createUserError({
title: 'Foo',
code: 'HELLO',
code: 'ENOENT',
});
// @ts-ignore
expect(error.code).to.equal('HELLO');
expect(error.code).to.equal('ENOENT');
});
it('should ignore an empty description', function () {
@ -692,26 +509,6 @@ describe('Shared: Errors', function () {
});
});
describe('.isUserError()', function () {
_.each([0, '', false], (value) => {
it(`should return true if report equals ${value}`, function () {
const error = new Error('foo bar');
// @ts-ignore
error.report = value;
expect(errors.isUserError(error)).to.be.true;
});
});
_.each([undefined, null, true, 1, 3, 'foo'], (value) => {
it(`should return false if report equals ${value}`, function () {
const error = new Error('foo bar');
// @ts-ignore
error.report = value;
expect(errors.isUserError(error)).to.be.false;
});
});
});
describe('.toJSON()', function () {
it('should convert a simple error', function () {
const error = new Error('My error');

View File

@ -46,7 +46,7 @@ describe('Spectron', function () {
expect(bounds.height).to.be.above(0);
expect(bounds.width).to.be.above(0);
expect(await app.browserWindow.isMinimized()).to.be.false;
expect(await app.browserWindow.isFocused()).to.be.true;
expect(await app.browserWindow.isVisible()).to.be.true;
});
it('should set a proper title', async () => {

View File

@ -4,15 +4,7 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"module": "commonjs",
"target": "es2019",
"jsx": "react",
"typeRoots": ["./node_modules/@types", "./typings"],
"importHelpers": true,
"allowSyntheticDefaultImports": true
},
"include": [
"lib/**/*.ts",
"node_modules/electron/**/*.d.ts"
]
"typeRoots": ["./node_modules/@types", "./typings"]
}
}

19
tsconfig.webpack.json Normal file
View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"module": "es2015",
"target": "es2019",
"jsx": "react",
"typeRoots": ["./node_modules/@types", "./typings"],
"importHelpers": true,
"allowSyntheticDefaultImports": true
},
"include": [
"lib/**/*.ts",
"node_modules/electron/**/*.d.ts"
]
}

View File

@ -135,8 +135,20 @@ const commonConfig = {
},
{
test: /\.tsx?$/,
use: 'ts-loader',
use: [
{
loader: 'ts-loader',
options: {
configFile: 'tsconfig.webpack.json',
},
},
],
},
// don't import WeakMap polyfill in deep-map-keys (required in corvus)
replace(/node_modules\/deep-map-keys\/lib\/deep-map-keys\.js$/, {
search: "var WeakMap = require('es6-weak-map');",
replace: '',
}),
// force axios to use http backend (not xhr) to support streams
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
search: './adapters/xhr',
@ -154,16 +166,24 @@ const commonConfig = {
replace: 'bindings',
},
),
// remove node-pre-gyp magic from lzma-native
replace(/node_modules\/lzma-native\/index\.js$/, {
search: 'require(binding_path)',
replace: () => {
return `require('./${path.posix.join(
LZMA_BINDINGS_FOLDER,
'lzma_native.node',
)}')`;
replace(
/node_modules\/lzma-native\/index\.js$/,
// remove node-pre-gyp magic from lzma-native
{
search: 'require(binding_path)',
replace: () => {
return `require('./${path.posix.join(
LZMA_BINDINGS_FOLDER,
'lzma_native.node',
)}')`;
},
},
}),
// use regular stream module instead of readable-stream
{
search: "var stream = require('readable-stream');",
replace: "var stream = require('stream');",
},
),
// remove node-pre-gyp magic from usb
replace(/node_modules\/@balena.io\/usb\/usb\.js$/, {
search: 'require(binding_path)',