Deployed 77f5a4c with MkDocs version: 1.2.3

gh-pages
2 years ago
commit 732a1e4daf

2024
404.html

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
#!/bin/bash
mv "{{subtitles}}" "{{directory}}/{{episode_name}}.{{subtitles_language_code3}}.srt"
exit

File diff suppressed because it is too large Load Diff

@ -0,0 +1 @@
trash-guides.info

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

@ -0,0 +1,61 @@
#!/usr/bin/env python3
#
##############################################################################
### NZBGET SCAN SCRIPT ###
# Clean NZB name.
#
# Removes the following suffixes from NZB name:
# NZBgeek / Obfuscated / BUYMORE / Scrambled.
#
# NOTE: This script requires Python to be installed on your system.
### NZBGET SCAN SCRIPT ###
##############################################################################
from __future__ import print_function
import os, re, sys
# Exit codes used by NZBGet
POSTPROCESS_SUCCESS=93
POSTPROCESS_ERROR=94
POSTPROCESS_SKIP=95
# Check if the script is called from NZBGet 13.0 or later
if not 'NZBOP_SCRIPTDIR' in os.environ:
print('*** NZBGet post-processing script ***')
print('This script is supposed to be called from NZBGet (13.0 or later).')
sys.exit(POSTPROCESS_ERROR)
if not 'NZBNP_NZBNAME' in os.environ:
print('[WARN] Filename not found in environment')
sys.exit(POSTPROCESS_ERROR)
fwp = os.environ['NZBNP_NZBNAME']
fwp = re.sub('(?i)-4P\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-4Planet\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-AsRequested\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-AsRequested-xpost\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-BUYMORE\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-Chamele0n\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-GEROV\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-iNC0GNiTO\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-NZBGeek\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-Obfuscated\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-postbot\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-Rakuv\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-Scrambled\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-WhiteRev\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-xpost\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)\[eztv\]\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)\[TGx\]\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)\[TGx\]-xpost\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)\[ettv\]\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-WRTEAM\.nzb$', '.nzb', fwp)
fwp = re.sub('(?i)-CAPTCHA\.nzb$', '.nzb', fwp)
fwp = re.sub(r'(\-[^-.\n]*)(\-.{4})?\.nzb$', r'\1.nzb', fwp)
if fwp:
print('[NZB] NZBNAME=', fwp, sep='')
sys.exit(POSTPROCESS_SUCCESS)

