Remove the old v5 angular version.

This commit is contained in:
florian committed 2019-02-16 14:10:04 +01:00
1 parent 52fe0abee1
commit 18c4d0ba0d
94 files changed
-4021

No files matched your search

-67
View File
@@ -1,67 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "codiki-bootstrap-material"
},
"apps": [
{
"root": "src",
"outDir": "../resources/static/",
"assets": [
"assets",
"favicon.png"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"../node_modules/font-awesome/scss/font-awesome.scss",
"../node_modules/angular-bootstrap-md/scss/bootstrap/bootstrap.scss",
"../node_modules/angular-bootstrap-md/scss/mdb-free.scss",
"./styles.scss"
],
"scripts": [
"../node_modules/chart.js/dist/Chart.js",
"../node_modules/hammerjs/hammer.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"integ": "environments/environment.integ.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"component": {}
}
}
-13
View File
@@ -1,13 +0,0 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
-16
View File
@@ -1,16 +0,0 @@
{
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
// Pointez pour afficher la description des attributs existants.
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"url": "http://localhost:4200/#",
"webRoot": "${workspaceFolder}",
"runtimeExecutable": "/usr/bin/chromium"
},
]
}
-27
View File
@@ -1,27 +0,0 @@
# CodikiBootstrapMaterial
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.1.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
-33
View File
@@ -1,33 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
-53
View File
@@ -1,53 +0,0 @@
{
"name": "codiki-bootstrap-material",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.2.0",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/core": "^5.2.0",
"@angular/forms": "^5.2.0",
"@angular/http": "^5.2.0",
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
"angular-bootstrap-md": "^5.2.3",
"chart.js": "^2.5.0",
"core-js": "^2.4.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"ng2-handy-syntax-highlighter": "^1.0.12",
"rxjs": "^5.5.6",
"zone.js": "^0.8.19"
},
"devDependencies": {
"@angular/cli": "~1.7.1",
"@angular/compiler-cli": "^5.2.0",
"@angular/language-service": "^5.2.0",
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~4.1.0",
"tslint": "~5.9.1",
"typescript": "~2.5.3"
}
}
-28
View File
@@ -1,28 +0,0 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
@@ -1,55 +0,0 @@
<h1>Paramètres</h1>
<div class="align-top">
<div class="card hoverable">
<a routerLink="/changePassword">
<div class="card-body row">
<div class="col-10">
<h4>
<i class="fa fa-lock blue-text"></i>
Mot de passe
</h4>
</div>
<div class="col-1 d-flex align-items-center text-right">
<i class="fa fa-chevron-right"></i>
</div>
</div>
<div class="card-body grey lighten-4">
Changer de mot de passe
</div>
</a>
</div>
<div class="card hoverable">
<a routerLink="/profilEdit">
<div class="card-body row">
<div class="col-10">
<h4>
<i class="fa fa-user-circle blue-text"></i>
Mes informations
</h4>
</div>
<div class="col-1 d-flex align-items-center text-right">
<i class="fa fa-chevron-right"></i>
</div>
</div>
<div class="card-body grey lighten-4">
Modifier les informations personnelles comme mon nom, mon adresse mail ou encore mon image de profil
</div>
</a>
</div>
<div class="card grey-text">
<div class="card-body row">
<div class="col-10">
<h4>
<i class="fa fa-cog"></i>
Paramètres de compte
</h4>
</div>
<div class="col-1 d-flex align-items-center text-right">
<i class="fa fa-chevron-right"></i>
</div>
</div>
<div class="card-body grey lighten-4">
Paramètres divers
</div>
</div>
</div>
@@ -1,24 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-account-settings',
templateUrl: './account-settings.component.html',
styles: [`
h4 i {
margin-right: 10px;
}
a, a:visited, a:hover {
color: black;
}
.card {
margin-right: 20px;
width: 30%;
display: inline-block;
vertical-align: top;
}
`]
})
export class AccountSettingsComponent {
}
@@ -1,61 +0,0 @@
<div class="card col-md-8 offset-md-2 col-lg-6 offset-lg-3">
<div id="form" class="card-body">
<h4 class="card-title">Mot de passe</h4>
<form (ngSubmit)="onSubmit()" #changePasswordForm="ngForm">
<div class="md-form">
<input mdbActive
id="oldPassword"
name="oldPassword"
type="password"
class="form-control"
[(ngModel)]="model.oldPassword"
#oldPassword="ngModel"
data-error="Veuillez saisir votre mot de passe actuel"
data-sucess=""
required />
<label for="oldPassword">Mot de passe actuel</label>
</div>
<div class="md-form">
<input mdbActive
id="newPassword"
name="newPassword"
type="password"
class="form-control"
[(ngModel)]="model.newPassword"
#newPassword="ngModel"
data-error="Veuillez saisir votre nouveau mot de passe"
data-sucess=""
required />
<label for="newPassword">Nouveau mot de passe</label>
</div>
<div class="md-form">
<input mdbActive
id="confirmPassword"
name="confirmPassword"
type="password"
class="form-control"
[(ngModel)]="model.confirmPassword"
#confirmPassword="ngModel"
data-error="Veuillez confirmer votre nouveau mot de passe"
data-sucess=""
required />
<label for="confirmPassword">Confirmation de votre mot de passe</label>
</div>
<div class="card red lighten-2 text-center z-depth-2" *ngIf="error">
<div class="card-body">
<p class="white-text mb-0">{{error}}</p>
</div>
</div>
<div class="col submitFormArea">
<a routerLink="/accountSettings" class="indigo-text">
Annuler
</a>
<button class="float-right waves-effect waves-light indigo btn"
type="submit" [disabled]="!changePasswordForm.form.valid">
Suivant
</button>
</div>
</form>
</div>
</div>
@@ -1,37 +0,0 @@
import { Component } from '@angular/core';
import { PasswordWrapper } from '../../core/entities';
import { ChangePasswordService } from './change-password.service';
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
@Component({
selector: 'app-change-password',
templateUrl: './change-password.component.html',
styles: [`
#form.card-body {
padding-bottom: 10px;
}
.submitFormArea {
line-height: 50px;
}
`]
})
export class ChangePasswordComponent {
model: PasswordWrapper = new PasswordWrapper('', '', '');
error: string;
constructor(
private changePasswordService: ChangePasswordService
) {}
onSubmit(): void {
if (this.model.newPassword !== this.model.confirmPassword) {
this.error = 'Les mots de passe saisis ne correspondent pas.';
} else {
this.changePasswordService.changePassword(this.model).subscribe(null, error => {
this.error = 'Le mot de passe saisi ne correspond pas au votre.';
});
}
}
}
@@ -1,17 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { PasswordWrapper } from '../../core/entities';
import { environment } from '../../../environments/environment';
const ACCOUNT_URL = environment.apiUrl + '/api/account';
@Injectable()
export class ChangePasswordService {
constructor(private http: HttpClient) {}
changePassword(passwordWrapper: PasswordWrapper): Observable<any> {
return this.http.put(ACCOUNT_URL + '/changePassword', passwordWrapper);
}
}
@@ -1,60 +0,0 @@
<input id="profilImageInput" type="file" (change)="uploadImage($event)" [hidden]="true">
<div class="col-md-8 offset-md-2 col-lg-6 offset-lg-3">
<div class="card">
<img id="profil-image" class="card-img-top"
(click)="triggerProfilImageChange()"
[src]="getAvatarUrl()"
alt="Card image cap"
mdbTooltip="Modifier mon image de profil"
placement="bottom">
<div id="form" class="card-body">
<form (ngSubmit)="onSubmit()" #profilEditionForm="ngForm">
<div class="md-form">
<input mdbActive
id="name"
name="name"
type="text"
class="form-control"
[(ngModel)]="model.name"
#name="ngModel"
data-error="Veuillez saisir votre nom d'utilisateur"
data-sucess=""
required />
<label for="name">Nom d'utilisateur</label>
</div>
<div class="md-form">
<input mdbActive
id="email"
name="email"
type="email"
class="form-control"
[(ngModel)]="model.email"
#email="ngModel"
data-error="Veuillez saisir votre adresse email"
data-sucess=""
required />
<label for="email">Email</label>
</div>
<div id="errorMsg" class="card red lighten-2 text-center z-depth-2">
<div class="card-body">
<p class="white-text mb-0">{{modelError}}</p>
</div>
</div>
<div id="resultMsg" class="card green lighten-2 text-center z-depth-2" >
<div class="card-body">
<p class="white-text mb-0">{{result}}</p>
</div>
</div>
<div class="col submitFormArea">
<a routerLink="/accountSettings" class="indigo-text">
Annuler
</a>
<button class="float-right waves-effect waves-light indigo btn"
type="submit" [disabled]="!profilEditionForm.form.valid">
Suivant
</button>
</div>
</form>
</div>
</div>
</div>
@@ -1,101 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { ProfilEditionService } from './profil-edition.service';
import { HttpEventType, HttpResponse } from '@angular/common/http';
import { User } from '../../core/entities';
import { AuthService } from '../../core/services/auth.service';
import { environment } from '../../../environments/environment';
@Component({
selector: 'app-profil-edition',
templateUrl: './profil-edition.component.html',
styles: [`
#form {
padding-bottom: 10px;
}
.submitFormArea {
line-height: 50px;
}
#profil-image {
cursor: pointer;
}
#resultMsg, #errorMsg {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
margin: 0;
}
`]
})
export class ProfilEditionComponent implements OnInit {
model: User;
selectedFiles: FileList;
currentFileUpload: File;
progress: { percentage: number } = { percentage: 0 };
modelError: string;
result: string;
constructor(
private profilEditionService: ProfilEditionService,
private authService: AuthService
) {}
ngOnInit(): void {
this.model = this.authService.getUser();
}
getAvatarUrl(): string {
return this.model.image
? `${environment.apiUrl}/api/images/loadAvatar/${this.model.image}`
: './assets/images/default_user.png';
}
triggerProfilImageChange(): void {
document.getElementById('profilImageInput').click();
}
uploadImage(event) {
this.selectedFiles = event.target.files;
this.progress.percentage = 0;
this.currentFileUpload = this.selectedFiles.item(0);
// This prevents error 400 if user doesn't select any file to upload and close the input file.
if (this.currentFileUpload) {
this.profilEditionService.uploadAvatarPicture(this.currentFileUpload).subscribe(result => {
if (result.type === HttpEventType.UploadProgress) {
this.progress.percentage = Math.round(100 * result.loaded / result.total);
} else if (result instanceof HttpResponse) {
console.log('File ' + result.body + ' completely uploaded!');
this.model.image = result.body as string;
this.authService.setUser(this.model);
}
this.selectedFiles = undefined;
});
}
}
onSubmit(): void {
this.profilEditionService.updateUser(this.model).subscribe(() => {
this.setMessage('Modification enregistrée.', false);
}, error => {
this.setMessage('L\'adresse mail saisie n\'est pas disponible.', true);
});
}
setMessage(message: string, error: boolean): void {
this[error ? 'modelError' : 'result'] = message;
const resultMsgDiv = document.getElementById(error ? 'errorMsg' : 'resultMsg');
resultMsgDiv.style.maxHeight = '64px';
setTimeout(() => {
resultMsgDiv.style.maxHeight = '0px';
setTimeout(() => {
this[error ? 'modelError' : 'result'] = undefined;
}, 550);
}, 3000);
}
}
@@ -1,30 +0,0 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpRequest, HttpEvent} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import { environment } from '../../../environments/environment';
import { User } from '../../core/entities';
const IMAGES_URL = environment.apiUrl + '/api/images';
const ACCOUNT_URL = environment.apiUrl + '/api/account';
@Injectable()
export class ProfilEditionService {
constructor(private http: HttpClient) {}
uploadAvatarPicture(file: File): Observable<HttpEvent<{}>> {
const formData: FormData = new FormData();
formData.append('file', file);
return this.http.request(new HttpRequest(
'POST', IMAGES_URL + '/uploadAvatar', formData, {
reportProgress: true,
responseType: 'text'
}
));
}
updateUser(user: User): Observable<any> {
return this.http.put<any>(`${ACCOUNT_URL}/`, user);
}
}
@@ -1,5 +0,0 @@
<app-header></app-header>
<main class="container">
<router-outlet></router-outlet>
</main>
<app-footer></app-footer>
@@ -1,3 +0,0 @@
main {
flex:1 0 auto;
}
@@ -1,27 +0,0 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
}));
});
-10
View File
@@ -1,10 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app';
}
-121
View File
@@ -1,121 +0,0 @@
// Angular core
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
// Dependencies
import { MDBBootstrapModule } from 'angular-bootstrap-md';
// Router
import { appRoutes } from './app.routes';
// Components
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { NotFoundComponent } from './not-found/not-found.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { DisconnectionComponent } from './disconnection/disconnection.component';
import { PostCardComponent } from './core/post-card/post-card.component';
import { PostComponent } from './posts/post.component';
import { ByCategoryComponent } from './posts/byCategory/by-category.component';
import { MyPostsComponent } from './posts/myPosts/my-posts.component';
import { AccountSettingsComponent } from './account-settings/account-settings.component';
import { ChangePasswordComponent } from './account-settings/change-password/change-password.component';
import { ProfilEditionComponent } from './account-settings/profil-edition/profil-edition.component';
import { CreateUpdatePostComponent } from './posts/create-update/create-update-post.component';
import { ForbiddenComponent } from './forbidden/forbidden.component';
import { SearchComponent } from './search/search.component';
import { SigninComponent } from './signin/signin.component';
import { VersionRevisionComponent } from './version-revisions/version-revisions.component';
// html components
import { ProgressBarComponent } from './core/directives/progress-bar/progress-bar.component';
import { SpinnerComponent } from './core/directives/spinner/spinner.component';
import { SearchBarComponent } from './core/directives/search-bar/search-bar.component';
// Services
import { AuthService } from './core/services/auth.service';
import { LoginService } from './login/login.service';
import { HomeService } from './home/home.service';
import { PostService } from './posts/post.service';
import { ByCategoryService } from './posts/byCategory/by-category.service';
import { MyPostsService } from './posts/myPosts/my-posts.service';
import { ChangePasswordService } from './account-settings/change-password/change-password.service';
import { ProfilEditionService } from './account-settings/profil-edition/profil-edition.service';
import { HeaderService } from './header/header.service';
import { CreateUpdatePostService } from './posts/create-update/create-update-post.service';
import { SearchService } from './search/search.service';
import { VersionRevisionService } from './version-revisions/version-revisions.service';
// Guards
import { AuthGuard } from './core/guards/auth.guard';
// Interceptors
import { TokenInterceptor } from './core/interceptors/token-interceptor';
import { SigninService } from './signin/signin.service';
@NgModule({
declarations: [
AppComponent,
HeaderComponent,
FooterComponent,
NotFoundComponent,
HomeComponent,
LoginComponent,
DisconnectionComponent,
PostCardComponent,
PostComponent,
ByCategoryComponent,
MyPostsComponent,
AccountSettingsComponent,
CreateUpdatePostComponent,
ChangePasswordComponent,
ProfilEditionComponent,
ForbiddenComponent,
SearchComponent,
SigninComponent,
ProgressBarComponent,
SpinnerComponent,
SearchBarComponent,
VersionRevisionComponent
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
MDBBootstrapModule.forRoot(),
RouterModule.forRoot(
appRoutes,
// { enableTracing: true } // Enabling tracing
{ onSameUrlNavigation: 'reload' }
)
],
providers: [
AuthService,
LoginService,
SigninService,
HomeService,
PostService,
ByCategoryService,
MyPostsService,
ChangePasswordService,
ProfilEditionService,
HeaderService,
CreateUpdatePostService,
SearchService,
VersionRevisionService,
AuthGuard,
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent],
schemas: [ NO_ERRORS_SCHEMA ]
})
export class AppModule { }
-39
View File
@@ -1,39 +0,0 @@
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { NotFoundComponent } from './not-found/not-found.component';
import { LoginComponent } from './login/login.component';
import { SigninComponent } from './signin/signin.component';
import { DisconnectionComponent } from './disconnection/disconnection.component';
import { PostComponent } from './posts/post.component';
import { ByCategoryComponent } from './posts/byCategory/by-category.component';
import { MyPostsComponent } from './posts/myPosts/my-posts.component';
import { AccountSettingsComponent } from './account-settings/account-settings.component';
import { ChangePasswordComponent } from './account-settings/change-password/change-password.component';
import { CreateUpdatePostComponent } from './posts/create-update/create-update-post.component';
import { ForbiddenComponent } from './forbidden/forbidden.component';
import { ProfilEditionComponent } from './account-settings/profil-edition/profil-edition.component';
import { SearchComponent } from './search/search.component';
import { VersionRevisionComponent } from './version-revisions/version-revisions.component';
import { AuthGuard } from './core/guards/auth.guard';
export const appRoutes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'signin', component: SigninComponent },
{ path: 'home', component: HomeComponent },
{ path: 'disconnection', component: DisconnectionComponent },
{ path: 'posts/new', component: CreateUpdatePostComponent, canActivate: [AuthGuard] },
{ path: 'posts/update/:postKey', component: CreateUpdatePostComponent, canActivate: [AuthGuard] },
{ path: 'posts/:postKey', component: PostComponent },
{ path: 'posts/byCategory/:categoryId', component: ByCategoryComponent},
{ path: 'posts/search/:searchCriteria', component: SearchComponent},
{ path: 'myPosts', component: MyPostsComponent, canActivate: [AuthGuard]},
{ path: 'accountSettings', component: AccountSettingsComponent, canActivate: [AuthGuard] },
{ path: 'changePassword', component: ChangePasswordComponent, canActivate: [AuthGuard] },
{ path: 'profilEdit', component: ProfilEditionComponent, canActivate: [AuthGuard] },
{ path: 'versionrevisions', component: VersionRevisionComponent },
{ path: 'forbidden', component: ForbiddenComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: NotFoundComponent }
];
@@ -1,112 +0,0 @@
.progress {
position: relative;
height: 4px;
display: block;
width: 100%;
background-color: #3F729B;
border-radius: 2px;
background-clip: padding-box;
margin: 0.5rem 0 1rem 0;
overflow: hidden;
-webkit-animation: random-background 5s infinite;
animation: random-background 5s infinite;transition: all 0.3s ease-out;
}
@keyframes random-background {
15% { background-color: #ff444480; }
30% { background-color: #ffbb3381; }
45% { background-color: rgba(0, 200, 80, 0.575); }
60% { background-color: #33b6e58c; }
75% { background-color: #aa66cc7c; }
}
.progress .indeterminate {
background-color: #1C2331;
-webkit-animation: random-bar 5s infinite;
animation: random-bar 5s infinite;transition: all 0.3s ease-out;
}
@keyframes random-bar {
15% { background-color: #ff4444; }
30% { background-color: #ffbb33; }
45% { background-color: #00C851; }
60% { background-color: #33b5e5; }
75% { background-color: #aa66cc; }
}
.progress .indeterminate:before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
.progress .indeterminate:after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
-webkit-animation-delay: 1.15s;
animation-delay: 1.15s;
}
@-webkit-keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@-webkit-keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
@@ -1,12 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-progress-bar',
template: `
<div class="progress">
<div class="indeterminate"></div>
</div>
`,
styleUrls: ['./progress-bar.component.scss']
})
export class ProgressBarComponent {}
@@ -1,65 +0,0 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
 @Component({
selector: 'app-search-bar',
template: `
<div id="search-bar">
<input id="search" name="search" type="text" [(ngModel)]="model" (keyup.enter)="search()" />
<label for="search" class="label-icon">
<i id="search-icon" class="fa fa-search" (click)="search()"></i>
</label>
</div>
`,
styles: [`
div#search-bar {
position: relative;
margin-right: 5px;
}
input#search, input#search:focus {
border-bottom: none;
}
input#search {
width: 400px;
height: 36px;
color: white;
background-color: #5c6bc0;
border-radius: 2px;
padding-left: 10px;
padding-right: 35px;
}
input#search:focus {
background: white;
color: #3f51b5;
}
i#search-icon {
font-size: 20px;
position: absolute;
right: 15px;
top: 8px;
color: #9e9e9e;
cursor: pointer;
}
`]
})
export class SearchBarComponent {
model: string;
constructor(
private router: Router
) {}
search(): void {
if (this.model) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.navigateByUrl(`/posts/search/${this.model}`).then(() => {
this.router.navigated = false;
this.router.navigate([this.router.url]);
});
}
}
}
@@ -1,84 +0,0 @@
$green: #00C851;
$blue: #33b5e5;
$red: #ff4444;
$yellow: #ffbb33;
$white: #eee;
$width: 100px;
body {
background-color: $white;
}
.showbox {
padding: 5%;
}
.loader {
position: relative;
margin: 0 auto;
width: $width;
&:before {
content: '';
display: block;
padding-top: 100%;
}
}
.circular {
animation: rotate 2s linear infinite;
height: 100%;
transform-origin: center center;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.path {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
stroke-linecap: round;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
@keyframes color {
100%,
0% {
stroke: $red;
}
40% {
stroke: $blue;
}
66% {
stroke: $green;
}
80%,
90% {
stroke: $yellow;
}
}
@@ -1,18 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-spinner',
template: `
<div class="showbox">
<div class="loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/>
</svg>
</div>
</div>
`,
styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent {
}
-75
View File
@@ -1,75 +0,0 @@
export class Role {
constructor(
public id: number,
public name: string
) { }
}
export class User {
constructor(
public key: string,
public name: string,
public email: string,
public password: string,
public image: string,
public inscriptionDate: Date,
public role: Role,
public token: string
) { }
}
export class Post {
constructor(
public key: string,
public title: string,
public text: string,
public description: string,
public image: string,
public creationDate: Date,
public author: User,
public category: Category
) { }
}
export class Category {
constructor(
public id: number,
public name: string,
public listSubCategories: Array<Category>
) { }
}
export class Image {
constructor(
public id: number,
public link: string
) { }
}
/**
* Class to send the new password to backoffice in order to change the user password.
*/
export class PasswordWrapper {
constructor(
public oldPassword: string,
public newPassword: string,
public confirmPassword: string
) { }
}
export class Version {
constructor(
public id: number,
public number: string,
public active: boolean
) { }
}
export class VersionRevision {
constructor(
public id: number,
public text: string,
public version: Version,
public bugfix: boolean
) { }
}
@@ -1,26 +0,0 @@
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../services/auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authService: AuthService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let result: boolean;
if (this.authService.isAuthenticated()) {
result = true;
} else {
result = false;
this.router.navigate(['/login']);
}
return result;
}
}
@@ -1,43 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import { User } from '../entities';
import { AuthService } from '../services/auth.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(
private authService: AuthService,
private router: Router
) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = this.authService.getToken();
let request: HttpRequest<any> = req;
if (token) {
request = req.clone({
setHeaders: {
token: token
}
});
}
return next.handle(request).do((event: HttpEvent<any>) => {
// Do nothing for the interceptor
}, (err: any) => {
if (err instanceof HttpErrorResponse && err.status === 401) {
this.authService.disconnect();
this.router.navigate(['/login']);
}
});
}
}
@@ -1,60 +0,0 @@
import { Component, Input } from '@angular/core';
import { Post } from '../entities';
import { environment } from '../../../environments/environment';
@Component({
selector: 'app-post-card',
template: `
<div class="card hoverable">
<div class="view hm-white-slight waves-light" mdbRippleRadius>
<img id="post-image" class="img-fluid" [src]="post.image" alt="Article" />
<a routerLink="/posts/{{post.key}}">
<div class="mask"></div>
</a>
</div>
<div class="card-body">
<h4 class="card-title">{{post.title}}</h4>
<p class="card-text">{{post.description}}</p>
</div>
<div class="card-data">
<img [src]="getAvatarUrl()"
class="author-img"
[alt]="post.author.name"
[mdbTooltip]="post.author.name"
placement="bottom"/>
Article écrit par {{post.author.name}}
<span class="creation-date-area">({{post.creationDate | date:'yyyy-MM-dd HH:mm:ss'}})</span>
</div>
</div>`,
styles: [`
div.card {
margin-bottom: 50px;
}
.card .card-data {
padding: 15px;
background-color: #f5f5f5;
}
.creation-date-area {
color: #bdbdbd;
font-style: italic;
}
.author-img {
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 15px;
}
#post-image {
width: 100%;
}
`]
})
export class PostCardComponent {
@Input() post: Post;
getAvatarUrl(): string {
return this.post.author.image
? `${environment.apiUrl}/api/images/loadAvatar/${this.post.author.image}`
: './assets/images/default_user.png';
}
}
@@ -1,39 +0,0 @@
import { Injectable } from '@angular/core';
import { User } from '../entities';
const PARAM_TOKEN = 'token';
const PARAM_USER = 'user';
@Injectable()
export class AuthService {
constructor() {}
public getToken(): string {
return localStorage.getItem(PARAM_TOKEN);
}
public setToken(token: string): void {
localStorage.setItem(PARAM_TOKEN, token);
}
public isAuthenticated(): boolean {
return this.getToken() != null;
}
public disconnect(): void {
localStorage.clear();
}
public isAdmin(): boolean {
return false;
}
public setUser(user: User): void {
localStorage.setItem(PARAM_USER, JSON.stringify(user));
}
public getUser(): User {
return JSON.parse(localStorage.getItem(PARAM_USER));
}
}
@@ -1,21 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../core/services/auth.service';
@Component({
selector: 'app-disconnection',
template: 'Déconnexion...'
})
export class DisconnectionComponent implements OnInit {
constructor(
private authService: AuthService,
private router: Router
) {}
ngOnInit(): void {
this.authService.disconnect();
this.router.navigate(['/home']);
}
}
@@ -1,20 +0,0 @@
<footer class="page-footer indigo center-on-small-only">
<!-- fixed-bottom -->
<div class="footer-copyright">
<div class="container">
<span class="float-left">
<span class="anticopy">&copy;</span> 2017 Tous droits r&eacute;serv&eacute;s -
<i id="appVersion" routerLink="/versionrevisions" mdbTooltip="Notes de versions" placement="top" mdbRippleRadius>
{{appVersion}}
</i>
</span>
<span class="float-right">
<a target="_blank" href="./assets/doc/codiki_user_manual.pdf" mdbTooltip="Manuel d'utilisation" placement="top" mdbRippleRadius>
<i class="fa fa-book"></i>
</a> -
Développements réalisés par
<a href="mailto:florian.thierry72@gmail.com">Florian THIERRY</a>
</span>
</div>
</div>
</footer>
@@ -1,19 +0,0 @@
footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
}
.page-footer {
padding-top: 0px;
}
span.anticopy {
display: inline-block;
transform: rotate(180deg);
}
#appVersion {
color: rgba(255, 255, 255, 0.6);
}
@@ -1,12 +0,0 @@
import { Component } from '@angular/core';
import { environment } from '../../environments/environment';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent {
appVersion = environment.appVersion;
}
@@ -1,18 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-forbidden',
template: `
<div class="text-center">
<img src="./assets/images/403.png" alt="403" />
<h3>Vous n'êtes pas autorisé à effectuer cette action...</h3>
</div>
`,
styles: [`
img {
max-height: 500px;
margin-bottom: 30px;
}
`]
})
export class ForbiddenComponent {}
@@ -1,62 +0,0 @@
<mdb-navbar SideClass="navbar fixed-top navbar-expand-lg navbar-dark bg-indigo scrolling-navbar ie-nav" [containerInside]="false">
<logo>
<a class="logo navbar-brand" routerLink="/">
<img id="logo" src="./assets/images/codiki.png" alt="logo" />
<span id="title" *ngIf="!title">Codiki</span>
<span id="title" *ngIf="title">Codiki - {{title}}</span>
</a>
</logo>
<links>
<div class="navbar-nav ml-auto nav-flex-icons">
<app-search-bar></app-search-bar>
</div>
<ul class="navbar-nav ml-auto nav-flex-icons" style="margin-left: 0 !important;">
<li class="nav-item" *ngIf="!isAuthenticated()">
<a routerLink="/login" class="nav-link waves-light" mdbRippleRadius>
<i class="fa fa-sign-in"></i> Connexion
</a>
</li>
<li class="nav-item dropdown" dropdown *ngIf="isAuthenticated()">
<a dropdownToggle mdbRippleRadius type="button" class="nav-link dropdown-toggle waves-light" mdbRippleRadius>
<i class="fa fa-user-circle"></i> Mon Compte
</a>
<div *dropdownMenu class="dropdown-menu dropdown-menu-right dropdown dropdown-primary" role="menu">
<a class="dropdown-item waves-light" mdbRippleRadius routerLink="/myPosts">
<i class="fa fa-list-alt"></i> Mes articles
</a>
<a class="dropdown-item waves-light" mdbRippleRadius routerLink="/accountSettings">
<i class="fa fa-gear"></i> Paramètres
</a>
<a class="dropdown-item waves-light danger-color-dark" mdbRippleRadius routerLink="/disconnection">
<span class="white-text">
<i class="fa fa-sign-out"></i> Déconnexion
</span>
</a>
</div>
</li>
</ul>
<a (click)="openSidebar()">
<i id="sidebarButton" class="fa fa-lg fa-bars white-text"></i>
</a>
</links>
</mdb-navbar>
<div id="sidenav" class="sidenav">
<h3>Catégories</h3>
<a class="closebtn" (click)="closeSidebar()">
<i class="fa fa-chevron-left"></i>
</a>
<div *ngFor="let category of listCategories">
<a [id]="'category-' + category.id" class="collapsible" *ngIf="category.listSubCategories.length" (click)="openCategoriesLinks(category)">
{{category.name}} <i class="fa fa-chevron-down pull-right"></i>
</a>
<div class="categoriesLinks" >
<a *ngFor="let subCategory of category.listSubCategories"
(click)="openPostsByCategory(subCategory.id)">
{{subCategory.name}}
</a>
</div>
</div>
</div>
<div id="overlay" (click)="closeSidebar()"></div>
@@ -1,87 +0,0 @@
#title {
color: white;
font-weight: 400;
}
#logo {
width: 30px;
height: 30px;
margin-top: -7px;
vertical-align: middle;
margin-right: 10px;
}
#sidebarButton {
margin-left: 10px;
}
/* The side navigation menu */
.sidenav {
height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1000; /* Stay on top */
top: 0; /* Stay at the top */
left: 0;
background-color: #3f51b5;
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 20px; /* Place content 60px from the top */
transition: 0.3s; /* 0.5 second transition effect to slide in the sidenav */
}
/* The navigation menu links */
.sidenav a {
padding: 8px 32px 8px 32px;
text-decoration: none;
color: white;
display: block;
transition: 0.3s;
}
/* When you mouse over the navigation links, change their color */
.sidenav a:hover {
color: #ccc;
background-color: #5c6bc0;
}
.sidenav h3 {
padding: 8px 8px 8px 32px;
color: white;
padding-bottom: 25px;
border-bottom: 1px solid #5c6bc0;
}
/* Position and style the close button (top right corner) */
.sidenav .closebtn {
position: absolute;
top: 25px;
right: 25px;
margin-left: 50px;
padding: 8px;
}
/* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */
@media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
#overlay {
position: fixed; /* Sit on top of the page content */
display: none; /* Hidden by default */
width: 100%; /* Full width (cover the whole page) */
height: 100%; /* Full height (cover the whole page) */
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
z-index: 999; /* Specify a stack order in case you're using a different order for other elements */
transition: 0.5s;
}
.categoriesLinks {
background-color: #303f9f;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
@@ -1,80 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../core/services/auth.service';
import { Category } from '../core/entities';
import { HeaderService } from './header.service';
import { environment } from '../../environments/environment';
const SIDENAV_WIDTH = '300px';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
isAdmin: boolean;
listCategories: Array<Category> = [];
title: string;
constructor(
private authService: AuthService,
private headerService: HeaderService,
private router: Router
) {}
ngOnInit() {
this.title = environment.title;
this.isAdmin = this.authService.isAdmin();
this.headerService.getAllCategories().subscribe(listCategories => {
this.listCategories = listCategories;
});
}
isAuthenticated(): boolean {
// console.log('Checking if user is connected... for header');
return this.authService.isAuthenticated();
}
openSidebar(): void {
document.getElementById('sidenav').style.width = SIDENAV_WIDTH;
document.getElementById('overlay').style.display = 'block';
}
closeSidebar(): void {
document.getElementById('sidenav').style.width = '0';
document.getElementById('overlay').style.display = 'none';
}
/**
* Redirect the user to the page to show the posts of the category which its id is in parameters.
*
* @param categoryId The id of the category which we need to show its posts after redirection.
*/
openPostsByCategory(categoryId: string): void {
this.closeSidebar();
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.navigateByUrl('/posts/byCategory/' + categoryId).then(() => {
this.router.navigated = false;
this.router.navigate([this.router.url]);
});
}
/**
* Opens the accordion which correspond to the category in parameters.
*
* @param category The category which its accodion needs to be open.
*/
openCategoriesLinks(category: Category): void {
const divCategoriesLinks = document.getElementById('category-' + category.id);
divCategoriesLinks.classList.toggle('active');
const divContent = divCategoriesLinks.nextElementSibling as HTMLElement;
if (divContent.style.maxHeight) {
divContent.style.maxHeight = null;
} else {
divContent.style.maxHeight = divContent.scrollHeight + 'px';
}
}
}
@@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Category } from '../core/entities';
import { environment } from '../../environments/environment';
const CATEGORY_URL = environment.apiUrl + '/api/categories/';
@Injectable()
export class HeaderService {
constructor(private http: HttpClient) {}
getAllCategories(): Observable<Array<Category>> {
return this.http.get<Array<Category>>(CATEGORY_URL);
}
}
@@ -1,7 +0,0 @@
<div>
<h1>Derniers articles</h1>
<app-spinner *ngIf="!listArticle"></app-spinner>
<div *ngIf="listArticle" class="col-lg-8 offset-lg-2">
<app-post-card *ngFor="let post of listArticle" [post]="post"></app-post-card>
</div>
</div>
@@ -1,3 +0,0 @@
div.card {
margin-bottom: 50px;
}
@@ -1,24 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { HomeService } from './home.service';
import { Post } from '../core/entities';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
listArticle: Array<Post>;
title: string;
constructor(
private homeService: HomeService
) {}
ngOnInit(): void {
this.homeService.getLastPosts().subscribe(lastPosts => {
this.listArticle = lastPosts;
});
}
}
@@ -1,18 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Post } from '../core/entities';
import { environment } from '../../environments/environment';
const POSTS_URL = environment.apiUrl + '/api/posts';
@Injectable()
export class HomeService {
constructor(private http: HttpClient) {}
getLastPosts(): Observable<Array<Post>> {
return this.http.get<Array<Post>>(POSTS_URL + '/last');
}
}
@@ -1,49 +0,0 @@
<div class="card col-md-8 offset-md-2 col-lg-6 offset-lg-3">
<div class="card-body">
<h4 class="card-title">Connexion</h4>
<form id="form" (ngSubmit)="onSubmit()" #loginForm="ngForm">
<div class="md-form">
<i class="fa fa-envelope prefix grey-text"></i>
<input mdbActive
id="email"
name="email"
type="email"
class="form-control"
[(ngModel)]="model.email"
#email="ngModel"
data-error="Veuillez saisir une adresse email valide"
data-sucess=""
required />
<label for="email">Email</label>
</div>
<div class="md-form">
<i class="fa fa-lock prefix grey-text"></i>
<input mdbActive
id="password"
name="password"
type="password"
class="form-control"
[(ngModel)]="model.password"
#password="ngModel"
data-error="Veuillez saisir votre mot de passe"
data-sucess=""
required />
<label for="password">Password</label>
</div>
<div id="errorMsg" class="card red lighten-2 text-center z-depth-2">
<div class="card-body">
<p class="white-text mb-0">{{loginError}}</p>
</div>
</div>
<div class="col submitFormArea">
<a routerLink="/signin" class="indigo-text">
Je n'ai pas de compte
</a>
<button class="float-right waves-effect waves-light indigo btn"
type="submit" [disabled]="!loginForm.form.valid">
Suivant
</button>
</div>
</form>
</div>
</div>
@@ -1,62 +0,0 @@
import { Component } from '@angular/core';
import { User } from '../core/entities';
import { AuthService } from '../core/services/auth.service';
import { LoginService } from './login.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styles: [`
#form {
padding-bottom: 10px;
}
.submitFormArea {
line-height: 50px;
}
#errorMsg {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
margin: 0;
}
`]
})
export class LoginComponent {
model: User = new User('', '', '', '', '', null, null, '');
loginError: string;
constructor(
private loginService: LoginService,
private authService: AuthService,
private router: Router
) {}
onSubmit(): void {
this.loginError = undefined;
this.loginService.login(this.model).subscribe(user => {
this.authService.setToken(user.token);
this.authService.setUser(user);
this.router.navigate(['/myPosts']);
}, error => {
this.setMessage('Email ou password incorrect.');
});
}
setMessage(message: string): void {
this.loginError = message;
const resultMsgDiv = document.getElementById('errorMsg');
resultMsgDiv.style.maxHeight = '64px';
setTimeout(() => {
resultMsgDiv.style.maxHeight = '0px';
setTimeout(() => {
this.loginError = undefined;
}, 550);
}, 3000);
}
}
@@ -1,18 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { User } from '../core/entities';
import { environment } from '../../environments/environment';
const LOGIN_URL = environment.apiUrl + '/api/account/login';
@Injectable()
export class LoginService {
constructor(private http: HttpClient) {}
login(user: User): Observable<User> {
return this.http.post<User>(LOGIN_URL, user);
}
}
@@ -1,12 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-not-found',
template: `
<div class="text-center">
<img src="./assets/images/404.png" alt="404" />
<h3>Page non trouvée...</h3>
</div>
`
})
export class NotFoundComponent {}
@@ -1,7 +0,0 @@
<div>
<app-spinner *ngIf="!listPosts"></app-spinner>
<h1 *ngIf="listPosts">Catégorie {{category.name}}</h1>
<div *ngIf="listPosts" class="col-lg-8 offset-lg-2">
<app-post-card *ngFor="let post of listPosts" [post]="post"></app-post-card>
</div>
</div>
@@ -1,31 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Post, Category } from '../../core/entities';
import { ByCategoryService } from './by-category.service';
@Component({
selector: 'app-posts-by-category',
templateUrl: './by-category.component.html'
})
export class ByCategoryComponent implements OnInit {
category: Category;
listPosts: Array<Post>;
constructor(
private route: ActivatedRoute,
private byCategoryService: ByCategoryService
) {}
ngOnInit(): void {
// Get the category
this.byCategoryService.getCategoryById(+this.route.snapshot.paramMap.get('categoryId')).subscribe(category => {
this.category = category;
// Get the posts by category
this.byCategoryService.getPostsByCategory(this.category).subscribe(listPosts => {
this.listPosts = listPosts;
});
});
}
}
@@ -1,23 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../environments/environment';
import { Post, Category } from '../../core/entities';
const CATEGORIES_URL = environment.apiUrl + '/api/categories';
const POSTS_URL = environment.apiUrl + '/api/posts';
@Injectable()
export class ByCategoryService {
constructor(private http: HttpClient) {}
getCategoryById(categoryId: number): Observable<Category> {
return this.http.get<Category>(`${CATEGORIES_URL}/${categoryId}`);
}
getPostsByCategory(category: Category): Observable<Array<Post>> {
return this.http.get<Array<Post>>(`${POSTS_URL}/byCategory/${category.id}`);
}
}
@@ -1,240 +0,0 @@
<div class="card hoverable">
<div class="card-header indigo white-text" mdbRippleRadius>
<h1 *ngIf="!model.key">Création d'un article</h1>
<h1 *ngIf="model.key">Modification de l'article {{model.key}}</h1>
<div class="row">
<a class="waves-light tabs"
[ngClass]="{'active': activatedTab === 'Édition'}"
(click)="activateEdition()">
Édition
</a>
<a class="waves-light tabs"
[ngClass]="{'active': activatedTab === 'Aperçu'}"
(click)="activatePreview()">
Aperçu
</a>
</div>
</div>
<div class="card-body">
<div *ngIf="activatedTab === 'Édition'">
<div class="md-form">
<input mdbActive
id="title"
name="title"
type="text"
class="form-control"
[(ngModel)]="model.title"
#title="ngModel"
data-error="Veuillez saisir un titre d'article"
data-sucess=""
required />
<label for="title">Titre de l'article</label>
</div>
<div class="md-form">
<input mdbActive
id="image"
name="image"
type="text"
class="form-control"
[(ngModel)]="model.image"
#image="ngModel"
data-error="Veuillez saisir une adresse URL ou uploader une image"
data-success=""
required />
<label for="image">Image de l'article</label>
</div>
<div class="md-form">
<input mdbActive
id="description"
name="description"
type="text"
class="form-control"
[(ngModel)]="model.description"
#description="ngModel"
data-error="Veuillez saisir la description de l'article"
data-success=""
required />
<label for="description">Description de l'article</label>
</div>
<div class="input-group mb-3 wrap">
<div class="select">
<select id="category" class="select-text" [(ngModel)]="model.category" required>
<option value="" disabled selected></option>
<option *ngFor="let category of listCategories" [ngValue]="category">{{category.name}}</option>
</select>
<span class="select-highlight"></span>
<span class="select-bar"></span>
<label class="select-label">Catégorie de l'article</label>
</div>
</div>
<div id="toolbox" class="row">
<button type="button"
class="btn btn-floating waves-light"
(click)="injectHeader('h1')"
mdbTooltip="Titre 1"
placement="bottom"
mdbRippleRadius>H1</button>
<button type="button"
class="btn btn-floating waves-light"
(click)="injectHeader('h2')"
mdbTooltip="Titre 2"
placement="bottom"
mdbRippleRadius>H2</button>
<button type="button"
class="btn btn-floating waves-light"
(click)="injectHeader('h3')"
mdbTooltip="Titre 3"
placement="bottom"
mdbRippleRadius>H3</button>
<button type="button"
class="btn btn-floating waves-light"
(click)="openImagesModal()"
mdbTooltip="Image"
placement="bottom"
mdbRippleRadius>
<i class="fa fa-image"></i>
</button>
<button type="button"
class="btn btn-floating waves-light"
(click)="injectLink()"
mdbTooltip="Lien"
placement="bottom"
mdbRippleRadius>
<i class="fa fa-link"></i>
</button>
<button type="button"
class="btn btn-floating waves-light"
(click)="frameCode.show()"
mdbTooltip="Extrait de code"
placement="bottom"
mdbRippleRadius>
<i class="fa fa-code"></i>
</button>
</div>
<div class="md-form">
<textarea mdbActive
id="text"
name="text"
type="text"
class="md-textarea"
[(ngModel)]="model.text"
#text="ngModel"
data-error="Veuillez saisir le contenu de l'article"
data-sucess=""
required>
</textarea>
<label for="text">Contenu de l'article</label>
</div>
<div id="errorMsg" class="card red lighten-2 text-center z-depth-2">
<div class="card-body">
<p class="white-text mb-0">{{modelError}}</p>
</div>
</div>
<div id="resultMsg" class="card green lighten-2 text-center z-depth-2" >
<div class="card-body">
<p class="white-text mb-0">{{result}}</p>
</div>
</div>
</div>
<div *ngIf="activatedTab === 'Aperçu'">
<app-spinner *ngIf="!parsedPost"></app-spinner>
<div class="card" *ngIf="parsedPost">
<img [src]="parsedPost.image" class="img-fluid" alt="Post image">
<div class="card-body">
<h1 class="card-title">{{parsedPost.title}}</h1>
<h4>{{parsedPost.description}}</h4>
<hr/>
<div [innerHTML]="getContent()"></div>
</div>
</div>
</div>
<div id="footer">
<a routerLink="/myPosts">Annuler</a>
<button type="button"
class="btn btn-primary waves-light float-right"
(click)="save()" mdbRippleRadius>Enregistrer</button>
</div>
</div>
</div>
<div mdbModal #frameCode="mdb-modal" class="modal fade top"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-full-height modal-top" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title w-100" id="myModalLabel">Ajout de code</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="frameCode.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="wrap">
<div class="select">
<select id="languageTmp" class="select-text" [(ngModel)]="languageTmp" required>
<option value="" disabled selected></option>
<option value="java">Java</option>
<option value="python">Python</option>
<option value="markup">html/xml</option>
<option value="sql">SQL</option>
<option value="bash">Bash</option>
</select>
<span class="select-highlight"></span>
<span class="select-bar"></span>
<label class="select-label">Langage de programmation</label>
</div>
</div>
<div class="md-form" style="margin-top: 15px; margin-bottom: 0;">
<textarea mdbActive
id="codeTmp"
name="codeTmp"
type="text"
class="md-textarea"
[(ngModel)]="codeTmp"
required>
</textarea>
<label for="codeTmp">Extrait de code</label>
</div>
<div class="card red lighten-1 text-center z-depth-2" [hidden]="!codeError" style="margin-bottom: 0;">
<div class="card-body">
<p class="white-text mb-0">Le langage et l'extrait de code doivent être renseignés.</p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-primary waves-effect waves-light"
data-dismiss="modal" (click)="frameCode.hide()">Fermer</button>
<button type="button" class="btn btn-primary waves-effect waves-light"
(click)="injectCode()">Enregistrer</button>
</div>
</div>
</div>
</div>
<div mdbModal #frameImages="mdb-modal" class="modal fade top"
tabindex="-1" role="dialog" aria-labelledby="frameImagesLabel" aria-hidden="true">
<div class="modal-dialog modal-full-height modal-top" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title w-100" id="frameImagesLabel">Ajout d'image</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="frameCode.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<app-spinner *ngIf="!imagesLoaded"></app-spinner>
<div id="image-div" *ngIf="imagesLoaded">
<img *ngFor="let img of listImages"
[src]="getLinkSrc(img.link)"
class="uploaded-image hoverable"
(click)="injectImage(img.link)" />
</div>
<a class="fixed-action-btn green white-text" *ngIf="imagesLoaded" (click)="openNewImageInput()">+</a>
<input id="newImageInput" type="file" (change)="uploadImage($event)" [hidden]="true">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-primary waves-effect waves-light"
data-dismiss="modal" (click)="frameImages.hide()">Fermer</button>
<button type="button" class="btn btn-primary waves-effect waves-light"
(click)="injectCode()">Enregistrer</button>
</div>
</div>
</div>
</div>
@@ -1,237 +0,0 @@
.card {
margin-bottom: 50px;
}
.card-header {
padding-top: 24px;
padding-left: 24px;
padding-right: 24px;
padding-bottom: 0px;
border-width: 0px;
}
.tabs {
width: 50%;
text-align: center;
line-height: 62px;
}
.tabs.active {
border-bottom: 4px solid white;
}
textarea {
height: 250px;
overflow-y: scroll;
}
.custom-select {
border: 0px;
border-bottom: 1px #aaa solid;
border-radius: 0;
padding-left: 0;
margin-bottom: 20px;
}
.custom-select:focus {
-webkit-box-shadow: 0;
box-shadow: 0;
}
.md-form {
margin-bottom: 35px;
}
#footer {
line-height: 57px;
padding-left: 15px;
}
#toolbox {
margin-left: 5px;
margin-bottom: 15px;
}
.btn-floating {
border-radius: 50%;
padding: 0;
margin: 2px;
width: 40px;
height: 40px;
background-color: #3f51b5;
text-align: center;
box-shadow: 0 5px 11px 0 rgba(0,0,0,.18), 0 4px 15px 0 rgba(0,0,0,.15);
transition: box-shadow 0.3s ease-in-out;
}
.btn-floating:hover {
box-shadow: 0 8px 17px 0 rgba(0,0,0,.2), 0 6px 20px 0 rgba(0,0,0,.19);
}
#text {
padding: 0;
}
#resultMsg, #errorMsg {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
margin: 0;
}
.wrap {
top: 40%;
width: 100%;
margin: 0 auto;
}
/* select starting stylings ------------------------------*/
.select {
position: relative;
width: 100%;
}
.select-text {
position: relative;
font-family: inherit;
background-color: transparent;
width: 100%;
padding: 10px 10px 10px 0;
font-size: 18px;
border-radius: 0;
border: none;
border-bottom: 1px solid #bdbdbd;
}
/* Remove focus */
.select-text:focus {
outline: none;
border-bottom: 1px solid rgba(0,0,0, 0);
}
/* Use custom arrow */
.select .select-text {
appearance: none;
-webkit-appearance:none
}
.select:after {
position: absolute;
top: 18px;
right: 10px;
/* Styling the down arrow */
width: 0;
height: 0;
padding: 0;
content: '';
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #bdbdbd;
pointer-events: none;
}
/* LABEL ======================================= */
.select-label {
color: #757575;
font-size: 1rem;
font-weight: normal;
position: absolute;
pointer-events: none;
left: 0;
top: -5px;
transition: 0.2s ease all;
}
/* active state */
.select-text:focus ~ .select-label {
color: #2F80ED;
}
.select-text:focus ~ .select-label, .select-text:valid ~ .select-label {
top: -20px;
transition: 0.2s ease all;
font-size: 14px;
}
/* BOTTOM BARS ================================= */
.select-bar {
position: relative;
display: block;
width: 100%;
}
.select-bar:before, .select-bar:after {
content: '';
height: 2px;
width: 0;
bottom: 1px;
position: absolute;
background: #2F80ED;
transition: 0.2s ease all;
}
.select-bar:before {
left: 50%;
}
.select-bar:after {
right: 50%;
}
/* active state */
.select-text:focus ~ .select-bar:before, .select-text:focus ~ .select-bar:after {
width: 50%;
}
/* HIGHLIGHTER ================================== */
.select-highlight {
position: absolute;
height: 60%;
width: 40%;
top: 25%;
left: 0;
pointer-events: none;
opacity: 0.5;
}
$btnSize: 45px;
.fixed-action-btn {
display: block;
position: absolute;
bottom: 10px;
right: 40px;
z-index: 997;
width: $btnSize;
height: $btnSize;
border-radius: 50%;
line-height: $btnSize;
text-align: center;
font-size: 25px;
box-shadow: 0 5px 11px 0 rgba(0,0,0,.18), 0 4px 15px 0 rgba(0,0,0,.15);
transition: box-shadow 0.3s ease-in-out;
}
.fixed-action-btn:hover {
box-shadow: 0 8px 17px 0 rgba(0,0,0,.2), 0 6px 20px 0 rgba(0,0,0,.19);
}
#image-div {
height: 60vh;
overflow-y: scroll;
}
.uploaded-image {
display: inline-flex;
position: relative;
width: 300px;
height: 300px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2);
cursor:pointer;
margin-right: 15px;
margin-bottom: 15px;
}
@@ -1,232 +0,0 @@
import { Component, OnInit, SecurityContext, ViewChild } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Router, ActivatedRoute, RoutesRecognized } from '@angular/router';
import { Post, Category, Image } from '../../core/entities';
import { AuthService } from '../../core/services/auth.service';
import { CreateUpdatePostService } from './create-update-post.service';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/pairwise';
import { environment } from '../../../environments/environment';
import { HttpEventType, HttpResponse } from '@angular/common/http';
enum Tabs {
EDITION = 'Édition',
PREVIEW = 'Aperçu'
}
declare let Prism: any;
@Component({
selector: 'app-create-update-post',
templateUrl: './create-update-post.component.html',
styleUrls: ['./create-update-post.component.scss']
})
export class CreateUpdatePostComponent implements OnInit {
static INPUT_POST_TEXT = 'text';
@ViewChild('frameCode') public contentModal;
@ViewChild('frameImages') public imagesModal;
model: Post = new Post('', '', '', '', '', null, null, null);
parsedPost: Post;
listCategories: Array<Category>;
activatedTab: string;
modelError: string;
result: string;
// Variables for the code popup
codeTmp: string;
languageTmp: string;
codeError: string;
// Variables for the images popup
imagesLoaded: boolean;
listImages: Array<Image>;
selectedFiles: FileList;
currentFileUpload: File;
progress: { percentage: number } = { percentage: 0 };
constructor(
private createUpdatePostService: CreateUpdatePostService,
private activatedRoute: ActivatedRoute,
private sanitizer: DomSanitizer,
private router: Router,
private authService: AuthService
) {
this.imagesLoaded = false;
}
ngOnInit(): void {
this.listCategories = [];
this.activatedTab = Tabs.EDITION;
this.createUpdatePostService.getCategories().subscribe(listCategories => {
this.listCategories = listCategories.filter(category => !category.listSubCategories.length);
});
const postKey = this.activatedRoute.snapshot.paramMap.get('postKey');
if (postKey) {
this.createUpdatePostService.getPost(postKey).subscribe(post => {
if (post.author.key === this.authService.getUser().key) {
this.model = post;
} else {
this.router.navigate(['/forbidden']);
}
});
this.router.events.filter(e => e instanceof RoutesRecognized).pairwise().subscribe((event: any[]) => {
if (event[0].urlAfterRedirects === '/posts/new') {
this.result = 'Article créé.';
setTimeout(() => {
this.result = undefined;
}, 3500);
}
});
}
}
activateEdition(): void {
this.activatedTab = Tabs.EDITION;
}
activatePreview(): void {
this.activatedTab = Tabs.PREVIEW;
this.parsedPost = undefined;
this.createUpdatePostService.processPreview(this.model).subscribe(parsedPost => {
this.parsedPost = parsedPost;
setTimeout(() => {
Prism.highlightAll();
}, 100);
});
}
getContent(): string {
return this.sanitizer.sanitize(SecurityContext.HTML, this.parsedPost.text);
}
injectHeader(header: string): void {
this.injectElement('[' + header + '][/' + header + ']', 4);
}
injectLink(): void {
this.injectElement('[link href="" txt="" /]', 11);
}
injectCode(): void {
if (this.languageTmp && this.codeTmp) {
const codeExtract = '\n[code lg="' + this.languageTmp + '"]\n'
+ this.codeTmp + '\n[/code]\n\n';
this.injectElement(codeExtract, codeExtract.length);
this.contentModal.hide();
this.codeTmp = undefined;
this.languageTmp = undefined;
this.resetSelect('languageTmp');
} else {
this.codeError = 'Le langage et l\'extrait de code doivent être renseignés.';
setTimeout(() => {
this.codeError = undefined;
}, 3500);
}
}
private injectElement(elementToInject: string, lengthForCursor: number): void {
const input = <HTMLInputElement>document.getElementById(CreateUpdatePostComponent.INPUT_POST_TEXT);
const contentValue = input.value;
const cursorPosition = input.selectionStart;
this.model.text = contentValue.slice(0, cursorPosition) + elementToInject + contentValue.slice(cursorPosition);
input.focus();
const newCursor = cursorPosition + lengthForCursor;
input.selectionStart = newCursor;
input.selectionEnd = newCursor;
}
private resetSelect(selectId: string): void {
const select = <HTMLSelectElement>document.getElementById(selectId);
select.selectedIndex = 0;
}
save(): void {
if (this.model.title && this.model.image && this.model.description && this.model.category && this.model.text) {
this.model.author = this.authService.getUser();
if (this.model.key) {
this.createUpdatePostService.updatePost(this.model).subscribe(post => {
this.setMessage('Modification enregistrée', false);
});
} else {
this.createUpdatePostService.addPost(this.model).subscribe(post => {
this.router.navigate([`/posts/update/${post.key}`]);
});
}
} else {
this.setMessage('Veuillez saisir les champs obligatoires.', true);
}
}
setMessage(message: string, error: boolean): void {
this[error ? 'modelError' : 'result'] = message;
const resultMsgDiv = document.getElementById(error ? 'errorMsg' : 'resultMsg');
resultMsgDiv.style.maxHeight = '64px';
setTimeout(() => {
resultMsgDiv.style.maxHeight = '0px';
setTimeout(() => {
this[error ? 'modelError' : 'result'] = undefined;
}, 550);
}, 3000);
}
openImagesModal(): void {
this.imagesLoaded = false;
this.imagesModal.show();
this.createUpdatePostService.getImages().subscribe(listImages => {
this.listImages = listImages;
this.imagesLoaded = true;
});
}
getLinkSrc(pLink: string): string {
return `${environment.apiUrl}/api/images/${pLink}`;
}
openNewImageInput(): void {
document.getElementById('newImageInput').click();
}
uploadImage(event): void {
this.selectedFiles = event.target.files;
this.progress.percentage = 0;
this.currentFileUpload = this.selectedFiles.item(0);
// This prevents error 400 if user doesn't select any file to upload and close the input file.
if (this.currentFileUpload) {
this.createUpdatePostService.uploadPicture(this.currentFileUpload).subscribe(result => {
if (result.type === HttpEventType.UploadProgress) {
this.progress.percentage = Math.round(100 * result.loaded / result.total);
} else if (result instanceof HttpResponse) {
console.log('File ' + result.body + ' completely uploaded!');
this.createUpdatePostService.getImageDetails(result.body as string).subscribe(image => {
this.listImages.push(image);
});
}
this.selectedFiles = undefined;
});
}
}
injectImage(pImageLink: string): void {
const imgTag = `[img src="${this.getLinkSrc(pImageLink)}" /]`;
this.injectElement(imgTag, imgTag.length);
this.imagesModal.hide();
}
}
@@ -1,57 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http';
import { Post, Category, Image } from '../../core/entities';
import { environment } from '../../../environments/environment';
const IMAGES_URL = environment.apiUrl + '/api/images';
const POSTS_URL = environment.apiUrl + '/api/posts';
const CATEGORIES_URL = environment.apiUrl + '/api/categories';
@Injectable()
export class CreateUpdatePostService {
constructor(private http: HttpClient) {}
processPreview(post: Post): Observable<Post> {
return this.http.post<Post>(`${POSTS_URL}/preview`, post);
}
getCategories(): Observable<Array<Category>> {
return this.http.get<Array<Category>>(`${CATEGORIES_URL}/`);
}
addPost(post: Post): Observable<Post> {
return this.http.post<Post>(`${POSTS_URL}/`, post);
}
updatePost(post: Post): Observable<Post> {
return this.http.put<Post>(`${POSTS_URL}/`, post);
}
getPost(postKey: string): Observable<Post> {
return this.http.get<Post>(`${POSTS_URL}/${postKey}/source`);
}
getImages(): Observable<Array<Image>> {
return this.http.get<Array<Image>>(`${IMAGES_URL}/myImages`);
}
uploadPicture(file: File): Observable<HttpEvent<{}>> {
const formData: FormData = new FormData();
formData.append('file', file);
return this.http.request(new HttpRequest(
'POST', IMAGES_URL, formData, {
reportProgress: true,
responseType: 'text'
}
));
}
getImageDetails(imageLink: string): Observable<Image> {
return this.http.get<Image>(`${IMAGES_URL}/${imageLink}/details`);
}
}
@@ -1,8 +0,0 @@
<div>
<h1>Mes articles</h1>
<app-spinner *ngIf="!listPosts"></app-spinner>
<div *ngIf="listPosts" class="col-lg-8 offset-lg-2">
<app-post-card *ngFor="let post of listPosts" [post]="post"></app-post-card>
</div>
<a routerLink="/posts/new" class="fixed-action-btn green white-text">+</a>
</div>
@@ -1,20 +0,0 @@
$btnSize: 55px;
.fixed-action-btn {
display: block;
position: fixed;
bottom: 23px;
right: 23px;
z-index: 997;
width: $btnSize;
height: $btnSize;
border-radius: 50%;
line-height: $btnSize;
text-align: center;
font-size: 30px;
box-shadow: 0 5px 11px 0 rgba(0,0,0,.18), 0 4px 15px 0 rgba(0,0,0,.15);
transition: box-shadow 0.3s ease-in-out;
}
.fixed-action-btn:hover {
box-shadow: 0 8px 17px 0 rgba(0,0,0,.2), 0 6px 20px 0 rgba(0,0,0,.19);
}
@@ -1,23 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { Post } from '../../core/entities';
import { MyPostsService } from './my-posts.service';
@Component({
selector: 'app-my-posts',
templateUrl: './my-posts.component.html',
styleUrls: ['./my-posts.component.scss']
})
export class MyPostsComponent implements OnInit {
listPosts: Array<Post>;
constructor(
private myPostsService: MyPostsService
) {}
ngOnInit(): void {
this.myPostsService.getMyPosts().subscribe(listPosts => {
this.listPosts = listPosts;
});
}
}
@@ -1,18 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../environments/environment';
import { Post } from '../../core/entities';
const POSTS_URL = environment.apiUrl + '/api/posts';
@Injectable()
export class MyPostsService {
constructor(private http: HttpClient) {}
getMyPosts(): Observable<Array<Post>> {
return this.http.get<Array<Post>>(`${POSTS_URL}/myPosts`);
}
}
@@ -1,67 +0,0 @@
<div id="content" *ngIf="!notFound">
<app-spinner *ngIf="!loaded"></app-spinner>
<div class="card" *ngIf="loaded">
<img [src]="post?.image" class="img-fluid" alt="Post image">
<a *ngIf="owned" class="btn-card-floating waves-light white-text"
routerLink="/posts/update/{{post.key}}">
<i class="fa fa-pencil"></i>
</a>
<div class="card-body">
<h1 class="card-title">{{post.title}}</h1>
<h4>{{post.description}}</h4>
<hr/>
<div [innerHTML]="getContent()"></div>
</div>
<div class="card-data">
<img [src]="getAvatarUrl()"
class="author-img"
[alt]="post.author.name"
[mdbTooltip]="post.author.name"
placement="bottom"/>
Article écrit par {{post.author.name}}
<span class="creation-date-area">({{post.creationDate | date:'yyyy-MM-dd HH:mm:ss'}})</span>
<button *ngIf="owned" type="button" class="btn btn-danger waves-light float-right" (click)="alertDelete.show()" mdbRippleRadius>
<i class="fa fa-trash mr-1"></i> Supprimer
</button>
</div>
</div>
<div mdbModal #alertDelete="mdb-modal" class="modal fade" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-notify modal-danger" role="document">
<div class="modal-content">
<div class="modal-header">
<p class="heading lead">Suppression de l'article</p>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="alertDelete.hide()">
<span aria-hidden="true" class="white-text">×</span>
</button>
</div>
<div class="modal-body">
<div class="text-center">
<p>Êtes vous sûr de vouloir supprimer cet article ?</p>
<p *ngIf="postDeletionFailed" class="red-text">
Une erreur est survenue lors de la suppression de l'article.
</p>
</div>
</div>
<div class="modal-footer">
<a type="button"
class="btn btn-outline-secondary-modal"
data-dismiss="modal"
(click)="alertDelete.hide()"
mdbRippleRadius>
Annuler
</a>
<a type="button" mdbRippleRadius
class="btn btn-primary-modal waves-light"
(click)="deletePost()">
<i class="fa fa-trash"></i> Supprimer
</a>
</div>
</div>
</div>
</div>
</div>
<app-not-found *ngIf="notFound"></app-not-found>
@@ -1,107 +0,0 @@
import { Component, OnInit, SecurityContext, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Post, User } from '../core/entities';
import { PostService } from './post.service';
import { AuthService } from '../core/services/auth.service';
import { environment } from '../../environments/environment';
declare let Prism: any;
@Component({
selector: 'app-post',
templateUrl: './post.component.html',
styles: [`
.author-img {
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 15px;
}
.card .card-data {
padding: 15px;
background-color: #f5f5f5;
}
#content {
margin-bottom: 50px;
}
.creation-date-area {
color: #bdbdbd;
font-style: italic;
}
`]
})
export class PostComponent implements OnInit {
post: Post = new Post('', '', '', '', '', null, new User('', '', '', '', '', null, null, ''), null);
loaded: boolean;
notFound: boolean;
owned: boolean;
@ViewChild('alertDelete') alertDelete;
postDeletionFailed: boolean;
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private postService: PostService,
private sanitizer: DomSanitizer,
private authService: AuthService
) {
this.loaded = false;
this.owned = false;
this.postDeletionFailed = false;
}
ngOnInit(): void {
this.postService.getPost(this.activatedRoute.snapshot.paramMap.get('postKey')).subscribe(post => {
this.post = post;
this.loaded = true;
this.owned = this.isOwned();
setTimeout(() => {
Prism.highlightAll();
}, 100);
}, error => {
if (error instanceof HttpErrorResponse && error.status === 404) {
this.notFound = true;
}
});
}
private isOwned(): boolean {
let result = false;
const connectedUser = this.authService.getUser();
if (connectedUser) {
result = this.post.author.key === connectedUser.key;
}
return result;
}
getContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.post.text);
}
getAvatarUrl(): string {
return this.post.author.image
? `${environment.apiUrl}/api/images/loadAvatar/${this.post.author.image}`
: './assets/images/default_user.png';
}
deletePost(): void {
this.postDeletionFailed = false;
this.postService.deletePost(this.post).subscribe(() => {
this.alertDelete.hide();
this.router.navigate(['/myPosts']);
}, error => {
this.postDeletionFailed = true;
setTimeout(() => {
this.postDeletionFailed = false;
}, 3500);
});
}
}
@@ -1,22 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
import { Post } from '../core/entities';
const POSTS_URL = environment.apiUrl + '/api/posts';
@Injectable()
export class PostService {
constructor(private http: HttpClient) {}
getPost(postKey: string): Observable<Post> {
return this.http.get<Post>(`${POSTS_URL}/${postKey}`);
}
deletePost(postToDelete: Post): Observable<any> {
return this.http.delete(`${POSTS_URL}/${postToDelete.key}`);
}
}
@@ -1,36 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { Post } from '../core/entities';
import { SearchService } from './search.service';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-search',
template: `
<div>
<h1>Résultats de la recherche</h1>
<app-spinner *ngIf="!listArticle"></app-spinner>
<div *ngIf="listArticle" class="col-lg-8 offset-lg-2">
<app-post-card *ngFor="let post of listArticle" [post]="post"></app-post-card>
</div>
</div>
`
})
export class SearchComponent implements OnInit {
searchLoading: boolean;
listArticle: Array<Post>;
constructor(
private activatedRoute: ActivatedRoute,
private searchService: SearchService
) {
this.searchLoading = true;
}
ngOnInit(): void {
this.searchService.search(this.activatedRoute.snapshot.paramMap.get('searchCriteria'))
.subscribe(listArticle => {
this.listArticle = listArticle;
this.searchLoading = false;
});
}
}
@@ -1,18 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { environment } from '../../environments/environment';
import { Post } from '../core/entities';
const POSTS_URL = environment.apiUrl + '/api/posts';
@Injectable()
export class SearchService {
constructor(private http: HttpClient) {}
search(searchCriteria: string): Observable<Array<Post>> {
return this.http.get<Array<Post>>(`${POSTS_URL}/search/${searchCriteria}`);
}
}
@@ -1,76 +0,0 @@
<div class="card col-md-8 offset-md-2 col-lg-6 offset-lg-3">
<div id="form" class="card-body">
<h4 class="card-title">Inscrition</h4>
<form (ngSubmit)="onSubmit()" #signinForm="ngForm">
<div class="md-form">
<i class="fa fa-id-badge prefix grey-text"></i>
<input mdbActive
id="name"
name="name"
type="text"
class="form-control"
[(ngModel)]="model.name"
#name="ngModel"
data-error="Veuillez saisir un nom d'utilisateur"
data-sucess=""
required />
<label for="name">Nom d'utilisateur</label>
</div>
<div class="md-form">
<i class="fa fa-envelope prefix grey-text"></i>
<input mdbActive
id="email"
name="email"
type="email"
class="form-control"
[(ngModel)]="model.email"
#email="ngModel"
data-error="Veuillez saisir une adresse email valide"
data-sucess=""
required />
<label for="email">Email</label>
</div>
<div class="md-form">
<i class="fa fa-lock prefix grey-text"></i>
<input mdbActive
id="password"
name="password"
type="password"
class="form-control"
[(ngModel)]="model.password"
#password="ngModel"
data-error="Veuillez saisir votre mot de passe"
data-sucess=""
required />
<label for="password">Password</label>
</div>
<div class="md-form">
<i class="fa fa-lock prefix grey-text"></i>
<input mdbActive
id="confirmPassword"
name="confirmPassword"
type="password"
class="form-control"
[(ngModel)]="confirmPassword"
data-error="Veuillez confirmer votre mot de passe"
data-sucess=""
required />
<label for="confirmPassword">Confirmez votre mot de passe</label>
</div>
<div id="errorMsg" class="card red lighten-2 text-center z-depth-2">
<div class="card-body">
<p class="white-text mb-0">{{errorMsg}}</p>
</div>
</div>
<div class="col submitFormArea">
<a routerLink="/login" class="indigo-text">
Connexion
</a>
<button class="float-right waves-effect waves-light indigo btn"
type="submit" [disabled]="!signinForm.form.valid">
Suivant
</button>
</div>
</form>
</div>
</div>
@@ -1,68 +0,0 @@
import { Component } from '@angular/core';
import { User } from '../core/entities';
import { SigninService } from './signin.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-signin',
templateUrl: './signin.component.html',
styles: [`
#form {
padding-bottom: 10px;
}
.submitFormArea {
line-height: 50px;
}
#errorMsg {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
margin: 0;
}
`]
})
export class SigninComponent {
model: User = new User('', '', '', '', '', null, null, '');
confirmPassword: string;
errorMsg: string;
constructor(
private signinService: SigninService,
private router: Router
) {}
onSubmit(): void {
if (this.confirmPassword && this.confirmPassword === this.model.password) {
this.signinService.signin(this.model).subscribe(user => {
this.router.navigate(['/login']);
}, error => {
switch (error.status) {
case 409:
this.setMessage('L\'adresse mail saisie n\'est pas disponible');
break;
default:
this.setMessage('Une erreur est survenue lors de l\'inscription, veuillez réessayer plus tard');
break;
}
});
} else {
this.setMessage('Les mots de passe saisis ne correspondent pas');
}
}
setMessage(message: string): void {
this.errorMsg = message;
const resultMsgDiv = document.getElementById('errorMsg');
resultMsgDiv.style.maxHeight = '64px';
setTimeout(() => {
resultMsgDiv.style.maxHeight = '0px';
setTimeout(() => {
this.errorMsg = undefined;
}, 550);
}, 3000);
}
}
@@ -1,18 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { User } from '../core/entities';
import { environment } from '../../environments/environment';
const SIGNIN_URL = environment.apiUrl + '/api/account/signin';
@Injectable()
export class SigninService {
constructor(private http: HttpClient) {}
signin(user: User): Observable<User> {
return this.http.post<User>(SIGNIN_URL, user);
}
}
@@ -1,34 +0,0 @@
<div class="row">
<div class="col-md-3 col-lg-2">
<h1>Versions</h1>
<ul class="list-group">
<a *ngFor="let version of versionsList">
<li [className]="version.active ? 'list-group-item active' : 'list-group-item'"
(click)="showVersionRevision(version)">
{{version.number}}
</li>
</a>
</ul>
</div>
<div id="versionRevisionsArea" class="col-md-9 col-lg-10">
<div *ngIf="versionRevisionsList.length">
<h3>Ajouts de fonctionnalités</h3>
<ul>
<li *ngFor="let versionRevision of versionRevisionsList">
{{versionRevision.text}}
</li>
</ul>
</div>
<h4 *ngIf="!versionRevisionsList.length">Aucune nouvelle fonctionnalité pour cette version.</h4>
<div *ngIf="versionRevisionsBugfixList.length">
<h3>Correction d'anomalies</h3>
<ul>
<li *ngFor="let versionRevision of versionRevisionsBugfixList">
{{versionRevision.text}}
</li>
</ul>
</div>
<h4 *ngIf="!versionRevisionsBugfixList.length">Aucune correction d'anomalie pour cette version.</h4>
</div>
</div>
@@ -1,51 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { VersionRevisionService } from './version-revisions.service';
import { VersionRevision, Version } from '../core/entities';
@Component({
selector: 'app-version-revisions',
templateUrl: 'version-revisions.component.html',
styles: [`
#versionRevisionsArea {
padding-top: 70px;
}
@media screen and (max-width: 767px) {
#versionRevisionsArea {
padding-top: 20px;
}
}
`]
})
export class VersionRevisionComponent implements OnInit {
versionsList: Array<Version>;
versionRevisionsList: Array<VersionRevision>;
versionRevisionsBugfixList: Array<VersionRevision>;
constructor(
private versionRevisionService: VersionRevisionService
) {
this.versionsList = [];
this.versionRevisionsList = [];
this.versionRevisionsBugfixList = [];
}
ngOnInit(): void {
this.versionRevisionService.getVersions().subscribe(versionsList => {
this.versionsList = versionsList;
this.showVersionRevision(this.versionsList[0]);
});
}
showVersionRevision(version: Version): void {
this.versionsList.forEach(versionTmp => versionTmp.active = false);
version.active = true;
this.versionRevisionService.findByVersionNumber(version.number).subscribe(versionRevisionsList => {
this.versionRevisionsList = versionRevisionsList.filter(vr => !vr.bugfix);
this.versionRevisionsBugfixList = versionRevisionsList.filter(vr => vr.bugfix);
});
}
}
@@ -1,23 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Version, VersionRevision } from '../core/entities';
import { Observable } from 'rxjs/Observable';
import { environment } from '../../environments/environment';
const VERSION_REVISIONS_URL = environment.apiUrl + '/api/versionrevisions';
@Injectable()
export class VersionRevisionService {
constructor(
private http: HttpClient
) {}
getVersions(): Observable<Array<Version>> {
return this.http.get<Array<Version>>(`${VERSION_REVISIONS_URL}/versions`);
}
findByVersionNumber(versionNumber: string): Observable<Array<VersionRevision>> {
return this.http.get<Array<VersionRevision>>(`${VERSION_REVISIONS_URL}/${versionNumber}`);
}
}
View File
Whitespace-only changes.
-271
View File
@@ -1,271 +0,0 @@
/* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+apacheconf+c+bash+batch+cpp+csharp+ruby+css-extras+django+docker+git+http+ini+java+json+latex+less+lua+makefile+markdown+nginx+php+php-extras+powershell+properties+python+jsx+rest+rust+sass+scss+scala+sql+typescript+vim+wiki+yaml&plugins=line-numbers+autolinker+file-highlight+toolbar+unescaped-markup+command-line+show-language+copy-to-clipboard */
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
background: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #272822;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a6e22e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre.line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
.token a {
color: inherit;
}
pre.code-toolbar {
position: relative;
}
pre.code-toolbar > .toolbar {
position: absolute;
top: .3em;
right: .2em;
transition: opacity 0.3s ease-in-out;
opacity: 0;
}
pre.code-toolbar:hover > .toolbar {
opacity: 1;
}
pre.code-toolbar > .toolbar .toolbar-item {
display: inline-block;
}
pre.code-toolbar > .toolbar a {
cursor: pointer;
}
pre.code-toolbar > .toolbar button {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none; /* for button */
-moz-user-select: none;
-ms-user-select: none;
}
pre.code-toolbar > .toolbar a,
pre.code-toolbar > .toolbar button,
pre.code-toolbar > .toolbar span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 2px 0 0 rgba(0,0,0,0.2);
border-radius: .5em;
}
pre.code-toolbar > .toolbar a:hover,
pre.code-toolbar > .toolbar a:focus,
pre.code-toolbar > .toolbar button:hover,
pre.code-toolbar > .toolbar button:focus,
pre.code-toolbar > .toolbar span:hover,
pre.code-toolbar > .toolbar span:focus {
color: inherit;
text-decoration: none;
}
/* Fallback, in case JS does not run, to ensure the code is at least visible */
.lang-markup script[type='text/plain'],
.language-markup script[type='text/plain'],
script[type='text/plain'].lang-markup,
script[type='text/plain'].language-markup {
display: block;
font: 100% Consolas, Monaco, monospace;
white-space: pre;
overflow: auto;
}
.command-line-prompt {
border-right: 1px solid #999;
display: block;
float: left;
font-size: 100%;
letter-spacing: -1px;
margin-right: 1em;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.command-line-prompt > span:before {
color: #999;
content: ' ';
display: block;
padding-right: 0.8em;
}
.command-line-prompt > span[data-user]:before {
content: "[" attr(data-user) "@" attr(data-host) "] $";
}
.command-line-prompt > span[data-user="root"]:before {
content: "[" attr(data-user) "@" attr(data-host) "] #";
}
.command-line-prompt > span[data-prompt]:before {
content: attr(data-prompt);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

-51
View File
@@ -1,51 +0,0 @@
/* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+apacheconf+c+bash+batch+cpp+csharp+ruby+css-extras+django+docker+git+http+ini+java+json+latex+less+lua+makefile+markdown+nginx+php+php-extras+powershell+properties+python+jsx+rest+rust+sass+scss+scala+sql+typescript+vim+wiki+yaml&plugins=line-numbers+autolinker+file-highlight+toolbar+unescaped-markup+command-line+show-language+copy-to-clipboard */
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=n.util.clone(e[r]));return a;case"Array":return e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var a=n.util.clone(n.languages[e]);for(var r in t)a[r]=t[r];return a},insertBefore:function(e,t,a,r){r=r||n.languages;var i=r[e];if(2==arguments.length){a=arguments[1];for(var l in a)a.hasOwnProperty(l)&&(i[l]=a[l]);return i}var o={};for(var s in i)if(i.hasOwnProperty(s)){if(s==t)for(var l in a)a.hasOwnProperty(l)&&(o[l]=a[l]);o[s]=i[s]}return n.languages.DFS(n.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,t,a,r){r=r||{};for(var i in e)e.hasOwnProperty(i)&&(t.call(e,i,e[i],a||i),"Object"!==n.util.type(e[i])||r[n.util.objId(e[i])]?"Array"!==n.util.type(e[i])||r[n.util.objId(e[i])]||(r[n.util.objId(e[i])]=!0,n.languages.DFS(e[i],t,i,r)):(r[n.util.objId(e[i])]=!0,n.languages.DFS(e[i],t,null,r)))}},plugins:{},highlightAll:function(e,t){var a={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var r,i=a.elements||document.querySelectorAll(a.selector),l=0;r=i[l++];)n.highlightElement(r,e===!0,a.callback)},highlightElement:function(t,a,r){for(var i,l,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(i=(o.className.match(e)||[,""])[1].toLowerCase(),l=n.languages[i]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+i,o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+i);var s=t.textContent,u={element:t,language:i,grammar:l,code:s};if(n.hooks.run("before-sanity-check",u),!u.code||!u.grammar)return u.code&&(n.hooks.run("before-highlight",u),u.element.textContent=u.code,n.hooks.run("after-highlight",u)),n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),a&&_self.Worker){var g=new Worker(n.filename);g.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,r){var i=n.tokenize(e,t);return a.stringify(n.util.encode(i),r)},matchGrammar:function(e,t,a,r,i,l,o){var s=n.Token;for(var u in a)if(a.hasOwnProperty(u)&&a[u]){if(u==o)return;var g=a[u];g="Array"===n.util.type(g)?g:[g];for(var c=0;c<g.length;++c){var h=g[c],f=h.inside,d=!!h.lookbehind,m=!!h.greedy,p=0,y=h.alias;if(m&&!h.pattern.global){var v=h.pattern.toString().match(/[imuy]*$/)[0];h.pattern=RegExp(h.pattern.source,v+"g")}h=h.pattern||h;for(var b=r,k=i;b<t.length;k+=t[b].length,++b){var w=t[b];if(t.length>e.length)return;if(!(w instanceof s)){h.lastIndex=0;var _=h.exec(w),P=1;if(!_&&m&&b!=t.length-1){if(h.lastIndex=k,_=h.exec(e),!_)break;for(var A=_.index+(d?_[1].length:0),j=_.index+_[0].length,x=b,O=k,S=t.length;S>x&&(j>O||!t[x].type&&!t[x-1].greedy);++x)O+=t[x].length,A>=O&&(++b,k=O);if(t[b]instanceof s||t[x-1].greedy)continue;P=x-b,w=e.slice(k,O),_.index-=k}if(_){d&&(p=_[1].length);var A=_.index+p,_=_[0].slice(p),j=A+_.length,N=w.slice(0,A),C=w.slice(j),E=[b,P];N&&(++b,k+=N.length,E.push(N));var I=new s(u,f?n.tokenize(_,f):_,y,_,m);if(E.push(I),C&&E.push(C),Array.prototype.splice.apply(t,E),1!=P&&n.matchGrammar(e,t,a,b,k,!0,u),l)break}else if(l)break}}}}},tokenize:function(e,t){var a=[e],r=t.rest;if(r){for(var i in r)t[i]=r[i];delete t.rest}return n.matchGrammar(e,a,t,0,0,!1),a},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.length=0|(a||"").length,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var i={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("commentLine truncated
Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:/<!DOCTYPE[\s\S]+?>/i,cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\s\S])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\s\S]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
Prism.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\s\S]*?>)[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\s\S]*?>)[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript;
Prism.languages.apacheconf={comment:/#.*/,"directive-inline":{pattern:/^(\s*)\b(AcceptFilter|AcceptPathInfo|AccessFileName|Action|AddAlt|AddAltByEncoding|AddAltByType|AddCharset|AddDefaultCharset|AddDescription|AddEncoding|AddHandler|AddIcon|AddIconByEncoding|AddIconByType|AddInputFilter|AddLanguage|AddModuleInfo|AddOutputFilter|AddOutputFilterByType|AddType|Alias|AliasMatch|Allow|AllowCONNECT|AllowEncodedSlashes|AllowMethods|AllowOverride|AllowOverrideList|Anonymous|Anonymous_LogEmail|Anonymous_MustGiveEmail|Anonymous_NoUserID|Anonymous_VerifyEmail|AsyncRequestWorkerFactor|AuthBasicAuthoritative|AuthBasicFake|AuthBasicProvider|AuthBasicUseDigestAlgorithm|AuthDBDUserPWQuery|AuthDBDUserRealmQuery|AuthDBMGroupFile|AuthDBMType|AuthDBMUserFile|AuthDigestAlgorithm|AuthDigestDomain|AuthDigestNonceLifetime|AuthDigestProvider|AuthDigestQop|AuthDigestShmemSize|AuthFormAuthoritative|AuthFormBody|AuthFormDisableNoStore|AuthFormFakeBasicAuth|AuthFormLocation|AuthFormLoginRequiredLocation|AuthFormLoginSuccessLocation|AuthFormLogoutLocation|AuthFormMethod|AuthFormMimetype|AuthFormPassword|AuthFormProvider|AuthFormSitePassphrase|AuthFormSize|AuthFormUsername|AuthGroupFile|AuthLDAPAuthorizePrefix|AuthLDAPBindAuthoritative|AuthLDAPBindDN|AuthLDAPBindPassword|AuthLDAPCharsetConfig|AuthLDAPCompareAsUser|AuthLDAPCompareDNOnServer|AuthLDAPDereferenceAliases|AuthLDAPGroupAttribute|AuthLDAPGroupAttributeIsDN|AuthLDAPInitialBindAsUser|AuthLDAPInitialBindPattern|AuthLDAPMaxSubGroupDepth|AuthLDAPRemoteUserAttribute|AuthLDAPRemoteUserIsDN|AuthLDAPSearchAsUser|AuthLDAPSubGroupAttribute|AuthLDAPSubGroupClass|AuthLDAPUrl|AuthMerging|AuthName|AuthnCacheContext|AuthnCacheEnable|AuthnCacheProvideFor|AuthnCacheSOCache|AuthnCacheTimeout|AuthnzFcgiCheckAuthnProvider|AuthnzFcgiDefineProvider|AuthType|AuthUserFile|AuthzDBDLoginToReferer|AuthzDBDQuery|AuthzDBDRedirectQuery|AuthzDBMType|AuthzSendForbiddenOnFailure|BalancerGrowth|BalancerInherit|BalancerMember|BalancerPersist|BrowserMatch|BrowserMatchNoCase|BufferedLogs|BufferSize|CacheDefaultExpire|CacheDetailHeader|CacheDirLength|CacheDirLevels|CacheDisable|CacheEnable|CacheFile|CacheHeader|CacheIgnoreCacheControl|CacheIgnoreHeaders|CacheIgnoreNoLastMod|CacheIgnoreQueryString|CacheIgnoreURLSessionIdentifiers|CacheKeyBaseURL|CacheLastModifiedFactor|CacheLock|CacheLockMaxAge|CacheLockPath|CacheMaxExpire|CacheMaxFileSize|CacheMinExpire|CacheMinFileSize|CacheNegotiatedDocs|CacheQuickHandler|CacheReadSize|CacheReadTime|CacheRoot|CacheSocache|CacheSocacheMaxSize|CacheSocacheMaxTime|CacheSocacheMinTime|CacheSocacheReadSize|CacheSocacheReadTime|CacheStaleOnError|CacheStoreExpired|CacheStoreNoStore|CacheStorePrivate|CGIDScriptTimeout|CGIMapExtension|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckCaseOnly|CheckSpelling|ChrootDir|ContentDigest|CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|Dav|DavDepthInfinity|DavGenericLockDB|DavLockDB|DavMinTimeout|DBDExptime|DBDInitSQL|DBDKeep|DBDMax|DBDMin|DBDParams|DBDPersist|DBDPrepareSQL|DBDriver|DefaultIcon|DefaultLanguage|DefaultRuntimeDir|DefaultType|Define|DeflateBufferSize|DeflateCompressionLevel|DeflateFilterNote|DeflateInflateLimitRequestBody|DeflateInflateRatioBurst|DeflateInflateRatioLimit|DeflateMemLevel|DeflateWindowSize|Deny|DirectoryCheckHandler|DirectoryIndex|DirectoryIndexRedirect|DirectorySlash|DocumentRoot|DTracePrivileges|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|Error|ErrorDocument|ErrorLog|ErrorLogFormat|Example|ExpiresActive|ExpiresByType|ExpiresDefault|ExtendedStatus|ExtFilterDefine|ExtFilterOptions|FallbackResource|FileETag|FilterChain|FilterDeclare|FilterProtocol|FilterProvider|FilterTrace|ForceLanguagePriority|ForceType|ForensicLog|GprofDir|GracefulShutdownTimeout|Group|Header|HeaderName|HeartbeatAddress|HeartbeatListen|HeartbeatMaxServers|HeartbeatStorage|HeartbeatStorage|HostnameLookups|IdentityCheck|IdentityCheckTimeout|ImapBase|ImapDefault|ImapMenu|Include|IncludeOptional|IndexHeadInsert|IndexIgnore|IndexIgnoreReset|IndexOptions|IndexOrderDefault|IndexStyleSheet|InputSed|ISAPIAppendLogToErrors|ISAPIAppendLogToQuery|ISAPICacheFile|ISAPIFakeAsync|ISAPILogNotSupported|ISAPIReadAheadBuffer|KeepAlive|KeepAliveTimeout|KeptBodySize|LanguagePriority|LDAPCacheEntries|LDAPCacheTTL|LDAPConnectionPoolTTL|LDAPConnectionTimeout|LDAPLibraryDebug|LDAPOpCacheEntries|LDAPOpCacheTTL|LDAPReferralHopLimit|LDAPReferrals|LDAPRetries|LDAPRetryDelay|LDAPSharedCacheFile|LDAPSharedCacheSize|LDAPTimeout|LDAPTrustedClientCert|LDAPTrustedGlobalCert|LDAPTrustedMode|LDAPVerifyServerCert|LimitInternalRecursion|LimitRequestBody|LimitRequestFields|LimitRequestFieldSize|LimitRequestLine|LimitXMLRequestBody|Listen|ListenBackLog|LoadFile|LoadModule|LogFormat|LogLevel|LogMessage|LuaAuthzProvider|LuaCodeCache|LuaHookAccessChecker|LuaHookAuthChecker|LuaHookCheckUserID|LuaHookFixups|LuaHookInsertFilter|LuaHookLog|LuaHookMapToStorage|LuaHookTranslateName|LuaHookTypeChecker|LuaInherit|LuaInputFilter|LLine truncated
Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"];
!function(e){var t={variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,lookbehind:!0,greedy:!0,inside:t},{pattern:/(["'])(?:\\\\|\\?[^\\])*?\1/g,greedy:!0,inside:t}],variable:t.variable,"function":{pattern:/(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,lookbehind:!0},keyword:{pattern:/(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,lookbehind:!0},"boolean":{pattern:/(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var a=t.variable[1].inside;a["function"]=e.languages.bash["function"],a.keyword=e.languages.bash.keyword,a.boolean=e.languages.bash.boolean,a.operator=e.languages.bash.operator,a.punctuation=e.languages.bash.punctuation}(Prism);
!function(e){var r=/%%?[~:\w]+%?|!\S+!/,t={pattern:/\/[a-z?]+(?=[ :]|$):?|-[a-z]\b|--[a-z-]+\b/im,alias:"attr-name",inside:{punctuation:/:/}},n=/"[^"]*"/,i=/(?:\b|-)\d+\b/;e.languages.batch={comment:[/^::.*/m,{pattern:/((?:^|[&(])[ \t]*)rem\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0}],label:{pattern:/^:.*/m,alias:"property"},command:[{pattern:/((?:^|[&(])[ \t]*)for(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* \S+ in \([^)]+\) do/im,lookbehind:!0,inside:{keyword:/^for\b|\b(?:in|do)\b/i,string:n,parameter:t,variable:r,number:i,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*)if(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* (?:not )?(?:cmdextversion \d+|defined \w+|errorlevel \d+|exist \S+|(?:"[^"]*"|\S+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:"[^"]*"|\S+))/im,lookbehind:!0,inside:{keyword:/^if\b|\b(?:not|cmdextversion|defined|errorlevel|exist)\b/i,string:n,parameter:t,variable:r,number:i,operator:/\^|==|\b(?:equ|neq|lss|leq|gtr|geq)\b/i}},{pattern:/((?:^|[&()])[ \t]*)else\b/im,lookbehind:!0,inside:{keyword:/^else\b/i}},{pattern:/((?:^|[&(])[ \t]*)set(?: ?\/[a-z](?:[ :](?:"[^"]*"|\S+))?)* (?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^set\b/i,string:n,parameter:t,variable:[r,/\w+(?=(?:[*\/%+\-&^|]|<<|>>)?=)/],number:i,operator:/[*\/%+\-&^|]=?|<<=?|>>=?|[!~_=]/,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*@?)\w+\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^\w+\b/i,string:n,parameter:t,label:{pattern:/(^\s*):\S+/m,lookbehind:!0,alias:"property"},variable:r,number:i,operator:/\^/}}],operator:/[&@]/,punctuation:/[()']/}}(Prism);
Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}});
Prism.languages.csharp=Prism.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[{pattern:/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,greedy:!0},{pattern:/("|')(\\?.)*?\1/,greedy:!0}],number:/\b-?(0x[\da-f]+|\d*\.?\d+f?)\b/i}),Prism.languages.insertBefore("csharp","keyword",{"generic-method":{pattern:/[a-z0-9_]+\s*<[^>\r\n]+?>\s*(?=\()/i,alias:"function",inside:{keyword:Prism.languages.csharp.keyword,punctuation:/[<>(),.:]/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});
!function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#(?!\{[^\r\n]*?\}).*/,/^=begin(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?=end/m],keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.util.clone(e.languages.ruby)}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,greedy:!0,inside:{interpolation:n}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,greedy:!0,inside:{interpolation:n}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,greedy:!0,inside:{interpolation:n}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,greedy:!0,inside:{interpolation:n}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,greedy:!0,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,greedy:!0,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,greedy:!0,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,greedy:!0,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,greedy:!0,inside:{interpolation:n}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,greedy:!0,inside:{interpolation:n}}]}(Prism);
Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,"class":/\.[-:\.\w]+/,id:/#[-:\.\w]+/,attribute:/\[[^\]]+\]/}},Prism.languages.insertBefore("css","function",{hexcode:/#[\da-f]{3,8}/i,entity:/\\[\da-f]{1,8}/i,number:/[\d%\.]+/});
var _django_template={property:{pattern:/(?:{{|{%)[\s\S]*?(?:%}|}})/g,greedy:!0,inside:{string:{pattern:/("|')(?:\\\\|\\?[^\\\r\n])*?\1/,greedy:!0},keyword:/\b(?:\||load|verbatim|widthratio|ssi|firstof|for|url|ifchanged|csrf_token|lorem|ifnotequal|autoescape|now|templatetag|debug|cycle|ifequal|regroup|comment|filter|endfilter|if|spaceless|with|extends|block|include|else|empty|endif|endfor|as|endblock|endautoescape|endverbatim|trans|endtrans|[Tt]rue|[Ff]alse|[Nn]one|in|is|static|macro|endmacro|call|endcall|set|endset|raw|endraw)\b/,operator:/[-+=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,"function":/\b(?:_|abs|add|addslashes|attr|batch|callable|capfirst|capitalize|center|count|cut|d|date|default|default_if_none|defined|dictsort|dictsortreversed|divisibleby|e|equalto|escape|escaped|escapejs|even|filesizeformat|first|float|floatformat|force_escape|forceescape|format|get_digit|groupby|indent|int|iriencode|iterable|join|last|length|length_is|linebreaks|linebreaksbr|linenumbers|list|ljust|lower|make_list|map|mapping|number|odd|phone2numeric|pluralize|pprint|random|reject|rejectattr|removetags|replace|reverse|rjust|round|safe|safeseq|sameas|select|selectattr|sequence|slice|slugify|sort|string|stringformat|striptags|sum|time|timesince|timeuntil|title|trim|truncate|truncatechars|truncatechars_html|truncatewords|truncatewords_html|undefined|unordered_list|upper|urlencode|urlize|urlizetrunc|wordcount|wordwrap|xmlattr|yesno)\b/,important:/\b-?\d+(?:\.\d+)?\b/,variable:/\b\w+?\b/,punctuation:/[[\];(),.:]/}}};Prism.languages.django=Prism.languages.extend("markup",{comment:/(?:<!--|{#)[\s\S]*?(?:#}|-->)/}),Prism.languages.django.tag.pattern=/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\s\S])*\1|[^>=]+))?)*\s*\/?>/i,Prism.languages.insertBefore("django","entity",_django_template),Prism.languages.insertBefore("inside","tag",_django_template,Prism.languages.django.tag),Prism.languages.javascript&&(Prism.languages.insertBefore("inside","string",_django_template,Prism.languages.django.script),Prism.languages.django.script.inside.string.inside=_django_template),Prism.languages.css&&(Prism.languages.insertBefore("inside","atrule",{tag:_django_template.property},Prism.languages.django.style),Prism.languages.django.style.inside.string.inside=_django_template),Prism.languages.jinja2=Prism.languages.django;
Prism.languages.docker={keyword:{pattern:/(^\s*)(?:ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|ONBUILD|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)(?=\s)/im,lookbehind:!0},string:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*?\1/,comment:/#.*/,punctuation:/---|\.\.\.|[:[\]{}\-,|>?]/},Prism.languages.dockerfile=Prism.languages.docker;
Prism.languages.git={comment:/^#.*/m,deleted:/^[-–].*/m,inserted:/^\+.*/m,string:/("|')(\\?.)*?\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s(--|-)\w+/m}},coord:/^@@.*@@$/m,commit_sha1:/^commit \w{40}$/m};
Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/m,inside:{property:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/,"attr-name":/:\w+/}},"response-status":{pattern:/^HTTP\/1.[01] \d+.*/m,inside:{property:{pattern:/(^HTTP\/1.[01] )\d+.*/i,lookbehind:!0}}},"header-name":{pattern:/^[\w-]+:(?=.)/m,alias:"keyword"}};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)(?:\\r?\\n|\\r){2}[\\w\\W]*","i"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}},Prism.languages.insertBefore("http","header-name",options)};
Prism.languages.ini={comment:/^[ \t]*;.*$/m,selector:/^[ \t]*\[.*?\]/m,constant:/^[ \t]*[^\s=]+?(?=[ \t]*=)/m,"attr-value":{pattern:/=.*/,inside:{punctuation:/^[=]/}}};
Prism.languages.java=Prism.languages.extend("clike",{keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+(?:e[+-]?\d+)?[df]?\b/i,operator:{pattern:/(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<<?=?|>>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,lookbehind:!0}}),Prism.languages.insertBefore("java","function",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0}});
Prism.languages.json={property:/"(?:\\.|[^\\"])*"(?=\s*:)/gi,string:/"(?!:)(?:\\.|[^\\"])*"(?!:)/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?)\b/g,punctuation:/[{}[\]);,]/g,operator:/:/g,"boolean":/\b(true|false)\b/gi,"null":/\bnull\b/gi},Prism.languages.jsonp=Prism.languages.json;
!function(a){var e=/\\([^a-z()[\]]|[a-z\*]+)/i,n={"equation-command":{pattern:e,alias:"regex"}};a.languages.latex={comment:/%.*/m,cdata:{pattern:/(\\begin\{((?:verbatim|lstlisting)\*?)\})([\s\S]*?)(?=\\end\{\2\})/,lookbehind:!0},equation:[{pattern:/\$(?:\\?[\s\S])*?\$|\\\((?:\\?[\s\S])*?\\\)|\\\[(?:\\?[\s\S])*?\\\]/,inside:n,alias:"string"},{pattern:/(\\begin\{((?:equation|math|eqnarray|align|multline|gather)\*?)\})([\s\S]*?)(?=\\end\{\2\})/,lookbehind:!0,inside:n,alias:"string"}],keyword:{pattern:/(\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,lookbehind:!0},url:{pattern:/(\\url\{)[^}]+(?=\})/,lookbehind:!0},headline:{pattern:/(\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\}(?:\[[^\]]+\])?)/,lookbehind:!0,alias:"class-name"},"function":{pattern:e,alias:"selector"},punctuation:/[[\]{}&]/}}(Prism);
Prism.languages.less=Prism.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-]+?(?:\([^{}]+\)|[^(){};])*?(?=\s*\{)/i,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\([^{}]*\)|[^{};@])*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/i,punctuation:/[{}();:,]/,operator:/[+\-*\/]/}),Prism.languages.insertBefore("less","punctuation",{"function":Prism.languages.less.function}),Prism.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-]+.*?(?=[(;])/,lookbehind:!0,alias:"function"}});
Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[\s\S]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+\.?[a-f\d]*(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|\.?\d*(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,"function":/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/};
Prism.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|.)*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},builtin:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,symbol:{pattern:/^[^:=\r\n]+(?=\s*:(?!=))/m,inside:{variable:/\$+(?:[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:[/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,{pattern:/(\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \t])/,lookbehind:!0}],operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/};
Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold);
Prism.languages.nginx=Prism.languages.extend("clike",{comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},keyword:/\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|server|events|location|include|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stubLine truncated
Prism.languages.php=Prism.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0}}),Prism.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),Prism.languages.insertBefore("php","keyword",{delimiter:{pattern:/\?>|<\?(?:php|=)?/i,alias:"important"},variable:/\$\w+\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),Prism.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),Prism.languages.markup&&(Prism.hooks.add("before-highlight",function(e){"php"===e.language&&/(?:<\?php|<\?)/gi.test(e.code)&&(e.tokenStack=[],e.backupCode=e.code,e.code=e.code.replace(/(?:<\?php|<\?)[\s\S]*?(?:\?>|$)/gi,function(a){for(var n=e.tokenStack.length;-1!==e.backupCode.indexOf("___PHP"+n+"___");)++n;return e.tokenStack[n]=a,"___PHP"+n+"___"}),e.grammar=Prism.languages.markup)}),Prism.hooks.add("before-insert",function(e){"php"===e.language&&e.backupCode&&(e.code=e.backupCode,delete e.backupCode)}),Prism.hooks.add("after-highlight",function(e){if("php"===e.language&&e.tokenStack){e.grammar=Prism.languages.php;for(var a=0,n=Object.keys(e.tokenStack);a<n.length;++a){var t=n[a],r=e.tokenStack[t];e.highlightedCode=e.highlightedCode.replace("___PHP"+t+"___",'<span class="token php language-php">'+Prism.highlight(r,e.grammar,"php").replace(/\$/g,"$$$$")+"</span>")}e.element.innerHTML=e.highlightedCode}}));
Prism.languages.insertBefore("php","variable",{"this":/\$this\b/,global:/\$(?:_(?:SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE)|GLOBALS|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/(static|self|parent)/,punctuation:/(::|\\)/}}});
Prism.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(`?[\s\S])*?"/,greedy:!0,inside:{"function":{pattern:/[^`]\$\(.*?\)/,inside:{}}}},{pattern:/'([^']|'')*'/,greedy:!0}],namespace:/\[[a-z][\s\S]*?\]/i,"boolean":/\$(true|false)\b/i,variable:/\$\w+\b/i,"function":[/\b(Add-(Computer|Content|History|Member|PSSnapin|Type)|Checkpoint-Computer|Clear-(Content|EventLog|History|Item|ItemProperty|Variable)|Compare-Object|Complete-Transaction|Connect-PSSession|ConvertFrom-(Csv|Json|StringData)|Convert-Path|ConvertTo-(Csv|Html|Json|Xml)|Copy-(Item|ItemProperty)|Debug-Process|Disable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)|Disconnect-PSSession|Enable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)|Enter-PSSession|Exit-PSSession|Export-(Alias|Clixml|Console|Csv|FormatData|ModuleMember|PSSession)|ForEach-Object|Format-(Custom|List|Table|Wide)|Get-(Alias|ChildItem|Command|ComputerRestorePoint|Content|ControlPanelItem|Culture|Date|Event|EventLog|EventSubscriber|FormatData|Help|History|Host|HotFix|Item|ItemProperty|Job|Location|Member|Module|Process|PSBreakpoint|PSCallStack|PSDrive|PSProvider|PSSession|PSSessionConfiguration|PSSnapin|Random|Service|TraceSource|Transaction|TypeData|UICulture|Unique|Variable|WmiObject)|Group-Object|Import-(Alias|Clixml|Csv|LocalizedData|Module|PSSession)|Invoke-(Command|Expression|History|Item|RestMethod|WebRequest|WmiMethod)|Join-Path|Limit-EventLog|Measure-(Command|Object)|Move-(Item|ItemProperty)|New-(Alias|Event|EventLog|Item|ItemProperty|Module|ModuleManifest|Object|PSDrive|PSSession|PSSessionConfigurationFile|PSSessionOption|PSTransportOption|Service|TimeSpan|Variable|WebServiceProxy)|Out-(Default|File|GridView|Host|Null|Printer|String)|Pop-Location|Push-Location|Read-Host|Receive-(Job|PSSession)|Register-(EngineEvent|ObjectEvent|PSSessionConfiguration|WmiEvent)|Remove-(Computer|Event|EventLog|Item|ItemProperty|Job|Module|PSBreakpoint|PSDrive|PSSession|PSSnapin|TypeData|Variable|WmiObject)|Rename-(Computer|Item|ItemProperty)|Reset-ComputerMachinePassword|Resolve-Path|Restart-(Computer|Service)|Restore-Computer|Resume-(Job|Service)|Save-Help|Select-(Object|String|Xml)|Send-MailMessage|Set-(Alias|Content|Date|Item|ItemProperty|Location|PSBreakpoint|PSDebug|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)|Show-(Command|ControlPanelItem|EventLog)|Sort-Object|Split-Path|Start-(Job|Process|Service|Sleep|Transaction)|Stop-(Computer|Job|Process|Service)|Suspend-(Job|Service)|Tee-Object|Test-(ComputerSecureChannel|Connection|ModuleManifest|Path|PSSessionConfigurationFile)|Trace-Command|Unblock-File|Undo-Transaction|Unregister-(Event|PSSessionConfiguration)|Update-(FormatData|Help|List|TypeData)|Use-Transaction|Wait-(Event|Job|Process)|Where-Object|Write-(Debug|Error|EventLog|Host|Output|Progress|Verbose|Warning))\b/i,/\b(ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(\W?)(!|-(eq|ne|gt|ge|lt|le|sh[lr]|not|b?(and|x?or)|(Not)?(Like|Match|Contains|In)|Replace|Join|is(Not)?|as)\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/},Prism.languages.powershell.string[0].inside.boolean=Prism.languages.powershell.boolean,Prism.languages.powershell.string[0].inside.variable=Prism.languages.powershell.variable,Prism.languages.powershell.string[0].inside.function.inside=Prism.util.clone(Prism.languages.powershell);
Prism.languages.properties={comment:/^[ \t]*[#!].*$/m,"attr-value":{pattern:/(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+?(?: *[=:] *| ))(?:\\(?:\r\n|[\s\S])|.)+/m,lookbehind:!0},"attr-name":/^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+?(?= *[ =:]| )/m,punctuation:/[=:]/};
Prism.languages.python={"triple-quoted-string":{pattern:/"""[\s\S]+?"""|'''[\s\S]+?'''/,alias:"string"},comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:{pattern:/("|')(?:\\\\|\\?[^\\\r\n])*?\1/,greedy:!0},"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/};
!function(a){var e=a.util.clone(a.languages.javascript);a.languages.jsx=a.languages.extend("markup",e),a.languages.jsx.tag.pattern=/<\/?[\w\.:-]+\s*(?:\s+(?:[\w\.:-]+(?:=(?:("|')(\\?[\s\S])*?\1|[^\s'">=]+|(\{[\s\S]*?\})))?|\{\.{3}\w+\}))*\s*\/?>/i,a.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:('|")[\s\S]*?(\1)|[^\s>]+)/i,a.languages.insertBefore("inside","attr-name",{spread:{pattern:/\{\.{3}\w+\}/,inside:{punctuation:/\{|\}|\./,"attr-value":/\w+/}}},a.languages.jsx.tag);var s=a.util.clone(a.languages.jsx);delete s.punctuation,s=a.languages.insertBefore("jsx","operator",{punctuation:/=(?={)|[{}[\];(),.:]/},{jsx:s}),a.languages.insertBefore("inside","attr-value",{script:{pattern:/=(\{(?:\{[^}]*\}|[^}])+\})/i,inside:s,alias:"language-javascript"}},a.languages.jsx.tag)}(Prism);
Prism.languages.rest={table:[{pattern:/(\s*)(?:\+[=-]+)+\+(?:\r?\n|\r)(?:\1(?:[+|].+)+[+|](?:\r?\n|\r))+\1(?:\+[=-]+)+\+/,lookbehind:!0,inside:{punctuation:/\||(?:\+[=-]+)+\+/}},{pattern:/(\s*)(?:=+ +)+=+((?:\r?\n|\r)\1.+)+(?:\r?\n|\r)\1(?:=+ +)+=+(?=(?:\r?\n|\r){2}|\s*$)/,lookbehind:!0,inside:{punctuation:/[=-]+/}}],"substitution-def":{pattern:/(^\s*\.\. )\|(?:[^|\s](?:[^|]*[^|\s])?)\| [^:]+::/m,lookbehind:!0,inside:{substitution:{pattern:/^\|(?:[^|\s]|[^|\s][^|]*[^|\s])\|/,alias:"attr-value",inside:{punctuation:/^\||\|$/}},directive:{pattern:/( +)[^:]+::/,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}}}},"link-target":[{pattern:/(^\s*\.\. )\[[^\]]+\]/m,lookbehind:!0,alias:"string",inside:{punctuation:/^\[|\]$/}},{pattern:/(^\s*\.\. )_(?:`[^`]+`|(?:[^:\\]|\\.)+):/m,lookbehind:!0,alias:"string",inside:{punctuation:/^_|:$/}}],directive:{pattern:/(^\s*\.\. )[^:]+::/m,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}},comment:{pattern:/(^\s*\.\.)(?:(?: .+)?(?:(?:\r?\n|\r).+)+| .+)(?=(?:\r?\n|\r){2}|$)/m,lookbehind:!0},title:[{pattern:/^(([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+)(?:\r?\n|\r).+(?:\r?\n|\r)\1$/m,inside:{punctuation:/^[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+|[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}},{pattern:/(^|(?:\r?\n|\r){2}).+(?:\r?\n|\r)([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+(?=\r?\n|\r|$)/,lookbehind:!0,inside:{punctuation:/[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}}],hr:{pattern:/((?:\r?\n|\r){2})([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2{3,}(?=(?:\r?\n|\r){2})/,lookbehind:!0,alias:"punctuation"},field:{pattern:/(^\s*):[^:\r\n]+:(?= )/m,lookbehind:!0,alias:"attr-name"},"command-line-option":{pattern:/(^\s*)(?:[+-][a-z\d]|(?:\-\-|\/)[a-z\d-]+)(?:[ =](?:[a-z][a-z\d_-]*|<[^<>]+>))?(?:, (?:[+-][a-z\d]|(?:\-\-|\/)[a-z\d-]+)(?:[ =](?:[a-z][a-z\d_-]*|<[^<>]+>))?)*(?=(?:\r?\n|\r)? {2,}\S)/im,lookbehind:!0,alias:"symbol"},"literal-block":{pattern:/::(?:\r?\n|\r){2}([ \t]+).+(?:(?:\r?\n|\r)\1.+)*/,inside:{"literal-block-punctuation":{pattern:/^::/,alias:"punctuation"}}},"quoted-literal-block":{pattern:/::(?:\r?\n|\r){2}([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]).*(?:(?:\r?\n|\r)\1.*)*/,inside:{"literal-block-punctuation":{pattern:/^(?:::|([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\1*)/m,alias:"punctuation"}}},"list-bullet":{pattern:/(^\s*)(?:[*+\-•‣⁃]|\(?(?:\d+|[a-z]|[ivxdclm]+)\)|(?:\d+|[a-z]|[ivxdclm]+)\.)(?= )/im,lookbehind:!0,alias:"punctuation"},"doctest-block":{pattern:/(^\s*)>>> .+(?:(?:\r?\n|\r).+)*/m,lookbehind:!0,inside:{punctuation:/^>>>/}},inline:[{pattern:/(^|[\s\-:\/'"<(\[{])(?::[^:]+:`.*?`|`.*?`:[^:]+:|(\*\*?|``?|\|)(?!\s).*?[^\s]\2(?=[\s\-.,:;!?\\\/'")\]}]|$))/m,lookbehind:!0,inside:{bold:{pattern:/(^\*\*).+(?=\*\*$)/,lookbehind:!0},italic:{pattern:/(^\*).+(?=\*$)/,lookbehind:!0},"inline-literal":{pattern:/(^``).+(?=``$)/,lookbehind:!0,alias:"symbol"},role:{pattern:/^:[^:]+:|:[^:]+:$/,alias:"function",inside:{punctuation:/^:|:$/}},"interpreted-text":{pattern:/(^`).+(?=`$)/,lookbehind:!0,alias:"attr-value"},substitution:{pattern:/(^\|).+(?=\|$)/,lookbehind:!0,alias:"attr-value"},punctuation:/\*\*?|``?|\|/}}],link:[{pattern:/\[[^\]]+\]_(?=[\s\-.,:;!?\\\/'")\]}]|$)/,alias:"string",inside:{punctuation:/^\[|\]_$/}},{pattern:/(?:\b[a-z\d](?:[_.:+]?[a-z\d]+)*_?_|`[^`]+`_?_|_`[^`]+`)(?=[\s\-.,:;!?\\\/'")\]}]|$)/i,alias:"string",inside:{punctuation:/^_?`|`$|`?_?_$/}}],punctuation:{pattern:/(^\s*)(?:\|(?= |$)|(?:---?|—|\.\.|__)(?= )|\.\.$)/m,lookbehind:!0}};
Prism.languages.rust={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:[{pattern:/b?r(#*)"(?:\\?.)*?"\1/,greedy:!0},{pattern:/b?("|')(?:\\?.)*?\1/,greedy:!0}],keyword:/\b(?:abstract|alignof|as|be|box|break|const|continue|crate|do|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|match|mod|move|mut|offsetof|once|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\b/,attribute:{pattern:/#!?\[.+?\]/,greedy:!0,alias:"attr-name"},"function":[/[a-z0-9_]+(?=\s*\()/i,/[a-z0-9_]+!(?=\s*\(|\[)/i],"macro-rules":{pattern:/[a-z0-9_]+!/i,alias:"function"},number:/\b-?(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(\d(_?\d)*)?\.?\d(_?\d)*([Ee][+-]?\d+)?)(?:_?(?:[iu](?:8|16|32|64)?|f32|f64))?\b/,"closure-params":{pattern:/\|[^|]*\|(?=\s*[{-])/,inside:{punctuation:/[\|:,]/,operator:/[&*]/}},punctuation:/[{}[\];(),:]|\.+|->/,operator:/[-+*\/%!^=]=?|@|&[&=]?|\|[|=]?|<<?=?|>>?=?/};
!function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t]+.+)*/m,lookbehind:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,inside:{atrule:/(?:@[\w-]+|[+=])/m}}}),delete e.languages.sass.atrule;var a=/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i,t=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|or|not)\b/,{pattern:/(\s+)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,inside:{punctuation:/:/,variable:a,operator:t}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s]+.*)/m,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:a,operator:t,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,delete e.languages.sass.selector,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/([ \t]*)\S(?:,?[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,?[^,\r\n]+)*)*/,lookbehind:!0}})}(Prism);
Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)*url(?=\()/i,selector:{pattern:/(?=\S)[^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-_\w]+/,variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.scss.property={pattern:/(?:[\w-]|\$[-_\w]+|#\{\$[-_\w]+\})+(?=\s*:)/i,inside:{variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}},Prism.languages.insertBefore("scss","important",{variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-_\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},"boolean":/\b(?:true|false)\b/,"null":/\bnull\b/,operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.util.clone(Prism.languages.scss);
Prism.languages.scala=Prism.languages.extend("java",{keyword:/<-|=>|\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\b/,string:[{pattern:/"""[\s\S]*?"""/,greedy:!0},{pattern:/("|')(?:\\\\|\\?[^\\\r\n])*?\1/,greedy:!0}],builtin:/\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\b/,number:/\b(?:0x[\da-f]*\.?[\da-f]+|\d*\.?\d+e?\d*[dfl]?)\b/i,symbol:/'[^\d\s\\]\w*/}),delete Prism.languages.scala["class-name"],delete Prism.languages.scala["function"];
Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},string:{pattern:/(^|[^@\\])("|')(?:\\?[\s\S])*?\2/,greedy:!0,lookbehind:!0},variable:/@[\w.$]+|@("|'|`)(?:\\?[\s\S])+?\1/,"function":/\b(?:COUNT|SUM|AVG|MIN|MAX|FIRST|LAST|UCASE|LCASE|MID|LEN|ROUND|NOW|FORMAT)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR VARYING|CHARACTER (?:SET|VARYING)|CHARSET|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|DATA(?:BASES?)?|DATE(?:TIME)?|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITER(?:S)?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE(?: PRECISION)?|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE(?:D BY)?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEYS?|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL(?: CHAR VARYING| CHARACTER(?: VARYING)?| VARCHAR)?|NATURAL|NCHAR(?: VARCHAR)?|NEXT|NO(?: SQL|CHECK|CYCLE)?|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READ(?:S SQL DATA|TEXT)?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURNS?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START(?:ING BY)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED BY|TEXT(?:SIZE)?|THEN|TIMESTAMP|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNPIVOT|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?)\b/i,"boolean":/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b-?(?:0x)?\d*\.?[\da-f]+\b/,operator:/[-+*\/=%^~]|&&?|\|?\||!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/};
Prism.languages.typescript=Prism.languages.extend("javascript",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield|false|true|module|declare|constructor|string|Function|any|number|boolean|Array|enum|symbol|namespace|abstract|require|type)\b/}),Prism.languages.ts=Prism.languages.typescript;
Prism.languages.vim={string:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\r\n]|'')*'/,comment:/".*/,"function":/\w+(?=\()/,keyword:/\b(?:ab|abbreviate|abc|abclear|abo|aboveleft|al|all|arga|argadd|argd|argdelete|argdo|arge|argedit|argg|argglobal|argl|arglocal|ar|args|argu|argument|as|ascii|bad|badd|ba|ball|bd|bdelete|be|bel|belowright|bf|bfirst|bl|blast|bm|bmodified|bn|bnext|bN|bNext|bo|botright|bp|bprevious|brea|break|breaka|breakadd|breakd|breakdel|breakl|breaklist|br|brewind|bro|browse|bufdo|b|buffer|buffers|bun|bunload|bw|bwipeout|ca|cabbrev|cabc|cabclear|caddb|caddbuffer|cad|caddexpr|caddf|caddfile|cal|call|cat|catch|cb|cbuffer|cc|ccl|cclose|cd|ce|center|cex|cexpr|cf|cfile|cfir|cfirst|cgetb|cgetbuffer|cgete|cgetexpr|cg|cgetfile|c|change|changes|chd|chdir|che|checkpath|checkt|checktime|cla|clast|cl|clist|clo|close|cmapc|cmapclear|cnew|cnewer|cn|cnext|cN|cNext|cnf|cnfile|cNfcNfile|cnorea|cnoreabbrev|col|colder|colo|colorscheme|comc|comclear|comp|compiler|conf|confirm|con|continue|cope|copen|co|copy|cpf|cpfile|cp|cprevious|cq|cquit|cr|crewind|cuna|cunabbrev|cu|cunmap|cw|cwindow|debugg|debuggreedy|delc|delcommand|d|delete|delf|delfunction|delm|delmarks|diffg|diffget|diffoff|diffpatch|diffpu|diffput|diffsplit|diffthis|diffu|diffupdate|dig|digraphs|di|display|dj|djump|dl|dlist|dr|drop|ds|dsearch|dsp|dsplit|earlier|echoe|echoerr|echom|echomsg|echon|e|edit|el|else|elsei|elseif|em|emenu|endfo|endfor|endf|endfunction|endfun|en|endif|endt|endtry|endw|endwhile|ene|enew|ex|exi|exit|exu|exusage|f|file|files|filetype|fina|finally|fin|find|fini|finish|fir|first|fix|fixdel|fo|fold|foldc|foldclose|folddoc|folddoclosed|foldd|folddoopen|foldo|foldopen|for|fu|fun|function|go|goto|gr|grep|grepa|grepadd|ha|hardcopy|h|help|helpf|helpfind|helpg|helpgrep|helpt|helptags|hid|hide|his|history|ia|iabbrev|iabc|iabclear|if|ij|ijump|il|ilist|imapc|imapclear|in|inorea|inoreabbrev|isearch|isp|isplit|iuna|iunabbrev|iu|iunmap|j|join|ju|jumps|k|keepalt|keepj|keepjumps|kee|keepmarks|laddb|laddbuffer|lad|laddexpr|laddf|laddfile|lan|language|la|last|later|lb|lbuffer|lc|lcd|lch|lchdir|lcl|lclose|let|left|lefta|leftabove|lex|lexpr|lf|lfile|lfir|lfirst|lgetb|lgetbuffer|lgete|lgetexpr|lg|lgetfile|lgr|lgrep|lgrepa|lgrepadd|lh|lhelpgrep|l|list|ll|lla|llast|lli|llist|lmak|lmake|lm|lmap|lmapc|lmapclear|lnew|lnewer|lne|lnext|lN|lNext|lnf|lnfile|lNf|lNfile|ln|lnoremap|lo|loadview|loc|lockmarks|lockv|lockvar|lol|lolder|lop|lopen|lpf|lpfile|lp|lprevious|lr|lrewind|ls|lt|ltag|lu|lunmap|lv|lvimgrep|lvimgrepa|lvimgrepadd|lw|lwindow|mak|make|ma|mark|marks|mat|match|menut|menutranslate|mk|mkexrc|mks|mksession|mksp|mkspell|mkvie|mkview|mkv|mkvimrc|mod|mode|m|move|mzf|mzfile|mz|mzscheme|nbkey|new|n|next|N|Next|nmapc|nmapclear|noh|nohlsearch|norea|noreabbrev|nu|number|nun|nunmap|omapc|omapclear|on|only|o|open|opt|options|ou|ounmap|pc|pclose|ped|pedit|pe|perl|perld|perldo|po|pop|popu|popu|popup|pp|ppop|pre|preserve|prev|previous|p|print|P|Print|profd|profdel|prof|profile|promptf|promptfind|promptr|promptrepl|ps|psearch|pta|ptag|ptf|ptfirst|ptj|ptjump|ptl|ptlast|ptn|ptnext|ptN|ptNext|ptp|ptprevious|ptr|ptrewind|pts|ptselect|pu|put|pw|pwd|pyf|pyfile|py|python|qa|qall|q|quit|quita|quitall|r|read|rec|recover|redi|redir|red|redo|redr|redraw|redraws|redrawstatus|reg|registers|res|resize|ret|retab|retu|return|rew|rewind|ri|right|rightb|rightbelow|rub|ruby|rubyd|rubydo|rubyf|rubyfile|ru|runtime|rv|rviminfo|sal|sall|san|sandbox|sa|sargument|sav|saveas|sba|sball|sbf|sbfirst|sbl|sblast|sbm|sbmodified|sbn|sbnext|sbN|sbNext|sbp|sbprevious|sbr|sbrewind|sb|sbuffer|scripte|scriptencoding|scrip|scriptnames|se|set|setf|setfiletype|setg|setglobal|setl|setlocal|sf|sfind|sfir|sfirst|sh|shell|sign|sil|silent|sim|simalt|sla|slast|sl|sleep|sm|smagic|sm|smap|smapc|smapclear|sme|smenu|sn|snext|sN|sNext|sni|sniff|sno|snomagic|snor|snoremap|snoreme|snoremenu|sor|sort|so|source|spelld|spelldump|spe|spellgood|spelli|spellinfo|spellr|spellrepall|spellu|spellundo|spellw|spellwrong|sp|split|spr|sprevious|sre|srewind|sta|stag|startg|startgreplace|star|startinsert|startr|startreplace|stj|stjump|st|stop|stopi|stopinsert|sts|stselect|sun|sunhide|sunm|sunmap|sus|suspend|sv|sview|syncbind|t|tab|tabc|tabclose|tabd|tabdo|tabe|tabedit|tabf|tabfind|tabfir|tabfirst|tabl|tablast|tabm|tabmove|tabnew|tabn|tabnext|tabN|tabNext|tabo|tabonly|tabp|tabprevious|tabr|tabrewind|tabs|ta|tag|tags|tc|tcl|tcld|tcldo|tclf|tclfile|te|tearoff|tf|tfirst|th|throw|tj|tjump|tl|tlast|tm|tm|tmenu|tn|tnext|tN|tNext|to|topleft|tp|tprevious|tr|trewind|try|ts|tselect|tu|tu|tunmenu|una|unabbreviate|u|undo|undoj|undojoin|undol|undolist|unh|unhide|unlet|unlo|unlockvar|unm|unmap|up|update|verb|verbose|ve|version|vert|vertical|vie|view|vim|vimgrep|vimgrepa|vimgrepadd|vi|visual|viu|viusage|vmapc|vmapclear|vne|vnew|vs|vsplit|vu|vunmap|wa|wall|wh|while|winc|wincmd|windo|winp|winpos|win|winsize|wn|wnext|wN|wNext|wp|wprevious|wq|wqa|wqall|w|write|ws|wsverb|wv|wviminfo|X|xa|xall|x|xit|xm|xmap|xmapc|xmapclear|xme|xmenu|XMLent|XMLns|xn|xnoremap|xnoreme|xnoremenLine truncated
Prism.languages.wiki=Prism.languages.extend("markup",{"block-comment":{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0,alias:"comment"},heading:{pattern:/^(=+).+?\1/m,inside:{punctuation:/^=+|=+$/,important:/.+/}},emphasis:{pattern:/('{2,5}).+?\1/,inside:{"bold italic":{pattern:/(''''').+?(?=\1)/,lookbehind:!0},bold:{pattern:/(''')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},italic:{pattern:/('')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},punctuation:/^''+|''+$/}},hr:{pattern:/^-{4,}/m,alias:"punctuation"},url:[/ISBN +(?:97[89][ -]?)?(?:\d[ -]?){9}[\dx]\b|(?:RFC|PMID) +\d+/i,/\[\[.+?\]\]|\[.+?\]/],variable:[/__[A-Z]+__/,/\{{3}.+?\}{3}/,/\{\{.+?}}/],symbol:[/^#redirect/im,/~{3,5}/],"table-tag":{pattern:/((?:^|[|!])[|!])[^|\r\n]+\|(?!\|)/m,lookbehind:!0,inside:{"table-bar":{pattern:/\|$/,alias:"punctuation"},rest:Prism.languages.markup.tag.inside}},punctuation:/^(?:\{\||\|\}|\|-|[*#:;!|])|\|\||!!/m}),Prism.languages.insertBefore("wiki","tag",{nowiki:{pattern:/<(nowiki|pre|source)\b[\s\S]*?>[\s\S]*?<\/\1>/i,inside:{tag:{pattern:/<(?:nowiki|pre|source)\b[\s\S]*?>|<\/(?:nowiki|pre|source)>/i,inside:Prism.languages.markup.tag.inside}}}});
Prism.languages.yaml={scalar:{pattern:/([\-:]\s*(![^\s]+)?[ \t]*[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\3[^\r\n]+)*)/,lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:/(\s*(?:^|[:\-,[{\r\n?])[ \t]*(![^\s]+)?[ \t]*)[^\r\n{[\]},#\s]+?(?=\s*:\s)/,lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(\d{4}-\d\d?-\d\d?([tT]|[ \t]+)\d\d?:\d{2}:\d{2}(\.\d*)?[ \t]*(Z|[-+]\d\d?(:\d{2})?)?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(:\d{2}(\.\d*)?)?)(?=[ \t]*($|,|]|}))/m,lookbehind:!0,alias:"number"},"boolean":{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(true|false)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},"null":{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(null|~)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},string:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')(?=[ \t]*($|,|]|}))/m,lookbehind:!0,greedy:!0},number:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)[+\-]?(0x[\da-f]+|0o[0-7]+|(\d+\.?\d*|\.?\d+)(e[\+\-]?\d+)?|\.inf|\.nan)[ \t]*(?=$|,|]|})/im,lookbehind:!0},tag:/![^\s]+/,important:/[&*][\w]+/,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./};
!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var e="line-numbers",t=function(e){var t=n(e),r=t["white-space"];if("pre-wrap"===r||"pre-line"===r){var s=e.querySelector("code"),l=e.querySelector(".line-numbers-rows"),a=e.querySelector(".line-numbers-sizer"),i=e.textContent.split("\n");a||(a=document.createElement("span"),a.className="line-numbers-sizer",s.appendChild(a)),a.style.display="block",i.forEach(function(e,t){a.textContent=e||"\n";var n=a.getBoundingClientRect().height;l.children[t].style.height=n+"px"}),a.textContent="",a.style.display="none"}},n=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null};window.addEventListener("resize",function(){Array.prototype.forEach.call(document.querySelectorAll("pre."+e),t)}),Prism.hooks.add("complete",function(e){if(e.code){var n=e.element.parentNode,r=/\s*\bline-numbers\b\s*/;if(n&&/pre/i.test(n.nodeName)&&(r.test(n.className)||r.test(e.element.className))&&!e.element.querySelector(".line-numbers-rows")){r.test(e.element.className)&&(e.element.className=e.element.className.replace(r," ")),r.test(n.className)||(n.className+=" line-numbers");var s,l=e.code.match(/\n(?!$)/g),a=l?l.length+1:1,i=new Array(a+1);i=i.join("<span></span>"),s=document.createElement("span"),s.setAttribute("aria-hidden","true"),s.className="line-numbers-rows",s.innerHTML=i,n.hasAttribute("data-start")&&(n.style.counterReset="linenumber "+(parseInt(n.getAttribute("data-start"),10)-1)),e.element.appendChild(s),t(n)}}})}}();
!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var i=/\b([a-z]{3,7}:\/\/|tel:)[\w\-+%~\/.:#=?&amp;]+/,n=/\b\S+@[\w.]+[a-z]{2}/,e=/\[([^\]]+)]\(([^)]+)\)/,t=["comment","url","attr-value","string"];Prism.plugins.autolinker={processGrammar:function(a){a&&!a["url-link"]&&(Prism.languages.DFS(a,function(a,r,l){t.indexOf(l)>-1&&"Array"!==Prism.util.type(r)&&(r.pattern||(r=this[a]={pattern:r}),r.inside=r.inside||{},"comment"==l&&(r.inside["md-link"]=e),"attr-value"==l?Prism.languages.insertBefore("inside","punctuation",{"url-link":i},r):r.inside["url-link"]=i,r.inside["email-link"]=n)}),a["url-link"]=i,a["email-link"]=n)}},Prism.hooks.add("before-highlight",function(i){Prism.plugins.autolinker.processGrammar(i.grammar)}),Prism.hooks.add("wrap",function(i){if(/-link$/.test(i.type)){i.tag="a";var n=i.content;if("email-link"==i.type&&0!=n.indexOf("mailto:"))n="mailto:"+n;else if("md-link"==i.type){var t=i.content.match(e);n=t[2],i.content=t[1]}i.attributes.href=n}try{i.content=decodeURIComponent(i.content)}catch(a){}})}}();
!function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var s,a=t.getAttribute("data-src"),n=t,r=/\blang(?:uage)?-(?!\*)(\w+)\b/i;n&&!r.test(n.className);)n=n.parentNode;if(n&&(s=(t.className.match(r)||[,""])[1]),!s){var o=(a.match(/\.(\w+)$/)||[,""])[1];s=e[o]||o}var l=document.createElement("code");l.className="language-"+s,t.textContent="",l.textContent="Loading…",t.appendChild(l);var i=new XMLHttpRequest;i.open("GET",a,!0),i.onreadystatechange=function(){4==i.readyState&&(i.status<400&&i.responseText?(l.textContent=i.responseText,Prism.highlightElement(l)):l.textContent=i.status>=400?"✖ Error "+i.status+" while fetching file: "+i.statusText:"✖ Error: File does not exist or is empty")},i.send(null)})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))}();
!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=[],e={},n=function(){};Prism.plugins.toolbar={};var a=Prism.plugins.toolbar.registerButton=function(n,a){var o;o="function"==typeof a?a:function(t){var e;return"function"==typeof a.onClick?(e=document.createElement("button"),e.type="button",e.addEventListener("click",function(){a.onClick.call(this,t)})):"string"==typeof a.url?(e=document.createElement("a"),e.href=a.url):e=document.createElement("span"),e.textContent=a.text,e},t.push(e[n]=o)},o=Prism.plugins.toolbar.hook=function(a){var o=a.element.parentNode;if(o&&/pre/i.test(o.nodeName)&&!o.classList.contains("code-toolbar")){o.classList.add("code-toolbar");var r=document.createElement("div");r.classList.add("toolbar"),document.body.hasAttribute("data-toolbar-order")&&(t=document.body.getAttribute("data-toolbar-order").split(",").map(function(t){return e[t]||n})),t.forEach(function(t){var e=t(a);if(e){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(e),r.appendChild(n)}}),o.appendChild(r)}};a("label",function(t){var e=t.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&e.hasAttribute("data-label")){var n,a,o=e.getAttribute("data-label");try{a=document.querySelector("template#"+o)}catch(r){}return a?n=a.content:(e.hasAttribute("data-url")?(n=document.createElement("a"),n.href=e.getAttribute("data-url")):n=document.createElement("span"),n.textContent=o),n}}),Prism.hooks.add("complete",o)}}();
!function(){"undefined"!=typeof self&&self.Prism&&self.document&&Prism.languages.markup&&(Prism.plugins.UnescapedMarkup=!0,Prism.hooks.add("before-highlightall",function(e){e.selector+=", .lang-markup script[type='text/plain'], .language-markup script[type='text/plain'], script[type='text/plain'].lang-markup, script[type='text/plain'].language-markup"}),Prism.hooks.add("before-sanity-check",function(e){if("markup"==e.language){if(e.element.matches("script[type='text/plain']")){var t=document.createElement("code"),a=document.createElement("pre");return a.className=t.className=e.element.className,e.element.dataset&&Object.keys(e.element.dataset).forEach(function(t){Object.prototype.hasOwnProperty.call(e.element.dataset,t)&&(a.dataset[t]=e.element.dataset[t])}),e.code=e.code.replace(/&lt;\/script(>|&gt;)/gi,"</script>"),t.textContent=e.code,a.appendChild(t),e.element.parentNode.replaceChild(a,e.element),e.element=t,void 0}var a=e.element.parentNode;!e.code&&a&&"pre"==a.nodeName.toLowerCase()&&e.element.childNodes.length&&"#comment"==e.element.childNodes[0].nodeName&&(e.element.textContent=e.code=e.element.childNodes[0].textContent)}}))}();
!function(){"undefined"!=typeof self&&self.Prism&&self.document&&Prism.hooks.add("complete",function(e){if(e.code){var t=e.element.parentNode,a=/\s*\bcommand-line\b\s*/;if(t&&/pre/i.test(t.nodeName)&&(a.test(t.className)||a.test(e.element.className))&&!e.element.querySelector(".command-line-prompt")){a.test(e.element.className)&&(e.element.className=e.element.className.replace(a,"")),a.test(t.className)||(t.className+=" command-line");var n=function(e,a){return(t.getAttribute(e)||a).replace(/"/g,"&quot")},s=new Array(1+e.code.split("\n").length),r=n("data-prompt","");if(""!==r)s=s.join('<span data-prompt="'+r+'"></span>');else{var l=n("data-user","user"),m=n("data-host","localhost");s=s.join('<span data-user="'+l+'" data-host="'+m+'"></span>')}var o=document.createElement("span");o.className="command-line-prompt",o.innerHTML=s;var i=t.getAttribute("data-output")||"";i=i.split(",");for(var c=0;c<i.length;c++){var p=i[c].split("-"),d=parseInt(p[0]),u=d;if(2===p.length&&(u=parseInt(p[1])),!isNaN(d)&&!isNaN(u))for(var f=d;u>=f&&f<=o.children.length;f++){var N=o.children[f-1];N.removeAttribute("data-user"),N.removeAttribute("data-host"),N.removeAttribute("data-prompt")}}e.element.innerHTML=o.outerHTML+e.element.innerHTML}}})}();
!function(){if("undefined"!=typeof self&&self.Prism&&self.document){if(!Prism.plugins.toolbar)return console.warn("Show Languages plugin loaded before Toolbar plugin."),void 0;var e={html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",css:"CSS",clike:"C-like",javascript:"JavaScript",abap:"ABAP",actionscript:"ActionScript",apacheconf:"Apache Configuration",apl:"APL",applescript:"AppleScript",asciidoc:"AsciiDoc",aspnet:"ASP.NET (C#)",autoit:"AutoIt",autohotkey:"AutoHotkey",basic:"BASIC",csharp:"C#",cpp:"C++",coffeescript:"CoffeeScript","css-extras":"CSS Extras",django:"Django/Jinja2",fsharp:"F#",glsl:"GLSL",graphql:"GraphQL",http:"HTTP",inform7:"Inform 7",json:"JSON",latex:"LaTeX",livescript:"LiveScript",lolcode:"LOLCODE",matlab:"MATLAB",mel:"MEL",n4js:"N4JS",nasm:"NASM",nginx:"nginx",nsis:"NSIS",objectivec:"Objective-C",ocaml:"OCaml",opencl:"OpenCL",parigp:"PARI/GP",php:"PHP","php-extras":"PHP Extras",powershell:"PowerShell",properties:".properties",protobuf:"Protocol Buffers",jsx:"React JSX",renpy:"Ren'py",rest:"reST (reStructuredText)",sas:"SAS",sass:"Sass (Sass)",scss:"Sass (Scss)",sql:"SQL",typescript:"TypeScript",vbnet:"VB.Net",vhdl:"VHDL",vim:"vim",wiki:"Wiki markup",xojo:"Xojo (REALbasic)",yaml:"YAML"};Prism.plugins.toolbar.registerButton("show-language",function(t){var a=t.element.parentNode;if(a&&/pre/i.test(a.nodeName)){var s=a.getAttribute("data-language")||e[t.language]||t.language.substring(0,1).toUpperCase()+t.language.substring(1),r=document.createElement("span");return r.textContent=s,r}})}}();
!function(){if("undefined"!=typeof self&&self.Prism&&self.document){if(!Prism.plugins.toolbar)return console.warn("Copy to Clipboard plugin loaded before Toolbar plugin."),void 0;var o=window.Clipboard||void 0;o||"function"!=typeof require||(o=require("clipboard"));var e=[];if(!o){var t=document.createElement("script"),n=document.querySelector("head");t.onload=function(){if(o=window.Clipboard)for(;e.length;)e.pop()()},t.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.8/clipboard.min.js",n.appendChild(t)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(t){function n(){var e=new o(i,{text:function(){return t.code}});e.on("success",function(){i.textContent="Copied!",r()}),e.on("error",function(){i.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){i.textContent="Copy"},5e3)}var i=document.createElement("a");return i.textContent="Copy",o?n():e.push(n),i})}}();
@@ -1,11 +0,0 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false,
apiUrl: 'http://192.168.0.153:8445',
appVersion: '1.0.1',
title: 'Intégration'
};
@@ -1,6 +0,0 @@
export const environment = {
production: true,
apiUrl: 'https://176.188.217.1:54444',
appVersion: '1.0.1',
title: ''
};
@@ -1,11 +0,0 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false,
apiUrl: 'http://localhost:8080',
appVersion: '1.0.1',
title: 'Développement'
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

-17
View File
@@ -1,17 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>Codiki</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<base href="/" />
<link rel="icon" type="image/x-icon" href="favicon.png" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="./assets/css/prism.css" rel="stylesheet" />
</head>
<body>
<app-root></app-root>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.8/clipboard.min.js"></script>
<script type="text/javascript" src="./assets/js/prism.js"></script>
</body>
</html>
-12
View File
@@ -1,12 +0,0 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
-79
View File
@@ -1,79 +0,0 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
-38
View File
@@ -1,38 +0,0 @@
/* You can add global styles to this file, and also import other style files */
html {
height: 100%;
}
body {
// 64px for the header and 15px for a litle margin.
padding-top: 90px;
padding-bottom: 30px;
display: flex;
position: relative;
flex-direction: column;
justify-content:space-between;
min-height: 100%;
}
/* ***** Floating card button ***** */
.btn-card-floating {
border-radius: 50%;
width: 47px;
height: 47px;
margin: -23px 20px;
margin-left: auto;
line-height: 0;
display: inline-block;
text-align: center;
line-height: 47px;
padding-left: 2px;
z-index: 1;
box-shadow: 0 5px 11px 0 rgba(0,0,0,.18), 0 4px 15px 0 rgba(0,0,0,.15);
background-color: #3f51b5;
transition: box-shadow 0.3s ease-in-out;
}
.btn-card-floating:hover {
box-shadow: 0 8px 17px 0 rgba(0,0,0,.2), 0 6px 20px 0 rgba(0,0,0,.19);
}
/* ***** End of floating card button ***** */
-20
View File
@@ -1,20 +0,0 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
-13
View File
@@ -1,13 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
-19
View File
@@ -1,19 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"module": "commonjs",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}
-5
View File
@@ -1,5 +0,0 @@
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
id: string;
}
-20
View File
@@ -1,20 +0,0 @@
{
"include": ["node_modules/angular-bootstrap-md/**/*.ts", "src/**/*.ts"],
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}
-143
View File
@@ -1,143 +0,0 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs",
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"tabs"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}