Stripping out material because meh. Also loading in cels at the right ordering

This commit is contained in:
Lani Aung
2024-02-11 16:14:51 -07:00
parent 70c85d0e18
commit bf5a47c650
25 changed files with 1167 additions and 12116 deletions
-5
View File
@@ -38,11 +38,6 @@ namespace fxl.codes.kisekae.Controllers
return View(); return View();
} }
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error() public IActionResult Error()
{ {
+22 -20
View File
@@ -2,29 +2,31 @@ using System.Linq;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using fxl.codes.kisekae.Entities; using fxl.codes.kisekae.Entities;
namespace fxl.codes.kisekae.Models namespace fxl.codes.kisekae.Models;
public class PlaysetModel
{ {
public class PlaysetModel [JsonIgnore] public readonly string BorderColor;
internal PlaysetModel(Configuration configuration)
{ {
[JsonIgnore] public readonly string BorderColor; BorderColor = configuration.BackgroundColorHex;
internal PlaysetModel(Configuration configuration) Name = configuration.Name;
{ Height = configuration.Height;
BorderColor = configuration.BackgroundColorHex; Width = configuration.Width;
var totalCels = configuration.Cels.Count;
Cels = configuration.Cels
.Select((x, index) => new CelModel(x, (totalCels - index) * 10))
.OrderBy(x => x.ZIndex)
.ToArray();
Name = configuration.Name; for (var index = 0; index < 10; index++) Sets[index] = configuration.Cels.Any(x => x.Positions.Any(y => y.Set == index));
Height = configuration.Height;
Width = configuration.Width;
var totalCels = configuration.Cels.Count;
Cels = configuration.Cels.Select((x, index) => new CelModel(x, (totalCels - index) * 10)).ToArray();
for (var index = 0; index < 10; index++) Sets[index] = configuration.Cels.Any(x => x.Positions.Any(y => y.Set == index));
}
public CelModel[] Cels { get; set; }
public int Height { get; set; }
public string Name { get; set; }
public bool[] Sets { get; set; } = new bool[10];
public int Width { get; set; }
} }
public CelModel[] Cels { get; set; }
public int Height { get; set; }
public string Name { get; set; }
public bool[] Sets { get; set; } = new bool[10];
public int Width { get; set; }
} }
-75
View File
@@ -1,75 +0,0 @@
import {MDCLinearProgress} from "@material/linear-progress"
import {MDCRipple} from "@material/ripple"
import {MDCTopAppBar} from "@material/top-app-bar"
import {Playset} from "./pto"
import Tracker from "./tracker"
import Builder from "./utility"
declare global {
interface Document {
kisekae: Main
}
}
class Main {
appBar: MDCTopAppBar
linearProgress: MDCLinearProgress
ripples: MDCRipple[] = []
constructor() {
this.appBar = MDCTopAppBar.attachTo(document.querySelector(".mdc-top-app-bar"))
document.querySelectorAll(".mdc-button").forEach(button => {
this.ripples.push(MDCRipple.attachTo(button))
})
this.linearProgress = MDCLinearProgress.attachTo(document.querySelector(".mdc-linear-progress"))
this.init()
}
public load(containerId: string, headerId: string, playset: Playset, set: number = 0): void {
let container = document.getElementById(containerId)
let menu = document.getElementById(headerId).querySelector("ul")
let tracker = new Tracker(playset, menu, container)
tracker.setPlayArea(set)
}
private init() {
let main = document.querySelector("main")
let directories = main.querySelector("ul")
if (!directories) return
let links = directories.querySelectorAll("a")
links.forEach(link => {
link.addEventListener("click", () => {
this.linearProgress.determinate = false
this.linearProgress.open()
let directory = link.attributes.getNamedItem("data-directory")
let form = new Builder("form")
.addAttributes({"method": "post", "action": "/Home/Select"})
.addChildren(
new Builder("input").addAttributes({
"type": "hidden",
"name": "directory",
"value": directory.value
}),
new Builder("input").addAttributes({
"type": "hidden",
"name": "file",
"value": link.textContent
})
).build() as HTMLFormElement
link.appendChild(form)
form.submit()
})
})
}
}
document.kisekae = new Main()
+21
View File
@@ -0,0 +1,21 @@
import {fabric} from "fabric";
export interface Playset {
readonly borderColor: string;
readonly name: string;
readonly height: number;
readonly width: number;
readonly cels: Cel[];
readonly sets: boolean[];
}
export interface Cel {
readonly mark: number;
readonly fix: number;
readonly initialPositions: { [key: number]: fabric.Point };
readonly offset: fabric.Point;
readonly image: string;
readonly zIndex: number;
readonly height: number;
readonly width: number;
}
+59
View File
@@ -0,0 +1,59 @@
import * as $ from "jquery";
import {fabric} from "fabric";
import {Playset} from "./models";
export class PlaySpace {
private model: Playset;
private canvas: fabric.Canvas;
constructor(model: Playset) {
const container = $(".container");
this.canvas = new fabric.Canvas("play_space");
this.canvas.setHeight(container.height()).setWidth(container.width());
this.model = model;
this.selectSet();
$(".set-link").on("click", event => {
const set = parseInt($(event.target).attr("data-set"));
this.selectSet(set);
});
this.canvas.setZoom(this.canvas.width / model.width);
}
async selectSet(set?: number) {
if (!set) {
set = this.model.sets.indexOf(true);
}
$(".set-link").removeClass("active");
$(`.set-link[data-set=${set}]`).addClass("active");
this.canvas.clear();
if (this.model.borderColor) this.canvas.backgroundColor = this.model.borderColor;
const cels = this.model.cels.filter(x => x.initialPositions[set]);
for (let cel of cels) {
const image = await new Promise<fabric.Image>(resolve => {
fabric.Image.fromURL(cel.image, image => resolve(image));
});
image.set({
left: cel.initialPositions[set].x + cel.offset.x,
top: cel.initialPositions[set].y + cel.offset.y,
selectable: cel.fix == 0
});
this.canvas.add(image);
}
}
}
declare global {
interface Window {
playSet: Playset;
}
}
$(() => {
new PlaySpace(window.playSet);
});
-28
View File
@@ -1,28 +0,0 @@
export interface Playset {
readonly name: string
readonly height: number
readonly width: number
readonly cels: Cel[]
readonly sets: boolean[]
}
export interface Cel {
readonly mark: number
readonly fix: number
readonly initialPositions: { [key: number]: Coordinate }
readonly offset: Coordinate
readonly image: string
readonly zIndex: number
readonly height: number
readonly width: number
}
export class Coordinate {
readonly x: number
readonly y: number
constructor(x: number = 0, y: number = 0) {
this.x = x
this.y = y
}
}
+2
View File
@@ -1,3 +1,4 @@
/*
import * as _ from "lodash" import * as _ from "lodash"
import {fabric} from "fabric" import {fabric} from "fabric"
import {Cel, Playset} from "./pto" import {Cel, Playset} from "./pto"
@@ -62,3 +63,4 @@ export default class Tracker {
} }
} }
} }
*/
-58
View File
@@ -1,58 +0,0 @@
import {MDCChipSet} from "@material/chips"
import Builder from "./utility"
class Uploader {
chips: MDCChipSet
constructor() {
this.init()
}
init() {
let upload = document.getElementById("lzh_upload") as HTMLInputElement
let container = document.querySelector(".mdc-evolution-chip-set__chips")
document.addEventListener("MDCChipSet:interaction", (event: Event) => {
console.log(event)
})
document.addEventListener("MDCChipSet:selection", (event: Event) => {
console.log(event)
})
upload.addEventListener("change", (event: InputEvent) => {
while (container.firstChild) container.removeChild(container.firstChild)
for (let index = 0; index < upload.files.length; index++) {
this.addChip(container, index, upload.files.item(index))
}
let element = document.querySelector(".mdc-evolution-chip-set")
this.chips = MDCChipSet.attachTo(element)
})
}
addChip(container: Element, index: number, file: File) {
const chipClass = "mdc-evolution-chip"
let textButton = Builder.element("button", {"type":"button","tabindex":0}, `${chipClass}__action`, `${chipClass}__action--primary`)
.addChildren(
Builder.element("span", {}, `${chipClass}__ripple`, `${chipClass}__ripple--primary`),
Builder.element("span", {}, `${chipClass}__text-label`).setText(file.name))
let textWrapper = Builder.element("span", {"role":"gridcell"}, `${chipClass}__cell`, `${chipClass}__cell--primary`)
.addChildren(textButton)
let trailingButton = Builder.element("button", {"type":"button","tabindex":-1,"data-mdc-deletable":"true","aria-label":`Remove ${file.name}`})
.addChildren(
Builder.element("span", {}, `${chipClass}__ripple`,`${chipClass}__ripple--trailing`),
Builder.element("span", {}, `${chipClass}__icon`,`${chipClass}__icon--trailing`).setText("close"))
let trailingWrapper = Builder.element("span", {"role":"gridcell"}, `${chipClass}__cell`, `${chipClass}__cell--trailing`)
.addChildren(trailingButton)
let chip = Builder.element("span", {"role":"row","id":`chip_${index}`}, chipClass).addChildren(textWrapper, trailingWrapper).build()
container.appendChild(chip)
}
}
new Uploader()
-53
View File
@@ -1,53 +0,0 @@
export default class Builder {
element: HTMLElement
constructor(tag: string) {
this.element = document.createElement(tag)
}
addAttributes(attributes: { [key: string]: string | number }): Builder {
for (let key of Object.keys(attributes)) {
this.addAttribute(key, attributes[key])
}
return this
}
addAttribute(name: string, value: string | number): Builder {
let attribute = document.createAttribute(name)
attribute.value = value.toString()
this.element.attributes.setNamedItem(attribute)
return this
}
addClass(...classes: string[]): Builder {
this.element.classList.add(...classes)
return this
}
addChildren(...children: HTMLElement[] | Builder[]): Builder {
children.forEach(child => {
if (child instanceof HTMLElement) {
this.element.appendChild(child)
} else {
this.element.appendChild(child.build())
}
})
return this
}
setText(text: string): Builder {
this.element.textContent = text
return this
}
build(): HTMLElement {
return this.element
}
static element(tag: string, attributes: { [key: string]: string | number }, ...classes: string[]): Builder {
return new Builder(tag).addAttributes(attributes).addClass(...classes)
}
}
+28
View File
@@ -0,0 +1,28 @@
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
width: 100%;
main {
align-items: center;
display: flex;
flex-direction: column;
flex-grow: 1;
.container {
height: 100%;
width: 100%;
}
}
footer {
text-align: center;
}
}
-85
View File
@@ -1,85 +0,0 @@
$fxl-gray: #263238;
$fxl-orange: #ff6e40;
@use "@material/theme" with (
$primary: $fxl-orange,
$on-primary: $fxl-gray
);
@use "@material/button/styles" as button-styles;
@use "@material/button/mixins" as button-mixins;
@use "@material/chips/styles" as chip-styles;
@use "@material/icon-button/icon-button";
@use "@material/linear-progress";
@use "@material/top-app-bar/mdc-top-app-bar";
@use "@material/typography/mdc-typography";
html, body {
height: 100vh;
margin: 0;
padding: 0;
}
body {
@include icon-button.core-styles;
display: flex;
flex-direction: column;
main {
@include linear-progress.core-styles;
display: flex;
flex: 1;
flex-direction: column;
padding: 1rem;
header {
ul {
align-content: center;
display: flex;
justify-content: center;
list-style: none;
margin: 0;
padding: 0;
li {
margin: 0 0.25em;
button.active-set {
@include button-mixins.filled-accessible($fxl-gray);
}
}
}
}
article {
display: flex;
flex: 1;
justify-content: space-around;
text-align: center;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
&:focus + label {
outline: thin dotted;
}
&:focus-within + label {
outline: thin dotted;
}
}
}
footer {
background-color: $fxl-orange;
font-size: smaller;
text-align: center;
}
}
+2 -15
View File
@@ -6,20 +6,7 @@
<form enctype="multipart/form-data" method="post" asp-action="Upload" id="file_upload"> <form enctype="multipart/form-data" method="post" asp-action="Upload" id="file_upload">
<fieldset> <fieldset>
<input type="file" name="file" multiple accept=".lzh" class="visually-hidden" id="lzh_upload"> <input type="file" name="file" multiple accept=".lzh">
<label for="lzh_upload" class="mdc-button mdc-button--outlined">
<span class="mdc-button__ripple"></span>
<span class="mdc-button__label">Add KiSS file(s)</span>
</label>
<button type="submit" class="mdc-button mdc-button--unelevated">
<span class="mdc-button__ripple"></span>
<span class="mdc-button__label">Upload</span>
</button>
<div class="selected-files mdc-evolution-chip-set" role="grid">
<div class="mdc-evolution-chip-set__chips" role="presentation"></div>
</div>
</fieldset> </fieldset>
</form> </form>
@@ -42,5 +29,5 @@
@section Scripts @section Scripts
{ {
<script src="~/js/uploader.js" asp-append-version="true"></script>
} }
-6
View File
@@ -1,6 +0,0 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
+1 -1
View File
@@ -6,5 +6,5 @@ Uploading...
@section Scripts @section Scripts
{ {
<script src="~/js/uploader.js" asp-append-version="true"></script>
} }
+16 -17
View File
@@ -4,24 +4,23 @@
ViewData["Title"] = $"Play with {Model.Name}"; ViewData["Title"] = $"Play with {Model.Name}";
} }
<header id="play_menu"> <header>
<ul> Sets:
<li> @for (var index = 0; index < Model.Sets.Length; index++)
<button class="mdc-button mdc-button--icon-trailing" data-rel="reset"> {
<span class="mdc-button__ripple"></span> @if (Model.Sets[index])
<span class="mdc-button__label">Reset</span> {
<i class="material-icons mdc-button__icon" aria-hidden="true">restart_alt</i> <a href="javascript:" class="set-link" data-set="@index">@(index + 1)</a>
</button> }
</li> }
<li class="mdc-typography--button">Sets</li>
</ul>
</header> </header>
<article id="play_area" style="background-color: #@Model.BorderColor"> <div class="container">
<canvas id="play_space" style="height: @(Model.Height)px; width: @(Model.Width)px" height="@Model.Height" width="@Model.Width"></canvas> <canvas id="play_space"></canvas>
</article> </div>
@section Scripts @section Scripts
{ {
<script> <script src="~/js/main.js"></script>
document.kisekae.load("play_space", "play_menu", @Json.Serialize(Model)) <script>playSet = @Json.Serialize(Model);</script>
</script>
} }
+6 -34
View File
@@ -4,44 +4,16 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Kisekae Online - @ViewData["Title"]</title> <title>Kisekae Online - @ViewData["Title"]</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="/css/main.css">
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto:900i" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<link href="~/css/main.css" rel="stylesheet">
</head> </head>
<body class="mdc-typography"> <body>
<header class="mdc-top-app-bar"> <header>
<div class="mdc-top-app-bar__row"> <h1><a href="~/">Kisekae Online</a> - @ViewData["Title"]</h1>
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start">
<span class="mdc-top-app-bar__title">Kisekae Online - @ViewData["Title"]</span>
</section>
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-end" role="toolbar">
<a href="/" class="material-icons mdc-top-app-bar__action-item mdc-icon-button" aria-label="Home">home</a>
<a class="material-icons mdc-top-app-bar__action-item mdc-icon-button" aria-label="Favorite">favorite</a>
<a class="material-icons mdc-top-app-bar__action-item mdc-icon-button" aria-label="Search">search</a>
<a class="material-icons mdc-top-app-bar__action-item mdc-icon-button" aria-label="Options">more_vert</a>
</section>
</div>
</header> </header>
<main class="mdc-top-app-bar--fixed-adjust" role="main"> <main>
<div role="progressbar" class="mdc-linear-progress" aria-label="Example Progress Bar" aria-valuemin="0" aria-valuemax="1" aria-valuenow="0">
<div class="mdc-linear-progress__buffer">
<div class="mdc-linear-progress__buffer-bar"></div>
<div class="mdc-linear-progress__buffer-dots"></div>
</div>
<div class="mdc-linear-progress__bar mdc-linear-progress__primary-bar">
<span class="mdc-linear-progress__bar-inner"></span>
</div>
<div class="mdc-linear-progress__bar mdc-linear-progress__secondary-bar">
<span class="mdc-linear-progress__bar-inner"></span>
</div>
</div>
@RenderBody() @RenderBody()
</main> </main>
<footer> <footer>&copy; @DateTime.Now.Year - <a href="https://fxl.codes">fxl</a></footer>
&copy; 2021 - <a href="https://fxl.codes">fxl</a> - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</footer>
<script src="~/js/main.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", false) @await RenderSectionAsync("Scripts", false)
</body> </body>
</html> </html>
+16 -15
View File
@@ -7,26 +7,27 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<TypeScriptCompile Include="Scripts\main.ts" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.1"/>
<TypeScriptCompile Include="Scripts\pto.ts" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1"/>
<TypeScriptCompile Include="Scripts\tracker.ts" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<TypeScriptCompile Include="Scripts\upload.ts" /> <PrivateAssets>all</PrivateAssets>
<TypeScriptCompile Include="Scripts\utility.ts" /> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql" Version="8.0.1"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.1" /> <_ContentIncludedByDefault Remove="wwwroot\css\main.css"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\css\main.css" /> <Folder Include="wwwroot\css\"/>
<Folder Include="wwwroot\js\"/>
</ItemGroup>
<ItemGroup>
<None Remove="Scripts\fabric.min.js"/>
</ItemGroup> </ItemGroup>
</Project> </Project>
+939 -7996
View File
File diff suppressed because it is too large Load Diff
+9 -27
View File
@@ -1,31 +1,13 @@
{ {
"name": "fxl.codes.kisekae",
"version": "1.0.0",
"description": "Online Kisekae viewer",
"main": "index.js",
"scripts": {
"test": "exit 0",
"build": "webpack --mode=development",
"release": "webpack --mode=production"
},
"author": "Lani",
"license": "UNLICENSED",
"devDependencies": {
"@types/fabric": "^4.5.6",
"core-js": "^3.19.2",
"css-loader": "^6.5.1",
"extract-loader": "^5.1.0",
"file-loader": "^6.2.0",
"sass": "^1.43.4",
"sass-loader": "^12.3.0",
"ts-loader": "^9.2.6",
"webpack": "^5.61.0",
"webpack-cli": "^4.9.1"
},
"dependencies": { "dependencies": {
"@types/lodash": "^4.14.178", "@types/fabric": "^5.3.7",
"fabric": "^4.6.0", "fabric": "^5.3.0"
"lodash": "^4.17.21", },
"material-components-web": "^13.0.0" "devDependencies": {
"@types/jquery": "^3.5.29",
"jquery": "^3.7.1",
"ts-loader": "^9.5.1",
"webpack": "^5.90.1",
"webpack-cli": "^5.1.4"
} }
} }
+16 -4
View File
@@ -1,12 +1,24 @@
{ {
"compilerOptions": { "compilerOptions": {
"moduleResolution": "Node", "moduleResolution": "Node",
"module": "ES6", "module": "AMD",
"noImplicitAny": true, "noImplicitAny": true,
"removeComments": true, "removeComments": true,
"preserveConstEnums": true, "preserveConstEnums": true,
"sourceMap": true "outFile": "wwwroot/js/main.js",
"allowSyntheticDefaultImports": true,
"types": [
"jquery"
],
"lib": [
"ESNext",
"DOM"
]
}, },
"include": ["./Scripts/*"], "include": [
"exclude": ["node_modules"] "./Scripts/*"
],
"exclude": [
"node_modules"
]
} }
+3 -36
View File
@@ -1,9 +1,9 @@
const path = require('path'); const path = require('path');
module.exports = [{ module.exports = [{
mode: "development",
entry: { entry: {
main: ["./Scripts/main.ts", "./Styles/main.scss"], main: ["./Scripts/play.ts"]
uploader: "./Scripts/upload.ts",
}, },
output: { output: {
filename: 'js/[name].js', filename: 'js/[name].js',
@@ -15,41 +15,8 @@ module.exports = [{
}, },
module: { module: {
rules: [ rules: [
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: 'css/main.css',
},
},
{loader: 'extract-loader'},
{
loader: 'css-loader',
options: {
// What the **fuck**
// https://github.com/peerigon/extract-loader/issues/111#issuecomment-948791524
esModule: false
}
},
{
loader: 'sass-loader',
options: {
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
sassOptions: {
includePaths: ['./node_modules'],
},
},
}
],
},
{test: /\.tsx?$/, loader: "ts-loader"} {test: /\.tsx?$/, loader: "ts-loader"}
], ]
}, },
stats: { stats: {
errorDetails: true errorDetails: true
+5 -2872
View File
File diff suppressed because it is too large Load Diff
+19 -348
View File
File diff suppressed because one or more lines are too long
+1 -83
View File
@@ -1,83 +1 @@
/*! ***************************************************************************** /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/**
* @license
* Copyright 2016 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @license
* Copyright 2017 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @license
* Copyright 2019 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
File diff suppressed because one or more lines are too long