@ -0,0 +1,185 @@
#!/usr/bin/env python3
#
##############################################################################
# Title: HashRenamer.py #
# Author(s): l3uddz, desimaniac #
# URL: https://github.com/l3uddz/nzbgetScripts #
# Description: Renames hashed media files to match the source NZB. #
# -- #
# Part of the Cloudbox project: https://cloudbox.works #
##############################################################################
##############################################################################
# Built on top of the NZBGet scripts template created by Clinton Hall #
# (https://github.com/clinton-hall). #
# Released under GNU General Public License v2.0 #
##############################################################################
##############################################################################
### NZBGET POST-PROCESSING SCRIPT ###
# Rename files with hashes for file name
#
# NOTE: This script requires Python to be installed on your system.
#
##############################################################################
### NZBGET POST-PROCESSING SCRIPT ###
##############################################################################
import os
import re
import shutil
import sys
# NZBGet Exit Codes
NZBGET_POSTPROCESS_PARCHECK = 92
NZBGET_POSTPROCESS_SUCCESS = 93
NZBGET_POSTPROCESS_ERROR = 94
NZBGET_POSTPROCESS_NONE = 95
############################################################
# EXTENSION STUFF
############################################################
def do_check():
if 'NZBOP_SCRIPTDIR' not in os.environ:
print("This script can only be called from NZBGet (11.0 or later).")
sys.exit(0)
if os.environ['NZBOP_VERSION'][0:5] < '11.0':
print("[ERROR] NZBGet Version %s is not supported. Please update NZBGet." % (str(os.environ['NZBOP_VERSION'])))
sys.exit(0)
print("Script triggered from NZBGet Version %s." % (str(os.environ['NZBOP_VERSION'])))
status = 0
if 'NZBPP_TOTALSTATUS' in os.environ:
if not os.environ['NZBPP_TOTALSTATUS'] == 'SUCCESS':
print("[ERROR] Download failed with status %s." % (os.environ['NZBPP_STATUS']))
status = 1
else:
# Check par status
if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4':
print("[ERROR] Par-repair failed, setting status \"failed\".")
status = 1
# Check unpack status
if os.environ['NZBPP_UNPACKSTATUS'] == '1':
print("[ERROR] Unpack failed, setting status \"failed\".")
status = 1
if os.environ['NZBPP_UNPACKSTATUS'] == '0' and os.environ['NZBPP_PARSTATUS'] == '0':
# Unpack was skipped due to nzb-file properties or due to errors during par-check
if os.environ['NZBPP_HEALTH'] < 1000:
print("[ERROR] Download health is compromised and Par-check/repair disabled or no .par2 files found. " \
"Setting status \"failed\".")
print("[ERROR] Please check your Par-check/repair settings for future downloads.")
status = 1
else:
print("[ERROR] Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is " \
"ok so handle as though download successful.")
print("[WARNING] Please check your Par-check/repair settings for future downloads.")
# Check if destination directory exists (important for reprocessing of history items)
if not os.path.isdir(os.environ['NZBPP_DIRECTORY']):
print("[ERROR] Nothing to post-process: destination directory", os.environ[
'NZBPP_DIRECTORY'], "doesn't exist. Setting status \"failed\".")
status = 1
# All checks done, now launching the script.
if status == 1:
sys.exit(NZBGET_POSTPROCESS_NONE)
def get_file_name(path):
try:
file_name = os.path.basename(path)
extensions = re.findall(r'\.([^.]+)', file_name)
ext = '.'.join(extensions)
name = file_name.replace(".%s" % ext, '')
return name, ext
except Exception:
pass
return None
def is_file_hash(file_name):
hash_regexp = [
r'^[a-fA-F0-9]{40}$',
r'^[a-fA-F0-9]{32}$',
r'^[a-f0-9]{128}$',
r'^[a-zA-Z0-9]{42}$'
]
for hash in hash_regexp:
if re.match(hash, file_name):
return True
return False
def find_files(folder, extension=None, depth=None):
file_list = []
start_count = folder.count(os.sep)
for path, subdirs, files in os.walk(folder, topdown=True):
for name in files:
if depth and path.count(os.sep) - start_count >= depth:
del subdirs[:]
continue
file = os.path.join(path, name)
if not extension:
file_list.append(file)
else:
if file.lower().endswith(extension.lower()):
file_list.append(file)
return sorted(file_list, key=lambda x: x.count(os.path.sep), reverse=True)
############################################################
# MAIN
############################################################
# do checks
do_check()
# retrieve required variables
directory = os.path.normpath(os.environ['NZBPP_DIRECTORY'])
nzb_name = os.environ['NZBPP_NZBFILENAME']
if nzb_name is None:
print("[ERROR] Unable to retrieve NZBPP_NZBFILENAME")
sys.exit(NZBGET_POSTPROCESS_ERROR)
nzb_name = nzb_name.replace('.nzb', '')
print(("[INFO] Using \"%s\" for hashed filenames" % nzb_name))
print(("[INFO] Scanning \"%s\" for hashed filenames" % directory))
# scan for files
found_files = find_files(directory)
if not found_files:
print(("[INFO] No files were found in \"%s\"" % directory))
sys.exit(NZBGET_POSTPROCESS_NONE)
else:
print(("[INFO] Found %d files to check for hashed filenames" % len(found_files)))
# loop files checking for file hash
moved_files = 0
for found_file_path in found_files:
# set variable
dir_name = os.path.dirname(found_file_path)
file_name, file_ext = get_file_name(found_file_path)
# is this a file hash
if is_file_hash(file_name):
new_file_path = os.path.join(dir_name, "%s.%s" % (nzb_name, file_ext))
print(("[INFO] Moving \"%s\" to \"%s\"" % (found_file_path, new_file_path)))
try:
shutil.move(found_file_path, new_file_path)
moved_files += 1
except Exception:
print(("[ERROR] Failed moving \"%s\" to \"%s\"" % (found_file_path, new_file_path)))
print(("[INFO] Finished processing \"%s\", moved %d files" % (directory, moved_files)))
sys.exit(NZBGET_POSTPROCESS_SUCCESS)

@ -0,0 +1,151 @@
#!/usr/bin/env python3
### NZBGET SCAN SCRIPT
# Extract filenames from subjects containing [PRiVATE]-[WtFnZb]
#
# This extensions extracts obfuscated filenames from .nzb files
# created by WtFnZb.
#
# Supported subject formats:
#
# - [PRiVATE]-[WtFnZb]-[filename]-[1/5] - "" yEnc 0 (1/1)"
#
# - [PRiVATE]-[WtFnZb]-[5]-[1/filename] - "" yEnc
#
#
# NOTE: Requires Python and lxml (sudo apt install python3-lxml python-lxml)
#
### NZBGET SCAN SCRIPT
import sys
import os
import re
# Exit codes used by NZBGet
POSTPROCESS_SUCCESS = 93
POSTPROCESS_NONE = 95
POSTPROCESS_ERROR = 94
try:
from lxml import etree
except ImportError:
print(u'[ERROR] Python lxml required. Please install with "sudo apt install python-lxml" or "pip install lxml".')
sys.exit(POSTPROCESS_ERROR)
patterns = (
re.compile(r'^(?P<prefix>.*\[PRiVATE\]-\[WtFnZb\]-)'
r'\[(?P<total>\d+)\]-\[(?P<segment>\d+)\/(?P<filename>.{3,}?)\]'
r'\s+-\s+""\s+yEnc\s+',
re.MULTILINE | re.UNICODE),
re.compile(r'^(?P<prefix>.*\[PRiVATE\]-\[WtFnZb\]-)'
r'\[(?P<filename>.{3,}?)\]-\[(?P<segment>\d+)/(?P<total>\d+)\]'
r'\s+-\s+""\s+yEnc\s+',
re.MULTILINE | re.UNICODE))
nzb_dir = os.getenv('NZBNP_DIRECTORY')
nzb_filename = os.getenv('NZBNP_FILENAME')
nzb_name = os.getenv('NZBNP_NZBNAME')
nzb_file_naming = os.getenv('NZBOP_FILENAMING')
if nzb_dir is None or nzb_filename is None or nzb_name is None:
print('Please run as NZBGet plugin')
sys.exit(POSTPROCESS_ERROR)
if nzb_file_naming is not None and nzb_file_naming.lower() != 'nzb':
print(u'[ERROR] NZBGet setting FileNaming (under Download Queue) '
u'must be set to "Nzb" for this extension to work correctly, exiting.')
sys.exit(POSTPROCESS_ERROR)
if not os.path.exists(nzb_dir):
print('[ERROR] NZB directory doesn\'t exist, exiting')
sys.exit(POSTPROCESS_ERROR)
if not nzb_filename.lower().endswith('.nzb'):
print(u'[ERROR] {} is not a .nzb file.'.format(nzb_filename))
sys.exit(POSTPROCESS_ERROR)
nzb = os.path.join(nzb_dir, nzb_filename)
if not os.path.exists(nzb):
print('[ERROR] {nzb} doesn\'t exist, exiting'.format(nzb=nzb))
sys.exit(POSTPROCESS_ERROR)
with open(nzb, mode='rb') as infile:
tree = etree.parse(infile)
changed = False
file_count = 0
totals = set()
filenames = set()
for f in tree.getiterator('{http://www.newzbin.com/DTD/2003/nzb}file'):
subject = f.get('subject')
if subject is None:
print(u'[DETAIL] No subject in <file>, skipping')
continue
file_count += 1
result = [re.match(pattern, subject) for pattern in patterns]
matched = [m for m in result if m is not None]
if len(matched) == 0:
print(u'[INFO] No pattern matching subject, exiting.')
sys.exit(POSTPROCESS_NONE)
elif len(matched) > 1:
print(u'[ERROR] Multiple patterns matched, exiting.')
sys.exit(POSTPROCESS_ERROR)
else:
match = matched[0].groupdict()
if match['filename'].lower().endswith('.par2'):
print(u'[INFO] par2 exists, exiting')
sys.exit(POSTPROCESS_NONE)
if int(match['segment']) > int(match['total']):
print(u'[DETAIL] Segment index is greater then total, skipping')
continue
# NZBGet subject parsing changes when duplicate filenames are present
# prefix duplicates to avoid that
if match['filename'] in filenames:
match['filename'] = u'{}.{}'.format(file_count, match['filename'])
filenames.add(match['filename'])
s = u'WtFnZb "{filename}" yEnc ({segment}/{total})'.format(
filename = match['filename'],
segment = match['segment'],
total = match['total'])
print(u'[INFO] New subject {subject}'.format(subject=s.encode('ascii', 'ignore')))
f.set('subject', s)
changed = True
totals.add(int(match['total']))
if not changed:
print(u'[WARNING] No subject changed, exiting.')
sys.exit(POSTPROCESS_NONE)
if len(totals) != 1:
print(u'[WARNING] Mixed values for number of total segments, exiting.')
sys.exit(POSTPROCESS_NONE)
if totals.pop() != file_count:
print(u'[WARNING] Listed segment count does not match <file> count, exiting.')
sys.exit(POSTPROCESS_NONE)
org = u'{}.wtfnzb.original.processed'.format(nzb)
exists_counter = 0
while os.path.exists(org):
exists_counter += 1
org = u'{}.{}.wtfnzb.original.processed'.format(nzb, exists_counter)
print(u'[INFO] Preserving original nzb as {}'.format(org))
os.rename(nzb, org)
print(u'[INFO] Writing {}'.format(nzb))
with open(nzb, mode='wb') as outfile:
outfile.write(etree.tostring(tree,
xml_declaration=True,
encoding=tree.docinfo.encoding,
doctype=tree.docinfo.doctype))
sys.exit(POSTPROCESS_SUCCESS)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because it is too large Load Diff

@ -0,0 +1,61 @@
#!/usr/bin/python3 -OO
##################################################################
### SABnzbd - Clean NZB Renamer ##
##################################################################
## NOTE: This script is considered ALPHA! ##
## ##
## Removes the suffixes from NZB name used by bots: ##
## examples: NZBgeek / Obfuscated / BUYMORE / Scrambled, etc.. ##
## ##
## NOTE: This script requires Python 3 ##
## ##
## Install: ##
## 1. Copy script to sabnzbd's script folder ##
## 2. run: sudo chmod +x Clean.py ##
## 3. in SABnzbd go to Config > Switches ##
## 4. Change Pre-queue user script and select: Clean.py ##
##################################################################
import sys
import re
try:
(scriptname, nzbname, postprocflags, category, script, prio, downloadsize, grouplist, showname, season, episodenumber, episodename) = sys.argv
downloadsize = int(downloadsize)
except:
sys.exit(1) # exit with 1 causes SABnzbd to ignore the output of this script
fwp = nzbname
fwp = re.sub('(?i)-4P$', '', fwp)
fwp = re.sub('(?i)-4Planet$', '', fwp)
fwp = re.sub('(?i)-AsRequested$', '', fwp)
fwp = re.sub('(?i)-AsRequested-xpost$', '', fwp)
fwp = re.sub('(?i)-BUYMORE$', '', fwp)
fwp = re.sub('(?i)-Chamele0n$', '', fwp)
fwp = re.sub('(?i)-GEROV$', '', fwp)
fwp = re.sub('(?i)-iNC0GNiTO$', '', fwp)
fwp = re.sub('(?i)-NZBGeek$', '', fwp)
fwp = re.sub('(?i)-Obfuscated$', '', fwp)
fwp = re.sub('(?i)-postbot$', '', fwp)
fwp = re.sub('(?i)-Rakuv$', '', fwp)
fwp = re.sub('(?i)-Scrambled$', '', fwp)
fwp = re.sub('(?i)-WhiteRev$', '', fwp)
fwp = re.sub('(?i)-WRTEAM$', '', fwp)
fwp = re.sub('(?i)-CAPTCHA$', '', fwp)
fwp = re.sub('(?i)\[eztv\]$', '', fwp)
fwp = re.sub('(?i)\[TGx\]$', '', fwp)
fwp = re.sub('(?i)\[ettv\]$', '', fwp)
fwp = re.sub('(?i)\[TGx\]-xpost$', '', fwp)
fwp = re.sub('(?i).mkv-xpost$', '', fwp)
fwp = re.sub('(?i)-xpost$', '', fwp)
fwp = re.sub(r'(\-[^-.\n]*)(\-.{4})?$', r'\1', fwp)
print("1") # Accept
print(fwp)
print()
print()
print()
print()
print()
# 0 means OK
sys.exit(0)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting...</title>
<link rel="canonical" href="../Misc/x265-4k/">
<meta name="robots" content="noindex">
<script>var anchor=window.location.hash.substr(1);location.href="../Misc/x265-4k/"+(anchor?"#"+anchor:"")</script>
<meta http-equiv="refresh" content="0; url=../Misc/x265-4k/">
</head>
<body>
Redirecting...
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

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

Loading…
Cancel
Save