summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster')
-rw-r--r--bitbake/lib/toaster/bldcollector/urls.py2
-rw-r--r--bitbake/lib/toaster/bldcollector/views.py3
-rw-r--r--bitbake/lib/toaster/bldcontrol/localhostbecontroller.py4
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py83
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0008_models_bigautofield.py48
-rw-r--r--bitbake/lib/toaster/bldcontrol/models.py4
-rw-r--r--bitbake/lib/toaster/logs/.gitignore1
-rwxr-xr-xbitbake/lib/toaster/manage.py2
-rw-r--r--bitbake/lib/toaster/orm/fixtures/README2
-rwxr-xr-xbitbake/lib/toaster/orm/fixtures/check_fixtures.py38
-rwxr-xr-xbitbake/lib/toaster/orm/fixtures/gen_fixtures.py451
-rw-r--r--bitbake/lib/toaster/orm/fixtures/oe-core.xml80
-rw-r--r--bitbake/lib/toaster/orm/fixtures/poky.xml210
-rw-r--r--bitbake/lib/toaster/orm/fixtures/settings.xml4
-rw-r--r--bitbake/lib/toaster/orm/management/commands/lsupdates.py16
-rw-r--r--bitbake/lib/toaster/orm/migrations/0020_models_bigautofield.py173
-rw-r--r--bitbake/lib/toaster/orm/migrations/0021_eventlogsimports.py22
-rw-r--r--bitbake/lib/toaster/orm/models.py52
-rw-r--r--bitbake/lib/toaster/pytest.ini16
-rw-r--r--bitbake/lib/toaster/tests/browser/selenium_helpers_base.py88
-rw-r--r--bitbake/lib/toaster/tests/browser/test_all_builds_page.py316
-rw-r--r--bitbake/lib/toaster/tests/browser/test_all_projects_page.py162
-rw-r--r--bitbake/lib/toaster/tests/browser/test_builddashboard_page.py15
-rw-r--r--bitbake/lib/toaster/tests/browser/test_builddashboard_page_artifacts.py8
-rw-r--r--bitbake/lib/toaster/tests/browser/test_delete_project.py103
-rw-r--r--bitbake/lib/toaster/tests/browser/test_landing_page.py143
-rw-r--r--bitbake/lib/toaster/tests/browser/test_layerdetails_page.py31
-rw-r--r--bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py24
-rw-r--r--bitbake/lib/toaster/tests/browser/test_new_custom_image_page.py14
-rw-r--r--bitbake/lib/toaster/tests/browser/test_new_project_page.py16
-rw-r--r--bitbake/lib/toaster/tests/browser/test_project_builds_page.py4
-rw-r--r--bitbake/lib/toaster/tests/browser/test_project_config_page.py33
-rw-r--r--bitbake/lib/toaster/tests/browser/test_sample.py10
-rw-r--r--bitbake/lib/toaster/tests/browser/test_toastertable_ui.py11
-rw-r--r--bitbake/lib/toaster/tests/builds/buildtest.py13
-rw-r--r--bitbake/lib/toaster/tests/builds/test_core_image_min.py20
-rw-r--r--bitbake/lib/toaster/tests/commands/test_loaddata.py4
-rw-r--r--bitbake/lib/toaster/tests/commands/test_lsupdates.py3
-rw-r--r--bitbake/lib/toaster/tests/commands/test_runbuilds.py13
-rw-r--r--bitbake/lib/toaster/tests/db/test_db.py3
-rw-r--r--bitbake/lib/toaster/tests/functional/functional_helpers.py168
-rw-r--r--bitbake/lib/toaster/tests/functional/test_create_new_project.py124
-rw-r--r--bitbake/lib/toaster/tests/functional/test_functional_basic.py249
-rw-r--r--bitbake/lib/toaster/tests/functional/test_project_config.py294
-rw-r--r--bitbake/lib/toaster/tests/functional/test_project_page.py775
-rw-r--r--bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py507
-rw-r--r--bitbake/lib/toaster/tests/functional/utils.py86
-rw-r--r--bitbake/lib/toaster/tests/toaster-tests-requirements.txt10
-rw-r--r--bitbake/lib/toaster/tests/views/test_views.py20
-rw-r--r--bitbake/lib/toaster/toastergui/api.py26
-rw-r--r--bitbake/lib/toaster/toastergui/fixtures/toastergui-unittest-data.xml24
-rw-r--r--bitbake/lib/toaster/toastergui/forms.py14
-rw-r--r--bitbake/lib/toaster/toastergui/static/css/default.css28
-rw-r--r--bitbake/lib/toaster/toastergui/static/css/jquery.dataTables-1.13.8.min.css1
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.js (renamed from bitbake/lib/toaster/toastergui/static/js/bootstrap.js)431
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.min.js6
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/bootstrap.min.js7
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.js2
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.map1
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/jquery.dataTables-1.13.8.min.js4
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/libtoaster.js2
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectpage.js2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/base.html11
-rw-r--r--bitbake/lib/toaster/toastergui/templates/base_specific.html4
-rw-r--r--bitbake/lib/toaster/toastergui/templates/command_line_builds.html209
-rw-r--r--bitbake/lib/toaster/toastergui/templates/configvars.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/js-unit-tests.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/landing.html16
-rw-r--r--bitbake/lib/toaster/toastergui/templates/landing_not_managed.html34
-rw-r--r--bitbake/lib/toaster/toastergui/templates/layerdetails.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/mrb_section.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html8
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_detail_base.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html8
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html4
-rw-r--r--bitbake/lib/toaster/toastergui/templates/project.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/project_specific.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/projectconf.html34
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipe.html4
-rw-r--r--bitbake/lib/toaster/toastergui/templates/target.html4
-rw-r--r--bitbake/lib/toaster/toastergui/templatetags/projecttags.py5
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py6
-rw-r--r--bitbake/lib/toaster/toastergui/views.py220
-rw-r--r--bitbake/lib/toaster/toastergui/widgets.py10
-rw-r--r--bitbake/lib/toaster/toastermain/logs.py158
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/buildimport.py4
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/checksocket.py4
-rw-r--r--bitbake/lib/toaster/toastermain/settings.py86
-rw-r--r--bitbake/lib/toaster/toastermain/settings_test.py4
-rw-r--r--bitbake/lib/toaster/toastermain/urls.py4
-rw-r--r--bitbake/lib/toaster/tox.ini24
91 files changed, 5233 insertions, 668 deletions
diff --git a/bitbake/lib/toaster/bldcollector/urls.py b/bitbake/lib/toaster/bldcollector/urls.py
index efd67a81a5..3c34070351 100644
--- a/bitbake/lib/toaster/bldcollector/urls.py
+++ b/bitbake/lib/toaster/bldcollector/urls.py
@@ -6,7 +6,7 @@
6# SPDX-License-Identifier: GPL-2.0-only 6# SPDX-License-Identifier: GPL-2.0-only
7# 7#
8 8
9from django.conf.urls import url 9from django.urls import re_path as url
10 10
11import bldcollector.views 11import bldcollector.views
12 12
diff --git a/bitbake/lib/toaster/bldcollector/views.py b/bitbake/lib/toaster/bldcollector/views.py
index 04cd8b3dd4..bdf38ae6e8 100644
--- a/bitbake/lib/toaster/bldcollector/views.py
+++ b/bitbake/lib/toaster/bldcollector/views.py
@@ -14,8 +14,11 @@ import subprocess
14import toastermain 14import toastermain
15from django.views.decorators.csrf import csrf_exempt 15from django.views.decorators.csrf import csrf_exempt
16 16
17from toastermain.logs import log_view_mixin
18
17 19
18@csrf_exempt 20@csrf_exempt
21@log_view_mixin
19def eventfile(request): 22def eventfile(request):
20 """ Receives a file by POST, and runs toaster-eventreply on this file """ 23 """ Receives a file by POST, and runs toaster-eventreply on this file """
21 if request.method != "POST": 24 if request.method != "POST":
diff --git a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
index 75674ccbf1..577e765f11 100644
--- a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
+++ b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -200,7 +200,7 @@ class LocalhostBEController(BuildEnvironmentController):
200 localdirpath = os.path.join(localdirname, dirpath) 200 localdirpath = os.path.join(localdirname, dirpath)
201 logger.debug("localhostbecontroller: localdirpath expects '%s'" % localdirpath) 201 logger.debug("localhostbecontroller: localdirpath expects '%s'" % localdirpath)
202 if not os.path.exists(localdirpath): 202 if not os.path.exists(localdirpath):
203 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit)) 203 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Exiting." % (localdirpath, giturl, commit))
204 204
205 if name != "bitbake": 205 if name != "bitbake":
206 layerlist.append("%03d:%s" % (index,localdirpath.rstrip("/"))) 206 layerlist.append("%03d:%s" % (index,localdirpath.rstrip("/")))
@@ -467,7 +467,7 @@ class LocalhostBEController(BuildEnvironmentController):
467 logger.debug("localhostbecontroller: waiting for bblock content to appear") 467 logger.debug("localhostbecontroller: waiting for bblock content to appear")
468 time.sleep(1) 468 time.sleep(1)
469 else: 469 else:
470 raise BuildSetupException("Cannot find bitbake server lock file '%s'. Aborting." % bblock) 470 raise BuildSetupException("Cannot find bitbake server lock file '%s'. Exiting." % bblock)
471 471
472 with open(bblock) as fplock: 472 with open(bblock) as fplock:
473 for line in fplock: 473 for line in fplock:
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
index 19f659ec41..834e32b36f 100644
--- a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -180,6 +180,77 @@ class Command(BaseCommand):
180 except Exception as e: 180 except Exception as e:
181 logger.warning("runbuilds: schedule exception %s" % str(e)) 181 logger.warning("runbuilds: schedule exception %s" % str(e))
182 182
183 # Test to see if a build pre-maturely died due to a bitbake crash
184 def check_dead_builds(self):
185 do_cleanup = False
186 try:
187 for br in BuildRequest.objects.filter(state=BuildRequest.REQ_INPROGRESS):
188 # Get the build directory
189 if br.project.builddir:
190 builddir = br.project.builddir
191 else:
192 builddir = '%s-toaster-%d' % (br.environment.builddir,br.project.id)
193 # Check log to see if there is a recent traceback
194 toaster_ui_log = os.path.join(builddir, 'toaster_ui.log')
195 test_file = os.path.join(builddir, '._toaster_check.txt')
196 os.system("tail -n 50 %s > %s" % (os.path.join(builddir, 'toaster_ui.log'),test_file))
197 traceback_text = ''
198 is_traceback = False
199 with open(test_file,'r') as test_file_fd:
200 test_file_tail = test_file_fd.readlines()
201 for line in test_file_tail:
202 if line.startswith('Traceback (most recent call last):'):
203 traceback_text = line
204 is_traceback = True
205 elif line.startswith('NOTE: ToasterUI waiting for events'):
206 # Ignore any traceback before new build start
207 traceback_text = ''
208 is_traceback = False
209 elif line.startswith('Note: Toaster traceback auto-stop'):
210 # Ignore any traceback before this previous traceback catch
211 traceback_text = ''
212 is_traceback = False
213 elif is_traceback:
214 traceback_text += line
215 # Test the results
216 is_stop = False
217 if is_traceback:
218 # Found a traceback
219 errtype = 'Bitbake crash'
220 errmsg = 'Bitbake crash\n' + traceback_text
221 state = BuildRequest.REQ_FAILED
222 # Clean up bitbake files
223 bitbake_lock = os.path.join(builddir, 'bitbake.lock')
224 if os.path.isfile(bitbake_lock):
225 os.remove(bitbake_lock)
226 bitbake_sock = os.path.join(builddir, 'bitbake.sock')
227 if os.path.isfile(bitbake_sock):
228 os.remove(bitbake_sock)
229 if os.path.isfile(test_file):
230 os.remove(test_file)
231 # Add note to ignore this traceback on next check
232 os.system('echo "Note: Toaster traceback auto-stop" >> %s' % toaster_ui_log)
233 is_stop = True
234 # Add more tests here
235 #elif ...
236 # Stop the build request?
237 if is_stop:
238 brerror = BRError(
239 req = br,
240 errtype = errtype,
241 errmsg = errmsg,
242 traceback = traceback_text,
243 )
244 brerror.save()
245 br.state = state
246 br.save()
247 do_cleanup = True
248 # Do cleanup
249 if do_cleanup:
250 self.cleanup()
251 except Exception as e:
252 logger.error("runbuilds: Error in check_dead_builds %s" % e)
253
183 def handle(self, **options): 254 def handle(self, **options):
184 pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."), 255 pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."),
185 ".runbuilds.pid") 256 ".runbuilds.pid")
@@ -187,10 +258,18 @@ class Command(BaseCommand):
187 with open(pidfile_path, 'w') as pidfile: 258 with open(pidfile_path, 'w') as pidfile:
188 pidfile.write("%s" % os.getpid()) 259 pidfile.write("%s" % os.getpid())
189 260
261 # Clean up any stale/failed builds from previous Toaster run
190 self.runbuild() 262 self.runbuild()
191 263
192 signal.signal(signal.SIGUSR1, lambda sig, frame: None) 264 signal.signal(signal.SIGUSR1, lambda sig, frame: None)
193 265
194 while True: 266 while True:
195 signal.pause() 267 sigset = signal.sigtimedwait([signal.SIGUSR1], 5)
196 self.runbuild() 268 if sigset:
269 for sig in sigset:
270 # Consume each captured pending event
271 self.runbuild()
272 else:
273 # Check for build exceptions
274 self.check_dead_builds()
275
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0008_models_bigautofield.py b/bitbake/lib/toaster/bldcontrol/migrations/0008_models_bigautofield.py
new file mode 100644
index 0000000000..45b477d02c
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0008_models_bigautofield.py
@@ -0,0 +1,48 @@
1# Generated by Django 3.2.12 on 2022-03-06 03:28
2
3from django.db import migrations, models
4
5
6class Migration(migrations.Migration):
7
8 dependencies = [
9 ('bldcontrol', '0007_brlayers_optional_gitinfo'),
10 ]
11
12 operations = [
13 migrations.AlterField(
14 model_name='brbitbake',
15 name='id',
16 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 ),
18 migrations.AlterField(
19 model_name='brerror',
20 name='id',
21 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
22 ),
23 migrations.AlterField(
24 model_name='brlayer',
25 name='id',
26 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
27 ),
28 migrations.AlterField(
29 model_name='brtarget',
30 name='id',
31 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
32 ),
33 migrations.AlterField(
34 model_name='brvariable',
35 name='id',
36 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
37 ),
38 migrations.AlterField(
39 model_name='buildenvironment',
40 name='id',
41 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
42 ),
43 migrations.AlterField(
44 model_name='buildrequest',
45 name='id',
46 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
47 ),
48 ]
diff --git a/bitbake/lib/toaster/bldcontrol/models.py b/bitbake/lib/toaster/bldcontrol/models.py
index c2f302da24..42750e7180 100644
--- a/bitbake/lib/toaster/bldcontrol/models.py
+++ b/bitbake/lib/toaster/bldcontrol/models.py
@@ -4,7 +4,7 @@
4 4
5from __future__ import unicode_literals 5from __future__ import unicode_literals
6from django.db import models 6from django.db import models
7from django.utils.encoding import force_text 7from django.utils.encoding import force_str
8from orm.models import Project, Build, Layer_Version 8from orm.models import Project, Build, Layer_Version
9 9
10import logging 10import logging
@@ -124,7 +124,7 @@ class BuildRequest(models.Model):
124 return self.brvariable_set.get(name="MACHINE").value 124 return self.brvariable_set.get(name="MACHINE").value
125 125
126 def __str__(self): 126 def __str__(self):
127 return force_text('%s %s' % (self.project, self.get_state_display())) 127 return force_str('%s %s' % (self.project, self.get_state_display()))
128 128
129# These tables specify the settings for running an actual build. 129# These tables specify the settings for running an actual build.
130# They MUST be kept in sync with the tables in orm.models.Project* 130# They MUST be kept in sync with the tables in orm.models.Project*
diff --git a/bitbake/lib/toaster/logs/.gitignore b/bitbake/lib/toaster/logs/.gitignore
new file mode 100644
index 0000000000..e5ebf25a49
--- /dev/null
+++ b/bitbake/lib/toaster/logs/.gitignore
@@ -0,0 +1 @@
*.log*
diff --git a/bitbake/lib/toaster/manage.py b/bitbake/lib/toaster/manage.py
index ae32619d12..f8de49c264 100755
--- a/bitbake/lib/toaster/manage.py
+++ b/bitbake/lib/toaster/manage.py
@@ -1,5 +1,7 @@
1#!/usr/bin/env python3 1#!/usr/bin/env python3
2# 2#
3# Copyright BitBake Contributors
4#
3# SPDX-License-Identifier: GPL-2.0-only 5# SPDX-License-Identifier: GPL-2.0-only
4# 6#
5 7
diff --git a/bitbake/lib/toaster/orm/fixtures/README b/bitbake/lib/toaster/orm/fixtures/README
index 1b1c660aac..7cd745e26b 100644
--- a/bitbake/lib/toaster/orm/fixtures/README
+++ b/bitbake/lib/toaster/orm/fixtures/README
@@ -27,4 +27,4 @@ Data can be provided in XML, JSON and if installed YAML formats.
27 27
28Use the django management command manage.py loaddata <your fixture file> 28Use the django management command manage.py loaddata <your fixture file>
29For further information see the Django command documentation at: 29For further information see the Django command documentation at:
30https://docs.djangoproject.com/en/1.8/ref/django-admin/#django-admin-loaddata 30https://docs.djangoproject.com/en/3.2/ref/django-admin/#django-admin-loaddata
diff --git a/bitbake/lib/toaster/orm/fixtures/check_fixtures.py b/bitbake/lib/toaster/orm/fixtures/check_fixtures.py
new file mode 100755
index 0000000000..ae3722e0f6
--- /dev/null
+++ b/bitbake/lib/toaster/orm/fixtures/check_fixtures.py
@@ -0,0 +1,38 @@
1#!/usr/bin/env python3
2#
3# Copyright (C) 2025 Linux Foundation
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import json
8import urllib.request
9
10import gen_fixtures as fixtures
11
12RELEASE_URL = "https://dashboard.yoctoproject.org/releases.json"
13
14with urllib.request.urlopen(RELEASE_URL) as response:
15 if response.getcode() == 200:
16 data = response.read().decode("utf-8")
17 releases = json.loads(data)
18 else:
19 print("Couldn't access %s: %s" % (RELEASE_URL, reponse.getcode()))
20 exit(1)
21
22
23# grab the recent release branches and add master, so we can ignore old branches
24active_releases = [
25 e["release_codename"].lower() for e in releases if e["series"] == "current"
26]
27active_releases.append("master")
28active_releases.append("head")
29
30fixtures_releases = [x[0].lower() for x in fixtures.current_releases]
31
32if set(active_releases) != set(fixtures_releases):
33 print("WARNING: Active releases don't match toaster configured releases, the difference is: %s" % set(active_releases).difference(set(fixtures_releases)))
34 print("Active releases: %s" % sorted(active_releases))
35 print("Toaster configured releases: %s" % sorted(fixtures_releases))
36else:
37 print("Success, configuration matches")
38
diff --git a/bitbake/lib/toaster/orm/fixtures/gen_fixtures.py b/bitbake/lib/toaster/orm/fixtures/gen_fixtures.py
new file mode 100755
index 0000000000..6201f679b9
--- /dev/null
+++ b/bitbake/lib/toaster/orm/fixtures/gen_fixtures.py
@@ -0,0 +1,451 @@
1#!/usr/bin/env python3
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# Generate Toaster Fixtures for 'poky.xml' and 'oe-core.xml'
6#
7# Copyright (C) 2022 Wind River Systems
8# SPDX-License-Identifier: GPL-2.0-only
9#
10# Edit the 'current_releases' table for each new release cycle
11#
12# Usage: ./get_fixtures --all
13#
14
15import os
16import sys
17import argparse
18
19verbose = False
20
21####################################
22# Releases
23#
24# https://wiki.yoctoproject.org/wiki/Releases
25#
26# NOTE: for the current releases table, it helps to keep continuing releases
27# in the same table positions since this minimizes the patch diff for review.
28# The order of the table does not matter since Toaster presents them sorted.
29#
30# Traditionally, the two most current releases are included in addition to the
31# 'master' branch and the local installation's 'HEAD'.
32# It is also policy to include all active LTS releases.
33#
34
35# [Codename, Yocto Project Version, Release Date, Current Version, Support Level, Poky Version, BitBake branch]
36current_releases = [
37 # Release slot #1
38 ['Scarthgap','5.0','April 2024','5.0.0 (April 2024)','Long Term Support (until April 2028)','','2.8'],
39 # Release slot #2 'local'
40 ['HEAD','HEAD','','Local Yocto Project','HEAD','','HEAD'],
41 # Release slot #3 'master'
42 ['Master','master','','Yocto Project master','master','','master'],
43 # Release slot #4
44 ['Whinlatter','5.3','October 2025','5.3.0 (October 2024)','Support for 7 months (until May 2026)','','2.14'],
45 ['Walnascar','5.2','April 2025','5.2.0 (April 2025)','Support for 7 months (until October 2025)','','2.12'],
46 #['Styhead','5.1','November 2024','5.1.0 (November 2024)','Support for 7 months (until May 2025)','','2.10'],
47 #['Nanbield','4.3','November 2023','4.3.0 (November 2023)','Support for 7 months (until May 2024)','','2.6'],
48 #['Mickledore','4.2','April 2023','4.2.0 (April 2023)','Support for 7 months (until October 2023)','','2.4'],
49 #['Langdale','4.1','October 2022','4.1.2 (January 2023)','Support for 7 months (until May 2023)','','2.2'],
50 ['Kirkstone','4.0','April 2022','4.0.8 (March 2023)','Stable - Long Term Support (until Apr. 2024)','','2.0'],
51 #['Honister','3.4','October 2021','3.4.2 (February 2022)','Support for 7 months (until May 2022)','26.0','1.52'],
52 #['Hardknott','3.3','April 2021','3.3.5 (March 2022)','Stable - Support for 13 months (until Apr. 2022)','25.0','1.50'],
53 #['Gatesgarth','3.2','Oct 2020','3.2.4 (May 2021)','EOL','24.0','1.48'],
54 #['Dunfell','3.1','April 2020','3.1.23 (February 2023)','Stable - Long Term Support (until Apr. 2024)','23.0','1.46'],
55]
56
57default_poky_layers = [
58 'openembedded-core',
59 'meta-poky',
60 'meta-yocto-bsp',
61]
62
63default_oe_core_layers = [
64 'openembedded-core',
65]
66
67####################################
68# Templates
69
70prolog_template = '''\
71<?xml version="1.0" encoding="utf-8"?>
72<django-objects version="1.0">
73 <!-- Set the project default value for DISTRO -->
74 <object model="orm.toastersetting" pk="1">
75 <field type="CharField" name="name">DEFCONF_DISTRO</field>
76 <field type="CharField" name="value">{{distro}}</field>
77 </object>
78'''
79
80#<!-- Bitbake versions which correspond to the metadata release -->')
81bitbakeversion_poky_template = '''\
82 <object model="orm.bitbakeversion" pk="{{bitbake_id}}">
83 <field type="CharField" name="name">{{name}}</field>
84 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
85 <field type="CharField" name="branch">{{branch}}</field>
86 <field type="CharField" name="dirpath">bitbake</field>
87 </object>
88'''
89bitbakeversion_oecore_template = '''\
90 <object model="orm.bitbakeversion" pk="{{bitbake_id}}">
91 <field type="CharField" name="name">{{name}}</field>
92 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
93 <field type="CharField" name="branch">{{bitbakeversion}}</field>
94 </object>
95'''
96
97# <!-- Releases available -->
98releases_available_template = '''\
99 <object model="orm.release" pk="{{ra_count}}">
100 <field type="CharField" name="name">{{name}}</field>
101 <field type="CharField" name="description">{{description}}</field>
102 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">{{ra_count}}</field>
103 <field type="CharField" name="branch_name">{{release}}</field>
104 <field type="TextField" name="helptext">Toaster will run your builds {{help_source}}.</field>
105 </object>
106'''
107
108# <!-- Default project layers for each release -->
109default_layers_template = '''\
110 <object model="orm.releasedefaultlayer" pk="{{rdl_count}}">
111 <field rel="ManyToOneRel" to="orm.release" name="release">{{release_id}}</field>
112 <field type="CharField" name="layer_name">{{layer}}</field>
113 </object>
114'''
115
116default_layers_preface = '''\
117 <!-- Default layers provided by poky
118 openembedded-core
119 meta-poky
120 meta-yocto-bsp
121 -->
122'''
123
124layer_poky_template = '''\
125 <object model="orm.layer" pk="{{layer_id}}">
126 <field type="CharField" name="name">{{layer}}</field>
127 <field type="CharField" name="layer_index_url"></field>
128 <field type="CharField" name="vcs_url">{{vcs_url}}</field>
129 <field type="CharField" name="vcs_web_url">{{vcs_web_url}}</field>
130 <field type="CharField" name="vcs_web_tree_base_url">{{vcs_web_tree_base_url}}</field>
131 <field type="CharField" name="vcs_web_file_base_url">{{vcs_web_file_base_url}}</field>
132 </object>
133'''
134
135layer_oe_core_template = '''\
136 <object model="orm.layer" pk="{{layer_id}}">
137 <field type="CharField" name="name">{{layer}}</field>
138 <field type="CharField" name="vcs_url">{{vcs_url}}</field>
139 <field type="CharField" name="vcs_web_url">{{vcs_web_url}}</field>
140 <field type="CharField" name="vcs_web_tree_base_url">{{vcs_web_tree_base_url}}</field>
141 <field type="CharField" name="vcs_web_file_base_url">{{vcs_web_file_base_url}}</field>
142 </object>
143'''
144
145layer_version_template = '''\
146 <object model="orm.layer_version" pk="{{lv_count}}">
147 <field rel="ManyToOneRel" to="orm.layer" name="layer">{{layer_id}}</field>
148 <field type="IntegerField" name="layer_source">0</field>
149 <field rel="ManyToOneRel" to="orm.release" name="release">{{release_id}}</field>
150 <field type="CharField" name="branch">{{branch}}</field>
151 <field type="CharField" name="dirpath">{{dirpath}}</field>
152 </object>
153'''
154
155layer_version_HEAD_template = '''\
156 <object model="orm.layer_version" pk="{{lv_count}}">
157 <field rel="ManyToOneRel" to="orm.layer" name="layer">{{layer_id}}</field>
158 <field type="IntegerField" name="layer_source">0</field>
159 <field rel="ManyToOneRel" to="orm.release" name="release">{{release_id}}</field>
160 <field type="CharField" name="branch">{{branch}}</field>
161 <field type="CharField" name="commit">{{commit}}</field>
162 <field type="CharField" name="dirpath">{{dirpath}}</field>
163 </object>
164'''
165
166layer_version_oe_core_template = '''\
167 <object model="orm.layer_version" pk="1">
168 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
169 <field rel="ManyToOneRel" to="orm.release" name="release">2</field>
170 <field type="CharField" name="local_path">OE-CORE-LAYER-DIR</field>
171 <field type="CharField" name="branch">HEAD</field>
172 <field type="CharField" name="dirpath">meta</field>
173 <field type="IntegerField" name="layer_source">0</field>
174 </object>
175'''
176
177epilog_template = '''\
178</django-objects>
179'''
180
181#################################
182# Helper Routines
183#
184
185def print_str(str,fd):
186 # Avoid extra newline at end
187 if str and (str[-1] == '\n'):
188 str = str[0:-1]
189 print(str,file=fd)
190
191def print_template(template,params,fd):
192 for line in template.split('\n'):
193 p = line.find('{{')
194 while p > 0:
195 q = line.find('}}')
196 key = line[p+2:q]
197 if key in params:
198 line = line[0:p] + params[key] + line[q+2:]
199 else:
200 line = line[0:p] + '?' + key + '?' + line[q+2:]
201 p = line.find('{{')
202 if line:
203 print(line,file=fd)
204
205#################################
206# Generate poky.xml
207#
208
209def generate_poky():
210 fd = open('poky.xml','w')
211
212 params = {}
213 params['distro'] = 'poky'
214 print_template(prolog_template,params,fd)
215 print_str('',fd)
216
217 print_str(' <!-- Bitbake versions which correspond to the metadata release -->',fd)
218 for i,release in enumerate(current_releases):
219 params = {}
220 params['release'] = release[0]
221 params['Release'] = release[0]
222 params['release_version'] = release[1]
223 if not (params['release'] in ('HEAD')): # 'master',
224 params['release'] = params['release'][0].lower() + params['release'][1:]
225 params['name'] = params['release']
226 params['bitbake_id'] = str(i+1)
227 params['branch'] = params['release']
228 print_template(bitbakeversion_poky_template,params,fd)
229 print_str('',fd)
230
231 print_str('',fd)
232 print_str(' <!-- Releases available -->',fd)
233 for i,release in enumerate(current_releases):
234 params = {}
235 params['release'] = release[0]
236 params['Release'] = release[0]
237 params['release_version'] = release[1]
238 if not (params['release'] in ('HEAD')): #'master',
239 params['release'] = params['release'][0].lower() + params['release'][1:]
240 params['h_release'] = '?h={{release}}'
241 params['name'] = params['release']
242 params['ra_count'] = str(i+1)
243 params['branch'] = params['release']
244
245 if 'HEAD' == params['release']:
246 params['help_source'] = 'with the version of the Yocto Project you have cloned or downloaded to your computer'
247 params['description'] = 'Local Yocto Project'
248 params['name'] = 'local'
249 else:
250 params['help_source'] = 'using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/{{h_release}}"&gt;Yocto Project {{Release}} branch&lt;/a&gt;'
251 params['description'] = 'Yocto Project {{release_version}} "{{Release}}"'
252 if 'master' == params['release']:
253 params['h_release'] = ''
254 params['description'] = 'Yocto Project master'
255
256 print_template(releases_available_template,params,fd)
257 print_str('',fd)
258
259 print_str(' <!-- Default project layers for each release -->',fd)
260 rdl_count = 1
261 for i,release in enumerate(current_releases):
262 for j,layer in enumerate(default_poky_layers):
263 params = {}
264 params['layer'] = layer
265 params['release'] = release[0]
266 params['Release'] = release[0]
267 params['release_version'] = release[1]
268 if not (params['release'] in ('master','HEAD')):
269 params['release'] = params['release'][0].lower() + params['release'][1:]
270 params['release_id'] = str(i+1)
271 params['rdl_count'] = str(rdl_count)
272 params['branch'] = params['release']
273 print_template(default_layers_template,params,fd)
274 rdl_count += 1
275 print_str('',fd)
276
277 print_str(default_layers_preface,fd)
278 lv_count = 1
279 for i,layer in enumerate(default_poky_layers):
280 params = {}
281 params['layer'] = layer
282 params['layer_id'] = str(i+1)
283 params['vcs_url'] = 'git://git.yoctoproject.org/poky'
284 params['vcs_web_url'] = 'https://git.yoctoproject.org/cgit/cgit.cgi/poky'
285 params['vcs_web_tree_base_url'] = 'https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%'
286 params['vcs_web_file_base_url'] = 'https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%'
287
288 if i:
289 print_str('',fd)
290 print_template(layer_poky_template,params,fd)
291 for j,release in enumerate(current_releases):
292 params['release'] = release[0]
293 params['Release'] = release[0]
294 params['release_version'] = release[1]
295 if not (params['release'] in ('master','HEAD')):
296 params['release'] = params['release'][0].lower() + params['release'][1:]
297 params['release_id'] = str(j+1)
298 params['lv_count'] = str(lv_count)
299 params['branch'] = params['release']
300 params['commit'] = params['release']
301
302 params['dirpath'] = params['layer']
303 if params['layer'] in ('openembedded-core'): #'openembedded-core',
304 params['dirpath'] = 'meta'
305
306 if 'HEAD' == params['release']:
307 print_template(layer_version_HEAD_template,params,fd)
308 else:
309 print_template(layer_version_template,params,fd)
310 lv_count += 1
311
312 print_str(epilog_template,fd)
313 fd.close()
314
315#################################
316# Generate oe-core.xml
317#
318
319def generate_oe_core():
320 fd = open('oe-core.xml','w')
321
322 params = {}
323 params['distro'] = 'nodistro'
324 print_template(prolog_template,params,fd)
325 print_str('',fd)
326
327 print_str(' <!-- Bitbake versions which correspond to the metadata release -->',fd)
328 for i,release in enumerate(current_releases):
329 params = {}
330 params['release'] = release[0]
331 params['Release'] = release[0]
332 params['bitbakeversion'] = release[6]
333 params['release_version'] = release[1]
334 if not (params['release'] in ('HEAD')): # 'master',
335 params['release'] = params['release'][0].lower() + params['release'][1:]
336 params['name'] = params['release']
337 params['bitbake_id'] = str(i+1)
338 params['branch'] = params['release']
339 print_template(bitbakeversion_oecore_template,params,fd)
340 print_str('',fd)
341
342 print_str(' <!-- Releases available -->',fd)
343 for i,release in enumerate(current_releases):
344 params = {}
345 params['release'] = release[0]
346 params['Release'] = release[0]
347 params['release_version'] = release[1]
348 if not (params['release'] in ('HEAD')): #'master',
349 params['release'] = params['release'][0].lower() + params['release'][1:]
350 params['h_release'] = '?h={{release}}'
351 params['name'] = params['release']
352 params['ra_count'] = str(i+1)
353 params['branch'] = params['release']
354
355 if 'HEAD' == params['release']:
356 params['help_source'] = 'with the version of OpenEmbedded that you have cloned or downloaded to your computer'
357 params['description'] = 'Local Openembedded'
358 params['name'] = 'local'
359 else:
360 params['help_source'] = 'using the tip of the &lt;a href=\\"https://cgit.openembedded.org/openembedded-core/log/{{h_release}}\\"&gt;OpenEmbedded {{Release}}&lt;/a&gt; branch'
361 params['description'] = 'Openembedded {{Release}}'
362 if 'master' == params['release']:
363 params['h_release'] = ''
364 params['description'] = 'OpenEmbedded core master'
365 params['Release'] = params['release']
366
367 print_template(releases_available_template,params,fd)
368 print_str('',fd)
369
370 print_str(' <!-- Default layers for each release -->',fd)
371 rdl_count = 1
372 for i,release in enumerate(current_releases):
373 for j,layer in enumerate(default_oe_core_layers):
374 params = {}
375 params['layer'] = layer
376 params['release'] = release[0]
377 params['Release'] = release[0]
378 params['release_version'] = release[1]
379 if not (params['release'] in ('master','HEAD')):
380 params['release'] = params['release'][0].lower() + params['release'][1:]
381 params['release_id'] = str(i+1)
382 params['rdl_count'] = str(rdl_count)
383 params['branch'] = params['release']
384 print_template(default_layers_template,params,fd)
385 rdl_count += 1
386 print_str('',fd)
387
388 print_str('',fd)
389 print_str(' <!-- Layer for the Local release -->',fd)
390 lv_count = 1
391 for i,layer in enumerate(default_oe_core_layers):
392 params = {}
393 params['layer'] = layer
394 params['layer_id'] = str(i+1)
395 params['vcs_url'] = 'git://git.openembedded.org/openembedded-core'
396 params['vcs_web_url'] = 'https://cgit.openembedded.org/openembedded-core'
397 params['vcs_web_tree_base_url'] = 'https://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%'
398 params['vcs_web_file_base_url'] = 'https://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%'
399 if i:
400 print_str('',fd)
401 print_template(layer_oe_core_template,params,fd)
402
403 print_template(layer_version_oe_core_template,params,fd)
404 print_str('',fd)
405
406 print_str(epilog_template,fd)
407 fd.close()
408
409#################################
410# Help
411#
412
413def list_releases():
414 print("Release ReleaseVer BitbakeVer Support Level")
415 print("========== =========== ========== ==============================================")
416 for release in current_releases:
417 print("%10s %10s %11s %s" % (release[0],release[1],release[6],release[4]))
418
419#################################
420# main
421#
422
423def main(argv):
424 global verbose
425
426 parser = argparse.ArgumentParser(description='gen_fixtures.py: table generate the fixture files')
427 parser.add_argument('--poky', '-p', action='store_const', const='poky', dest='command', help='Generate the poky.xml file')
428 parser.add_argument('--oe-core', '-o', action='store_const', const='oe_core', dest='command', help='Generate the oe-core.xml file')
429 parser.add_argument('--all', '-a', action='store_const', const='all', dest='command', help='Generate all fixture files')
430 parser.add_argument('--list', '-l', action='store_const', const='list', dest='command', help='List the release table')
431 parser.add_argument('--verbose', '-v', action='store_true', dest='verbose', help='Enable verbose debugging output')
432 args = parser.parse_args()
433
434 verbose = args.verbose
435 if 'poky' == args.command:
436 generate_poky()
437 elif 'oe_core' == args.command:
438 generate_oe_core()
439 elif 'all' == args.command:
440 generate_poky()
441 generate_oe_core()
442 elif 'all' == args.command:
443 list_releases()
444 elif 'list' == args.command:
445 list_releases()
446
447 else:
448 print("No command for 'gen_fixtures.py' selected")
449
450if __name__ == '__main__':
451 main(sys.argv[1:])
diff --git a/bitbake/lib/toaster/orm/fixtures/oe-core.xml b/bitbake/lib/toaster/orm/fixtures/oe-core.xml
index 026d94869a..264231d139 100644
--- a/bitbake/lib/toaster/orm/fixtures/oe-core.xml
+++ b/bitbake/lib/toaster/orm/fixtures/oe-core.xml
@@ -8,9 +8,9 @@
8 8
9 <!-- Bitbake versions which correspond to the metadata release --> 9 <!-- Bitbake versions which correspond to the metadata release -->
10 <object model="orm.bitbakeversion" pk="1"> 10 <object model="orm.bitbakeversion" pk="1">
11 <field type="CharField" name="name">dunfell</field> 11 <field type="CharField" name="name">scarthgap</field>
12 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field> 12 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
13 <field type="CharField" name="branch">1.46</field> 13 <field type="CharField" name="branch">2.8</field>
14 </object> 14 </object>
15 <object model="orm.bitbakeversion" pk="2"> 15 <object model="orm.bitbakeversion" pk="2">
16 <field type="CharField" name="name">HEAD</field> 16 <field type="CharField" name="name">HEAD</field>
@@ -23,18 +23,33 @@
23 <field type="CharField" name="branch">master</field> 23 <field type="CharField" name="branch">master</field>
24 </object> 24 </object>
25 <object model="orm.bitbakeversion" pk="4"> 25 <object model="orm.bitbakeversion" pk="4">
26 <field type="CharField" name="name">gatesgarth</field> 26 <field type="CharField" name="name">whinlatter</field>
27 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field> 27 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
28 <field type="CharField" name="branch">1.48</field> 28 <field type="CharField" name="branch">2.14</field>
29 </object>
30 <object model="orm.bitbakeversion" pk="5">
31 <field type="CharField" name="name">walnascar</field>
32 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
33 <field type="CharField" name="branch">2.12</field>
34 </object>
35 <object model="orm.bitbakeversion" pk="6">
36 <field type="CharField" name="name">styhead</field>
37 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
38 <field type="CharField" name="branch">2.10</field>
39 </object>
40 <object model="orm.bitbakeversion" pk="7">
41 <field type="CharField" name="name">kirkstone</field>
42 <field type="CharField" name="giturl">git://git.openembedded.org/bitbake</field>
43 <field type="CharField" name="branch">2.0</field>
29 </object> 44 </object>
30 45
31 <!-- Releases available --> 46 <!-- Releases available -->
32 <object model="orm.release" pk="1"> 47 <object model="orm.release" pk="1">
33 <field type="CharField" name="name">dunfell</field> 48 <field type="CharField" name="name">scarthgap</field>
34 <field type="CharField" name="description">Openembedded Dunfell</field> 49 <field type="CharField" name="description">Openembedded Scarthgap</field>
35 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">1</field> 50 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">1</field>
36 <field type="CharField" name="branch_name">dunfell</field> 51 <field type="CharField" name="branch_name">scarthgap</field>
37 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"http://cgit.openembedded.org/openembedded-core/log/?h=dunfell\"&gt;OpenEmbedded Dunfell&lt;/a&gt; branch.</field> 52 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/?h=scarthgap\"&gt;OpenEmbedded Scarthgap&lt;/a&gt; branch.</field>
38 </object> 53 </object>
39 <object model="orm.release" pk="2"> 54 <object model="orm.release" pk="2">
40 <field type="CharField" name="name">local</field> 55 <field type="CharField" name="name">local</field>
@@ -48,14 +63,35 @@
48 <field type="CharField" name="description">OpenEmbedded core master</field> 63 <field type="CharField" name="description">OpenEmbedded core master</field>
49 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">3</field> 64 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">3</field>
50 <field type="CharField" name="branch_name">master</field> 65 <field type="CharField" name="branch_name">master</field>
51 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"http://cgit.openembedded.org/openembedded-core/log/\"&gt;OpenEmbedded master&lt;/a&gt; branch.</field> 66 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/\"&gt;OpenEmbedded master&lt;/a&gt; branch.</field>
52 </object> 67 </object>
53 <object model="orm.release" pk="4"> 68 <object model="orm.release" pk="4">
54 <field type="CharField" name="name">gatesgarth</field> 69 <field type="CharField" name="name">whinlatter</field>
55 <field type="CharField" name="description">Openembedded Gatesgarth</field> 70 <field type="CharField" name="description">Openembedded Whinlatter</field>
56 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">4</field> 71 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">4</field>
57 <field type="CharField" name="branch_name">gatesgarth</field> 72 <field type="CharField" name="branch_name">whinlatter</field>
58 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"http://cgit.openembedded.org/openembedded-core/log/?h=gatesgarth\"&gt;OpenEmbedded Gatesgarth&lt;/a&gt; branch.</field> 73 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/?h=whinlatter\"&gt;OpenEmbedded Whinlatter&lt;/a&gt; branch.</field>
74 </object>
75 <object model="orm.release" pk="5">
76 <field type="CharField" name="name">walnascar</field>
77 <field type="CharField" name="description">Openembedded Walnascar</field>
78 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">5</field>
79 <field type="CharField" name="branch_name">walnascar</field>
80 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/?h=walnascar\"&gt;OpenEmbedded Walnascar&lt;/a&gt; branch.</field>
81 </object>
82 <object model="orm.release" pk="6">
83 <field type="CharField" name="name">styhead</field>
84 <field type="CharField" name="description">Openembedded Styhead</field>
85 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">6</field>
86 <field type="CharField" name="branch_name">styhead</field>
87 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/?h=styhead\"&gt;OpenEmbedded Styhead&lt;/a&gt; branch.</field>
88 </object>
89 <object model="orm.release" pk="7">
90 <field type="CharField" name="name">kirkstone</field>
91 <field type="CharField" name="description">Openembedded Kirkstone</field>
92 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">7</field>
93 <field type="CharField" name="branch_name">kirkstone</field>
94 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href=\"https://cgit.openembedded.org/openembedded-core/log/?h=kirkstone\"&gt;OpenEmbedded Kirkstone&lt;/a&gt; branch.</field>
59 </object> 95 </object>
60 96
61 <!-- Default layers for each release --> 97 <!-- Default layers for each release -->
@@ -75,15 +111,27 @@
75 <field rel="ManyToOneRel" to="orm.release" name="release">4</field> 111 <field rel="ManyToOneRel" to="orm.release" name="release">4</field>
76 <field type="CharField" name="layer_name">openembedded-core</field> 112 <field type="CharField" name="layer_name">openembedded-core</field>
77 </object> 113 </object>
114 <object model="orm.releasedefaultlayer" pk="5">
115 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
116 <field type="CharField" name="layer_name">openembedded-core</field>
117 </object>
118 <object model="orm.releasedefaultlayer" pk="6">
119 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
120 <field type="CharField" name="layer_name">openembedded-core</field>
121 </object>
122 <object model="orm.releasedefaultlayer" pk="7">
123 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
124 <field type="CharField" name="layer_name">openembedded-core</field>
125 </object>
78 126
79 127
80 <!-- Layer for the Local release --> 128 <!-- Layer for the Local release -->
81 <object model="orm.layer" pk="1"> 129 <object model="orm.layer" pk="1">
82 <field type="CharField" name="name">openembedded-core</field> 130 <field type="CharField" name="name">openembedded-core</field>
83 <field type="CharField" name="vcs_url">git://git.openembedded.org/openembedded-core</field> 131 <field type="CharField" name="vcs_url">git://git.openembedded.org/openembedded-core</field>
84 <field type="CharField" name="vcs_web_url">http://cgit.openembedded.org/openembedded-core</field> 132 <field type="CharField" name="vcs_web_url">https://cgit.openembedded.org/openembedded-core</field>
85 <field type="CharField" name="vcs_web_tree_base_url">http://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%</field> 133 <field type="CharField" name="vcs_web_tree_base_url">https://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%</field>
86 <field type="CharField" name="vcs_web_file_base_url">http://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%</field> 134 <field type="CharField" name="vcs_web_file_base_url">https://cgit.openembedded.org/openembedded-core/tree/%path%?h=%branch%</field>
87 </object> 135 </object>
88 <object model="orm.layer_version" pk="1"> 136 <object model="orm.layer_version" pk="1">
89 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field> 137 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
diff --git a/bitbake/lib/toaster/orm/fixtures/poky.xml b/bitbake/lib/toaster/orm/fixtures/poky.xml
index a468a54c49..6cf4f0687a 100644
--- a/bitbake/lib/toaster/orm/fixtures/poky.xml
+++ b/bitbake/lib/toaster/orm/fixtures/poky.xml
@@ -8,9 +8,9 @@
8 8
9 <!-- Bitbake versions which correspond to the metadata release --> 9 <!-- Bitbake versions which correspond to the metadata release -->
10 <object model="orm.bitbakeversion" pk="1"> 10 <object model="orm.bitbakeversion" pk="1">
11 <field type="CharField" name="name">dunfell</field> 11 <field type="CharField" name="name">scarthgap</field>
12 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field> 12 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
13 <field type="CharField" name="branch">dunfell</field> 13 <field type="CharField" name="branch">scarthgap</field>
14 <field type="CharField" name="dirpath">bitbake</field> 14 <field type="CharField" name="dirpath">bitbake</field>
15 </object> 15 </object>
16 <object model="orm.bitbakeversion" pk="2"> 16 <object model="orm.bitbakeversion" pk="2">
@@ -26,20 +26,38 @@
26 <field type="CharField" name="dirpath">bitbake</field> 26 <field type="CharField" name="dirpath">bitbake</field>
27 </object> 27 </object>
28 <object model="orm.bitbakeversion" pk="4"> 28 <object model="orm.bitbakeversion" pk="4">
29 <field type="CharField" name="name">gatesgarth</field> 29 <field type="CharField" name="name">whinlatter</field>
30 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field> 30 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
31 <field type="CharField" name="branch">gatesgarth</field> 31 <field type="CharField" name="branch">whinlatter</field>
32 <field type="CharField" name="dirpath">bitbake</field>
33 </object>
34 <object model="orm.bitbakeversion" pk="5">
35 <field type="CharField" name="name">walnascar</field>
36 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
37 <field type="CharField" name="branch">walnascar</field>
38 <field type="CharField" name="dirpath">bitbake</field>
39 </object>
40 <object model="orm.bitbakeversion" pk="6">
41 <field type="CharField" name="name">styhead</field>
42 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
43 <field type="CharField" name="branch">styhead</field>
44 <field type="CharField" name="dirpath">bitbake</field>
45 </object>
46 <object model="orm.bitbakeversion" pk="7">
47 <field type="CharField" name="name">kirkstone</field>
48 <field type="CharField" name="giturl">git://git.yoctoproject.org/poky</field>
49 <field type="CharField" name="branch">kirkstone</field>
32 <field type="CharField" name="dirpath">bitbake</field> 50 <field type="CharField" name="dirpath">bitbake</field>
33 </object> 51 </object>
34 52
35 53
36 <!-- Releases available --> 54 <!-- Releases available -->
37 <object model="orm.release" pk="1"> 55 <object model="orm.release" pk="1">
38 <field type="CharField" name="name">dunfell</field> 56 <field type="CharField" name="name">scarthgap</field>
39 <field type="CharField" name="description">Yocto Project 3.1 "Dunfell"</field> 57 <field type="CharField" name="description">Yocto Project 5.0 "Scarthgap"</field>
40 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">1</field> 58 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">1</field>
41 <field type="CharField" name="branch_name">dunfell</field> 59 <field type="CharField" name="branch_name">scarthgap</field>
42 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="http://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=dunfell"&gt;Yocto Project Dunfell branch&lt;/a&gt;.</field> 60 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=scarthgap"&gt;Yocto Project Scarthgap branch&lt;/a&gt;.</field>
43 </object> 61 </object>
44 <object model="orm.release" pk="2"> 62 <object model="orm.release" pk="2">
45 <field type="CharField" name="name">local</field> 63 <field type="CharField" name="name">local</field>
@@ -53,14 +71,35 @@
53 <field type="CharField" name="description">Yocto Project master</field> 71 <field type="CharField" name="description">Yocto Project master</field>
54 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">3</field> 72 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">3</field>
55 <field type="CharField" name="branch_name">master</field> 73 <field type="CharField" name="branch_name">master</field>
56 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="http://git.yoctoproject.org/cgit/cgit.cgi/poky/log/"&gt;Yocto Project Master branch&lt;/a&gt;.</field> 74 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/"&gt;Yocto Project Master branch&lt;/a&gt;.</field>
57 </object> 75 </object>
58 <object model="orm.release" pk="4"> 76 <object model="orm.release" pk="4">
59 <field type="CharField" name="name">gatesgarth</field> 77 <field type="CharField" name="name">whinlatter</field>
60 <field type="CharField" name="description">Yocto Project 3.2 "Gatesgarth"</field> 78 <field type="CharField" name="description">Yocto Project 5.3 "Whinlatter"</field>
61 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">4</field> 79 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">4</field>
62 <field type="CharField" name="branch_name">gatesgarth</field> 80 <field type="CharField" name="branch_name">whinlatter</field>
63 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="http://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=gatesgarth"&gt;Yocto Project Gatesgarth branch&lt;/a&gt;.</field> 81 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=whinlatter"&gt;Yocto Project Whinlatter branch&lt;/a&gt;.</field>
82 </object>
83 <object model="orm.release" pk="5">
84 <field type="CharField" name="name">walnascar</field>
85 <field type="CharField" name="description">Yocto Project 5.2 "Walnascar"</field>
86 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">5</field>
87 <field type="CharField" name="branch_name">walnascar</field>
88 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=walnascar"&gt;Yocto Project Walnascar branch&lt;/a&gt;.</field>
89 </object>
90 <object model="orm.release" pk="6">
91 <field type="CharField" name="name">styhead</field>
92 <field type="CharField" name="description">Yocto Project 5.1 "Styhead"</field>
93 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">6</field>
94 <field type="CharField" name="branch_name">styhead</field>
95 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=styhead"&gt;Yocto Project Styhead branch&lt;/a&gt;.</field>
96 </object>
97 <object model="orm.release" pk="7">
98 <field type="CharField" name="name">kirkstone</field>
99 <field type="CharField" name="description">Yocto Project 4.0 "Kirkstone"</field>
100 <field rel="ManyToOneRel" to="orm.bitbakeversion" name="bitbake_version">7</field>
101 <field type="CharField" name="branch_name">kirkstone</field>
102 <field type="TextField" name="helptext">Toaster will run your builds using the tip of the &lt;a href="https://git.yoctoproject.org/cgit/cgit.cgi/poky/log/?h=kirkstone"&gt;Yocto Project Kirkstone branch&lt;/a&gt;.</field>
64 </object> 103 </object>
65 104
66 <!-- Default project layers for each release --> 105 <!-- Default project layers for each release -->
@@ -112,6 +151,42 @@
112 <field rel="ManyToOneRel" to="orm.release" name="release">4</field> 151 <field rel="ManyToOneRel" to="orm.release" name="release">4</field>
113 <field type="CharField" name="layer_name">meta-yocto-bsp</field> 152 <field type="CharField" name="layer_name">meta-yocto-bsp</field>
114 </object> 153 </object>
154 <object model="orm.releasedefaultlayer" pk="13">
155 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
156 <field type="CharField" name="layer_name">openembedded-core</field>
157 </object>
158 <object model="orm.releasedefaultlayer" pk="14">
159 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
160 <field type="CharField" name="layer_name">meta-poky</field>
161 </object>
162 <object model="orm.releasedefaultlayer" pk="15">
163 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
164 <field type="CharField" name="layer_name">meta-yocto-bsp</field>
165 </object>
166 <object model="orm.releasedefaultlayer" pk="16">
167 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
168 <field type="CharField" name="layer_name">openembedded-core</field>
169 </object>
170 <object model="orm.releasedefaultlayer" pk="17">
171 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
172 <field type="CharField" name="layer_name">meta-poky</field>
173 </object>
174 <object model="orm.releasedefaultlayer" pk="18">
175 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
176 <field type="CharField" name="layer_name">meta-yocto-bsp</field>
177 </object>
178 <object model="orm.releasedefaultlayer" pk="19">
179 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
180 <field type="CharField" name="layer_name">openembedded-core</field>
181 </object>
182 <object model="orm.releasedefaultlayer" pk="20">
183 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
184 <field type="CharField" name="layer_name">meta-poky</field>
185 </object>
186 <object model="orm.releasedefaultlayer" pk="21">
187 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
188 <field type="CharField" name="layer_name">meta-yocto-bsp</field>
189 </object>
115 190
116 <!-- Default layers provided by poky 191 <!-- Default layers provided by poky
117 openembedded-core 192 openembedded-core
@@ -122,15 +197,15 @@
122 <field type="CharField" name="name">openembedded-core</field> 197 <field type="CharField" name="name">openembedded-core</field>
123 <field type="CharField" name="layer_index_url"></field> 198 <field type="CharField" name="layer_index_url"></field>
124 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field> 199 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field>
125 <field type="CharField" name="vcs_web_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky</field> 200 <field type="CharField" name="vcs_web_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky</field>
126 <field type="CharField" name="vcs_web_tree_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 201 <field type="CharField" name="vcs_web_tree_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
127 <field type="CharField" name="vcs_web_file_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 202 <field type="CharField" name="vcs_web_file_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
128 </object> 203 </object>
129 <object model="orm.layer_version" pk="1"> 204 <object model="orm.layer_version" pk="1">
130 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field> 205 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
131 <field type="IntegerField" name="layer_source">0</field> 206 <field type="IntegerField" name="layer_source">0</field>
132 <field rel="ManyToOneRel" to="orm.release" name="release">1</field> 207 <field rel="ManyToOneRel" to="orm.release" name="release">1</field>
133 <field type="CharField" name="branch">dunfell</field> 208 <field type="CharField" name="branch">scarthgap</field>
134 <field type="CharField" name="dirpath">meta</field> 209 <field type="CharField" name="dirpath">meta</field>
135 </object> 210 </object>
136 <object model="orm.layer_version" pk="2"> 211 <object model="orm.layer_version" pk="2">
@@ -152,7 +227,28 @@
152 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field> 227 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
153 <field type="IntegerField" name="layer_source">0</field> 228 <field type="IntegerField" name="layer_source">0</field>
154 <field rel="ManyToOneRel" to="orm.release" name="release">4</field> 229 <field rel="ManyToOneRel" to="orm.release" name="release">4</field>
155 <field type="CharField" name="branch">gatesgarth</field> 230 <field type="CharField" name="branch">whinlatter</field>
231 <field type="CharField" name="dirpath">meta</field>
232 </object>
233 <object model="orm.layer_version" pk="5">
234 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
235 <field type="IntegerField" name="layer_source">0</field>
236 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
237 <field type="CharField" name="branch">walnascar</field>
238 <field type="CharField" name="dirpath">meta</field>
239 </object>
240 <object model="orm.layer_version" pk="6">
241 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
242 <field type="IntegerField" name="layer_source">0</field>
243 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
244 <field type="CharField" name="branch">styhead</field>
245 <field type="CharField" name="dirpath">meta</field>
246 </object>
247 <object model="orm.layer_version" pk="7">
248 <field rel="ManyToOneRel" to="orm.layer" name="layer">1</field>
249 <field type="IntegerField" name="layer_source">0</field>
250 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
251 <field type="CharField" name="branch">kirkstone</field>
156 <field type="CharField" name="dirpath">meta</field> 252 <field type="CharField" name="dirpath">meta</field>
157 </object> 253 </object>
158 254
@@ -160,18 +256,18 @@
160 <field type="CharField" name="name">meta-poky</field> 256 <field type="CharField" name="name">meta-poky</field>
161 <field type="CharField" name="layer_index_url"></field> 257 <field type="CharField" name="layer_index_url"></field>
162 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field> 258 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field>
163 <field type="CharField" name="vcs_web_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky</field> 259 <field type="CharField" name="vcs_web_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky</field>
164 <field type="CharField" name="vcs_web_tree_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 260 <field type="CharField" name="vcs_web_tree_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
165 <field type="CharField" name="vcs_web_file_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 261 <field type="CharField" name="vcs_web_file_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
166 </object> 262 </object>
167 <object model="orm.layer_version" pk="5"> 263 <object model="orm.layer_version" pk="8">
168 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field> 264 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
169 <field type="IntegerField" name="layer_source">0</field> 265 <field type="IntegerField" name="layer_source">0</field>
170 <field rel="ManyToOneRel" to="orm.release" name="release">1</field> 266 <field rel="ManyToOneRel" to="orm.release" name="release">1</field>
171 <field type="CharField" name="branch">dunfell</field> 267 <field type="CharField" name="branch">scarthgap</field>
172 <field type="CharField" name="dirpath">meta-poky</field> 268 <field type="CharField" name="dirpath">meta-poky</field>
173 </object> 269 </object>
174 <object model="orm.layer_version" pk="6"> 270 <object model="orm.layer_version" pk="9">
175 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field> 271 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
176 <field type="IntegerField" name="layer_source">0</field> 272 <field type="IntegerField" name="layer_source">0</field>
177 <field rel="ManyToOneRel" to="orm.release" name="release">2</field> 273 <field rel="ManyToOneRel" to="orm.release" name="release">2</field>
@@ -179,18 +275,39 @@
179 <field type="CharField" name="commit">HEAD</field> 275 <field type="CharField" name="commit">HEAD</field>
180 <field type="CharField" name="dirpath">meta-poky</field> 276 <field type="CharField" name="dirpath">meta-poky</field>
181 </object> 277 </object>
182 <object model="orm.layer_version" pk="7"> 278 <object model="orm.layer_version" pk="10">
183 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field> 279 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
184 <field type="IntegerField" name="layer_source">0</field> 280 <field type="IntegerField" name="layer_source">0</field>
185 <field rel="ManyToOneRel" to="orm.release" name="release">3</field> 281 <field rel="ManyToOneRel" to="orm.release" name="release">3</field>
186 <field type="CharField" name="branch">master</field> 282 <field type="CharField" name="branch">master</field>
187 <field type="CharField" name="dirpath">meta-poky</field> 283 <field type="CharField" name="dirpath">meta-poky</field>
188 </object> 284 </object>
189 <object model="orm.layer_version" pk="8"> 285 <object model="orm.layer_version" pk="11">
190 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field> 286 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
191 <field type="IntegerField" name="layer_source">0</field> 287 <field type="IntegerField" name="layer_source">0</field>
192 <field rel="ManyToOneRel" to="orm.release" name="release">4</field> 288 <field rel="ManyToOneRel" to="orm.release" name="release">4</field>
193 <field type="CharField" name="branch">gatesgarth</field> 289 <field type="CharField" name="branch">whinlatter</field>
290 <field type="CharField" name="dirpath">meta-poky</field>
291 </object>
292 <object model="orm.layer_version" pk="12">
293 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
294 <field type="IntegerField" name="layer_source">0</field>
295 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
296 <field type="CharField" name="branch">walnascar</field>
297 <field type="CharField" name="dirpath">meta-poky</field>
298 </object>
299 <object model="orm.layer_version" pk="13">
300 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
301 <field type="IntegerField" name="layer_source">0</field>
302 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
303 <field type="CharField" name="branch">styhead</field>
304 <field type="CharField" name="dirpath">meta-poky</field>
305 </object>
306 <object model="orm.layer_version" pk="14">
307 <field rel="ManyToOneRel" to="orm.layer" name="layer">2</field>
308 <field type="IntegerField" name="layer_source">0</field>
309 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
310 <field type="CharField" name="branch">kirkstone</field>
194 <field type="CharField" name="dirpath">meta-poky</field> 311 <field type="CharField" name="dirpath">meta-poky</field>
195 </object> 312 </object>
196 313
@@ -198,18 +315,18 @@
198 <field type="CharField" name="name">meta-yocto-bsp</field> 315 <field type="CharField" name="name">meta-yocto-bsp</field>
199 <field type="CharField" name="layer_index_url"></field> 316 <field type="CharField" name="layer_index_url"></field>
200 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field> 317 <field type="CharField" name="vcs_url">git://git.yoctoproject.org/poky</field>
201 <field type="CharField" name="vcs_web_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky</field> 318 <field type="CharField" name="vcs_web_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky</field>
202 <field type="CharField" name="vcs_web_tree_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 319 <field type="CharField" name="vcs_web_tree_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
203 <field type="CharField" name="vcs_web_file_base_url">http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field> 320 <field type="CharField" name="vcs_web_file_base_url">https://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/%path%?h=%branch%</field>
204 </object> 321 </object>
205 <object model="orm.layer_version" pk="9"> 322 <object model="orm.layer_version" pk="15">
206 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field> 323 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
207 <field type="IntegerField" name="layer_source">0</field> 324 <field type="IntegerField" name="layer_source">0</field>
208 <field rel="ManyToOneRel" to="orm.release" name="release">1</field> 325 <field rel="ManyToOneRel" to="orm.release" name="release">1</field>
209 <field type="CharField" name="branch">dunfell</field> 326 <field type="CharField" name="branch">scarthgap</field>
210 <field type="CharField" name="dirpath">meta-yocto-bsp</field> 327 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
211 </object> 328 </object>
212 <object model="orm.layer_version" pk="10"> 329 <object model="orm.layer_version" pk="16">
213 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field> 330 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
214 <field type="IntegerField" name="layer_source">0</field> 331 <field type="IntegerField" name="layer_source">0</field>
215 <field rel="ManyToOneRel" to="orm.release" name="release">2</field> 332 <field rel="ManyToOneRel" to="orm.release" name="release">2</field>
@@ -217,18 +334,39 @@
217 <field type="CharField" name="commit">HEAD</field> 334 <field type="CharField" name="commit">HEAD</field>
218 <field type="CharField" name="dirpath">meta-yocto-bsp</field> 335 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
219 </object> 336 </object>
220 <object model="orm.layer_version" pk="11"> 337 <object model="orm.layer_version" pk="17">
221 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field> 338 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
222 <field type="IntegerField" name="layer_source">0</field> 339 <field type="IntegerField" name="layer_source">0</field>
223 <field rel="ManyToOneRel" to="orm.release" name="release">3</field> 340 <field rel="ManyToOneRel" to="orm.release" name="release">3</field>
224 <field type="CharField" name="branch">master</field> 341 <field type="CharField" name="branch">master</field>
225 <field type="CharField" name="dirpath">meta-yocto-bsp</field> 342 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
226 </object> 343 </object>
227 <object model="orm.layer_version" pk="12"> 344 <object model="orm.layer_version" pk="18">
228 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field> 345 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
229 <field type="IntegerField" name="layer_source">0</field> 346 <field type="IntegerField" name="layer_source">0</field>
230 <field rel="ManyToOneRel" to="orm.release" name="release">4</field> 347 <field rel="ManyToOneRel" to="orm.release" name="release">4</field>
231 <field type="CharField" name="branch">gatesgarth</field> 348 <field type="CharField" name="branch">whinlatter</field>
349 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
350 </object>
351 <object model="orm.layer_version" pk="19">
352 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
353 <field type="IntegerField" name="layer_source">0</field>
354 <field rel="ManyToOneRel" to="orm.release" name="release">5</field>
355 <field type="CharField" name="branch">walnascar</field>
356 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
357 </object>
358 <object model="orm.layer_version" pk="20">
359 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
360 <field type="IntegerField" name="layer_source">0</field>
361 <field rel="ManyToOneRel" to="orm.release" name="release">6</field>
362 <field type="CharField" name="branch">styhead</field>
363 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
364 </object>
365 <object model="orm.layer_version" pk="21">
366 <field rel="ManyToOneRel" to="orm.layer" name="layer">3</field>
367 <field type="IntegerField" name="layer_source">0</field>
368 <field rel="ManyToOneRel" to="orm.release" name="release">7</field>
369 <field type="CharField" name="branch">kirkstone</field>
232 <field type="CharField" name="dirpath">meta-yocto-bsp</field> 370 <field type="CharField" name="dirpath">meta-yocto-bsp</field>
233 </object> 371 </object>
234</django-objects> 372</django-objects>
diff --git a/bitbake/lib/toaster/orm/fixtures/settings.xml b/bitbake/lib/toaster/orm/fixtures/settings.xml
index 78c0fdca7f..02c26a6974 100644
--- a/bitbake/lib/toaster/orm/fixtures/settings.xml
+++ b/bitbake/lib/toaster/orm/fixtures/settings.xml
@@ -12,14 +12,14 @@
12 </object> 12 </object>
13 <object model="orm.toastersetting" pk="4"> 13 <object model="orm.toastersetting" pk="4">
14 <field type="CharField" name="name">DEFCONF_MACHINE</field> 14 <field type="CharField" name="name">DEFCONF_MACHINE</field>
15 <field type="CharField" name="value">qemux86</field> 15 <field type="CharField" name="value">qemux86-64</field>
16 </object> 16 </object>
17 <object model="orm.toastersetting" pk="5"> 17 <object model="orm.toastersetting" pk="5">
18 <field type="CharField" name="name">DEFCONF_SSTATE_DIR</field> 18 <field type="CharField" name="name">DEFCONF_SSTATE_DIR</field>
19 <field type="CharField" name="value">${TOPDIR}/../sstate-cache</field> 19 <field type="CharField" name="value">${TOPDIR}/../sstate-cache</field>
20 </object> 20 </object>
21 <object model="orm.toastersetting" pk="6"> 21 <object model="orm.toastersetting" pk="6">
22 <field type="CharField" name="name">DEFCONF_IMAGE_INSTALL_append</field> 22 <field type="CharField" name="name">DEFCONF_IMAGE_INSTALL:append</field>
23 <field type="CharField" name="value"></field> 23 <field type="CharField" name="value"></field>
24 </object> 24 </object>
25 <object model="orm.toastersetting" pk="7"> 25 <object model="orm.toastersetting" pk="7">
diff --git a/bitbake/lib/toaster/orm/management/commands/lsupdates.py b/bitbake/lib/toaster/orm/management/commands/lsupdates.py
index 2fbd7be3d2..6d64830ebd 100644
--- a/bitbake/lib/toaster/orm/management/commands/lsupdates.py
+++ b/bitbake/lib/toaster/orm/management/commands/lsupdates.py
@@ -21,7 +21,7 @@ import threading
21import time 21import time
22logger = logging.getLogger("toaster") 22logger = logging.getLogger("toaster")
23 23
24DEFAULT_LAYERINDEX_SERVER = "http://layers.openembedded.org/layerindex/api/" 24DEFAULT_LAYERINDEX_SERVER = "https://layers.openembedded.org/layerindex/api/"
25 25
26# Add path to bitbake modules for layerindexlib 26# Add path to bitbake modules for layerindexlib
27# lib/toaster/orm/management/commands/lsupdates.py (abspath) 27# lib/toaster/orm/management/commands/lsupdates.py (abspath)
@@ -40,7 +40,7 @@ class Spinner(threading.Thread):
40 """ A simple progress spinner to indicate download/parsing is happening""" 40 """ A simple progress spinner to indicate download/parsing is happening"""
41 def __init__(self, *args, **kwargs): 41 def __init__(self, *args, **kwargs):
42 super(Spinner, self).__init__(*args, **kwargs) 42 super(Spinner, self).__init__(*args, **kwargs)
43 self.setDaemon(True) 43 self.daemon = True
44 self.signal = True 44 self.signal = True
45 45
46 def run(self): 46 def run(self):
@@ -87,13 +87,13 @@ class Command(BaseCommand):
87 87
88 # update branches; only those that we already have names listed in the 88 # update branches; only those that we already have names listed in the
89 # Releases table 89 # Releases table
90 whitelist_branch_names = [rel.branch_name 90 allowed_branch_names = [rel.branch_name
91 for rel in Release.objects.all()] 91 for rel in Release.objects.all()]
92 if len(whitelist_branch_names) == 0: 92 if len(allowed_branch_names) == 0:
93 raise Exception("Failed to make list of branches to fetch") 93 raise Exception("Failed to make list of branches to fetch")
94 94
95 logger.info("Fetching metadata for %s", 95 logger.info("Fetching metadata for %s",
96 " ".join(whitelist_branch_names)) 96 " ".join(allowed_branch_names))
97 97
98 # We require a non-empty bb.data, but we can fake it with a dictionary 98 # We require a non-empty bb.data, but we can fake it with a dictionary
99 layerindex = layerindexlib.LayerIndex({"DUMMY" : "VALUE"}) 99 layerindex = layerindexlib.LayerIndex({"DUMMY" : "VALUE"})
@@ -101,8 +101,8 @@ class Command(BaseCommand):
101 http_progress = Spinner() 101 http_progress = Spinner()
102 http_progress.start() 102 http_progress.start()
103 103
104 if whitelist_branch_names: 104 if allowed_branch_names:
105 url_branches = ";branch=%s" % ','.join(whitelist_branch_names) 105 url_branches = ";branch=%s" % ','.join(allowed_branch_names)
106 else: 106 else:
107 url_branches = "" 107 url_branches = ""
108 layerindex.load_layerindex("%s%s" % (self.apiurl, url_branches)) 108 layerindex.load_layerindex("%s%s" % (self.apiurl, url_branches))
diff --git a/bitbake/lib/toaster/orm/migrations/0020_models_bigautofield.py b/bitbake/lib/toaster/orm/migrations/0020_models_bigautofield.py
new file mode 100644
index 0000000000..f19b5dddbc
--- /dev/null
+++ b/bitbake/lib/toaster/orm/migrations/0020_models_bigautofield.py
@@ -0,0 +1,173 @@
1# Generated by Django 3.2.12 on 2022-03-06 03:28
2
3from django.db import migrations, models
4
5
6class Migration(migrations.Migration):
7
8 dependencies = [
9 ('orm', '0019_django_2_2'),
10 ]
11
12 operations = [
13 migrations.AlterField(
14 model_name='bitbakeversion',
15 name='id',
16 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 ),
18 migrations.AlterField(
19 model_name='build',
20 name='id',
21 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
22 ),
23 migrations.AlterField(
24 model_name='distro',
25 name='id',
26 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
27 ),
28 migrations.AlterField(
29 model_name='helptext',
30 name='id',
31 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
32 ),
33 migrations.AlterField(
34 model_name='layer',
35 name='id',
36 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
37 ),
38 migrations.AlterField(
39 model_name='layer_version',
40 name='id',
41 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
42 ),
43 migrations.AlterField(
44 model_name='layerversiondependency',
45 name='id',
46 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
47 ),
48 migrations.AlterField(
49 model_name='logmessage',
50 name='id',
51 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
52 ),
53 migrations.AlterField(
54 model_name='machine',
55 name='id',
56 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
57 ),
58 migrations.AlterField(
59 model_name='package',
60 name='id',
61 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
62 ),
63 migrations.AlterField(
64 model_name='package_dependency',
65 name='id',
66 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
67 ),
68 migrations.AlterField(
69 model_name='package_file',
70 name='id',
71 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
72 ),
73 migrations.AlterField(
74 model_name='project',
75 name='id',
76 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
77 ),
78 migrations.AlterField(
79 model_name='projectlayer',
80 name='id',
81 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
82 ),
83 migrations.AlterField(
84 model_name='projecttarget',
85 name='id',
86 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
87 ),
88 migrations.AlterField(
89 model_name='projectvariable',
90 name='id',
91 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
92 ),
93 migrations.AlterField(
94 model_name='provides',
95 name='id',
96 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
97 ),
98 migrations.AlterField(
99 model_name='recipe',
100 name='id',
101 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
102 ),
103 migrations.AlterField(
104 model_name='recipe_dependency',
105 name='id',
106 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
107 ),
108 migrations.AlterField(
109 model_name='release',
110 name='id',
111 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
112 ),
113 migrations.AlterField(
114 model_name='releasedefaultlayer',
115 name='id',
116 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
117 ),
118 migrations.AlterField(
119 model_name='target',
120 name='id',
121 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
122 ),
123 migrations.AlterField(
124 model_name='target_file',
125 name='id',
126 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
127 ),
128 migrations.AlterField(
129 model_name='target_image_file',
130 name='id',
131 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
132 ),
133 migrations.AlterField(
134 model_name='target_installed_package',
135 name='id',
136 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
137 ),
138 migrations.AlterField(
139 model_name='targetkernelfile',
140 name='id',
141 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
142 ),
143 migrations.AlterField(
144 model_name='targetsdkfile',
145 name='id',
146 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
147 ),
148 migrations.AlterField(
149 model_name='task',
150 name='id',
151 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
152 ),
153 migrations.AlterField(
154 model_name='task_dependency',
155 name='id',
156 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
157 ),
158 migrations.AlterField(
159 model_name='toastersetting',
160 name='id',
161 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
162 ),
163 migrations.AlterField(
164 model_name='variable',
165 name='id',
166 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
167 ),
168 migrations.AlterField(
169 model_name='variablehistory',
170 name='id',
171 field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
172 ),
173 ]
diff --git a/bitbake/lib/toaster/orm/migrations/0021_eventlogsimports.py b/bitbake/lib/toaster/orm/migrations/0021_eventlogsimports.py
new file mode 100644
index 0000000000..328eb5753c
--- /dev/null
+++ b/bitbake/lib/toaster/orm/migrations/0021_eventlogsimports.py
@@ -0,0 +1,22 @@
1# Generated by Django 4.2.5 on 2023-11-23 18:44
2
3from django.db import migrations, models
4
5
6class Migration(migrations.Migration):
7
8 dependencies = [
9 ('orm', '0020_models_bigautofield'),
10 ]
11
12 operations = [
13 migrations.CreateModel(
14 name='EventLogsImports',
15 fields=[
16 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17 ('name', models.CharField(max_length=255)),
18 ('imported', models.BooleanField(default=False)),
19 ('build_id', models.IntegerField(blank=True, null=True)),
20 ],
21 ),
22 ]
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py
index 7f7e922ade..e2f488ed89 100644
--- a/bitbake/lib/toaster/orm/models.py
+++ b/bitbake/lib/toaster/orm/models.py
@@ -58,7 +58,6 @@ if 'sqlite' in settings.DATABASES['default']['ENGINE']:
58 return _base_insert(self, *args, **kwargs) 58 return _base_insert(self, *args, **kwargs)
59 QuerySet._insert = _insert 59 QuerySet._insert = _insert
60 60
61 from django.utils import six
62 def _create_object_from_params(self, lookup, params): 61 def _create_object_from_params(self, lookup, params):
63 """ 62 """
64 Tries to create an object using passed params. 63 Tries to create an object using passed params.
@@ -80,7 +79,6 @@ if 'sqlite' in settings.DATABASES['default']['ENGINE']:
80 # end of HACK 79 # end of HACK
81 80
82class GitURLValidator(validators.URLValidator): 81class GitURLValidator(validators.URLValidator):
83 import re
84 regex = re.compile( 82 regex = re.compile(
85 r'^(?:ssh|git|http|ftp)s?://' # http:// or https:// 83 r'^(?:ssh|git|http|ftp)s?://' # http:// or https://
86 r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain... 84 r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
@@ -108,7 +106,7 @@ class ToasterSetting(models.Model):
108 106
109 107
110class ProjectManager(models.Manager): 108class ProjectManager(models.Manager):
111 def create_project(self, name, release, existing_project=None): 109 def create_project(self, name, release, existing_project=None, imported=False):
112 if existing_project and (release is not None): 110 if existing_project and (release is not None):
113 prj = existing_project 111 prj = existing_project
114 prj.bitbake_version = release.bitbake_version 112 prj.bitbake_version = release.bitbake_version
@@ -135,19 +133,19 @@ class ProjectManager(models.Manager):
135 133
136 if release is None: 134 if release is None:
137 return prj 135 return prj
138 136 if not imported:
139 for rdl in release.releasedefaultlayer_set.all(): 137 for rdl in release.releasedefaultlayer_set.all():
140 lv = Layer_Version.objects.filter( 138 lv = Layer_Version.objects.filter(
141 layer__name=rdl.layer_name, 139 layer__name=rdl.layer_name,
142 release=release).first() 140 release=release).first()
143 141
144 if lv: 142 if lv:
145 ProjectLayer.objects.create(project=prj, 143 ProjectLayer.objects.create(project=prj,
146 layercommit=lv, 144 layercommit=lv,
147 optional=False) 145 optional=False)
148 else: 146 else:
149 logger.warning("Default project layer %s not found" % 147 logger.warning("Default project layer %s not found" %
150 rdl.layer_name) 148 rdl.layer_name)
151 149
152 return prj 150 return prj
153 151
@@ -1390,9 +1388,6 @@ class Machine(models.Model):
1390 return "Machine " + self.name + "(" + self.description + ")" 1388 return "Machine " + self.name + "(" + self.description + ")"
1391 1389
1392 1390
1393
1394
1395
1396class BitbakeVersion(models.Model): 1391class BitbakeVersion(models.Model):
1397 1392
1398 name = models.CharField(max_length=32, unique = True) 1393 name = models.CharField(max_length=32, unique = True)
@@ -1504,7 +1499,7 @@ class Layer_Version(models.Model):
1504 # code lifted, with adaptations, from the layerindex-web application 1499 # code lifted, with adaptations, from the layerindex-web application
1505 # https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/ 1500 # https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/
1506 def _handle_url_path(self, base_url, path): 1501 def _handle_url_path(self, base_url, path):
1507 import re, posixpath 1502 import posixpath
1508 if base_url: 1503 if base_url:
1509 if self.dirpath: 1504 if self.dirpath:
1510 if path: 1505 if path:
@@ -1717,9 +1712,9 @@ class CustomImageRecipe(Recipe):
1717 1712
1718 def generate_recipe_file_contents(self): 1713 def generate_recipe_file_contents(self):
1719 """Generate the contents for the recipe file.""" 1714 """Generate the contents for the recipe file."""
1720 # If we have no excluded packages we only need to _append 1715 # If we have no excluded packages we only need to :append
1721 if self.excludes_set.count() == 0: 1716 if self.excludes_set.count() == 0:
1722 packages_conf = "IMAGE_INSTALL_append = \" " 1717 packages_conf = "IMAGE_INSTALL:append = \" "
1723 1718
1724 for pkg in self.appends_set.all(): 1719 for pkg in self.appends_set.all():
1725 packages_conf += pkg.name+' ' 1720 packages_conf += pkg.name+' '
@@ -1734,7 +1729,7 @@ class CustomImageRecipe(Recipe):
1734 packages_conf += "\"" 1729 packages_conf += "\""
1735 1730
1736 base_recipe_path = self.get_base_recipe_file() 1731 base_recipe_path = self.get_base_recipe_file()
1737 if base_recipe_path: 1732 if base_recipe_path and os.path.isfile(base_recipe_path):
1738 base_recipe = open(base_recipe_path, 'r').read() 1733 base_recipe = open(base_recipe_path, 'r').read()
1739 else: 1734 else:
1740 # Pass back None to trigger error message to user 1735 # Pass back None to trigger error message to user
@@ -1854,6 +1849,8 @@ def signal_runbuilds():
1854 os.kill(int(pidf.read()), SIGUSR1) 1849 os.kill(int(pidf.read()), SIGUSR1)
1855 except FileNotFoundError: 1850 except FileNotFoundError:
1856 logger.info("Stopping existing runbuilds: no current process found") 1851 logger.info("Stopping existing runbuilds: no current process found")
1852 except ProcessLookupError:
1853 logger.warning("Stopping existing runbuilds: process lookup not found")
1857 1854
1858class Distro(models.Model): 1855class Distro(models.Model):
1859 search_allowed_fields = ["name", "description", "layer_version__layer__name"] 1856 search_allowed_fields = ["name", "description", "layer_version__layer__name"]
@@ -1870,6 +1867,15 @@ class Distro(models.Model):
1870 def __unicode__(self): 1867 def __unicode__(self):
1871 return "Distro " + self.name + "(" + self.description + ")" 1868 return "Distro " + self.name + "(" + self.description + ")"
1872 1869
1870class EventLogsImports(models.Model):
1871 name = models.CharField(max_length=255)
1872 imported = models.BooleanField(default=False)
1873 build_id = models.IntegerField(blank=True, null=True)
1874
1875 def __str__(self):
1876 return self.name
1877
1878
1873django.db.models.signals.post_save.connect(invalidate_cache) 1879django.db.models.signals.post_save.connect(invalidate_cache)
1874django.db.models.signals.post_delete.connect(invalidate_cache) 1880django.db.models.signals.post_delete.connect(invalidate_cache)
1875django.db.models.signals.m2m_changed.connect(invalidate_cache) 1881django.db.models.signals.m2m_changed.connect(invalidate_cache)
diff --git a/bitbake/lib/toaster/pytest.ini b/bitbake/lib/toaster/pytest.ini
new file mode 100644
index 0000000000..071c65fcd5
--- /dev/null
+++ b/bitbake/lib/toaster/pytest.ini
@@ -0,0 +1,16 @@
1# -- FILE: pytest.ini (or tox.ini)
2[pytest]
3# --create-db - force re creation of the test database
4# https://pytest-django.readthedocs.io/en/latest/database.html#create-db-force-re-creation-of-the-test-database
5
6# --html=report.html --self-contained-html
7# https://docs.pytest.org/en/latest/usage.html#creating-html-reports
8# https://pytest-html.readthedocs.io/en/latest/user_guide.html#creating-a-self-contained-report
9addopts = --create-db --html="Toaster Tests Report.html" --self-contained-html
10
11# Define environment variables using pytest-env
12# A pytest plugin that enables you to set environment variables in the pytest.ini file.
13# https://pypi.org/project/pytest-env/
14env =
15 TOASTER_BUILDSERVER=1
16 DJANGO_SETTINGS_MODULE=toastermain.settings_test
diff --git a/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
index 644d45fe58..6953541ab5 100644
--- a/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
+++ b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
@@ -19,11 +19,15 @@ import os
19import time 19import time
20import unittest 20import unittest
21 21
22import pytest
22from selenium import webdriver 23from selenium import webdriver
24from selenium.webdriver.support import expected_conditions as EC
23from selenium.webdriver.support.ui import WebDriverWait 25from selenium.webdriver.support.ui import WebDriverWait
26from selenium.webdriver.common.by import By
24from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 27from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
25from selenium.common.exceptions import NoSuchElementException, \ 28from selenium.common.exceptions import NoSuchElementException, \
26 StaleElementReferenceException, TimeoutException 29 StaleElementReferenceException, TimeoutException, \
30 SessionNotCreatedException, WebDriverException
27 31
28def create_selenium_driver(cls,browser='chrome'): 32def create_selenium_driver(cls,browser='chrome'):
29 # set default browser string based on env (if available) 33 # set default browser string based on env (if available)
@@ -32,9 +36,32 @@ def create_selenium_driver(cls,browser='chrome'):
32 browser = env_browser 36 browser = env_browser
33 37
34 if browser == 'chrome': 38 if browser == 'chrome':
35 return webdriver.Chrome( 39 options = webdriver.ChromeOptions()
36 service_args=["--verbose", "--log-path=selenium.log"] 40 options.add_argument('--headless')
37 ) 41 options.add_argument('--disable-infobars')
42 options.add_argument('--disable-dev-shm-usage')
43 options.add_argument('--no-sandbox')
44 options.add_argument('--remote-debugging-port=9222')
45 try:
46 return webdriver.Chrome(options=options)
47 except SessionNotCreatedException as e:
48 exit_message = "Halting tests prematurely to avoid cascading errors."
49 # check if chrome / chromedriver exists
50 chrome_path = os.popen("find ~/.cache/selenium/chrome/ -name 'chrome' -type f -print -quit").read().strip()
51 if not chrome_path:
52 pytest.exit(f"Failed to install/find chrome.\n{exit_message}")
53 chromedriver_path = os.popen("find ~/.cache/selenium/chromedriver/ -name 'chromedriver' -type f -print -quit").read().strip()
54 if not chromedriver_path:
55 pytest.exit(f"Failed to install/find chromedriver.\n{exit_message}")
56 # check if depends on each are fulfilled
57 depends_chrome = os.popen(f"ldd {chrome_path} | grep 'not found'").read().strip()
58 if depends_chrome:
59 pytest.exit(f"Missing chrome dependencies.\n{depends_chrome}\n{exit_message}")
60 depends_chromedriver = os.popen(f"ldd {chromedriver_path} | grep 'not found'").read().strip()
61 if depends_chromedriver:
62 pytest.exit(f"Missing chromedriver dependencies.\n{depends_chromedriver}\n{exit_message}")
63 # print original error otherwise
64 pytest.exit(f"Failed to start chromedriver.\n{e}\n{exit_message}")
38 elif browser == 'firefox': 65 elif browser == 'firefox':
39 return webdriver.Firefox() 66 return webdriver.Firefox()
40 elif browser == 'marionette': 67 elif browser == 'marionette':
@@ -63,10 +90,12 @@ class Wait(WebDriverWait):
63 Subclass of WebDriverWait with predetermined timeout and poll 90 Subclass of WebDriverWait with predetermined timeout and poll
64 frequency. Also deals with a wider variety of exceptions. 91 frequency. Also deals with a wider variety of exceptions.
65 """ 92 """
66 _TIMEOUT = 10 93 _TIMEOUT = 20
67 _POLL_FREQUENCY = 0.5 94 _POLL_FREQUENCY = 0.5
68 95
69 def __init__(self, driver): 96 def __init__(self, driver, timeout=_TIMEOUT, poll=_POLL_FREQUENCY):
97 self._TIMEOUT = timeout
98 self._POLL_FREQUENCY = poll
70 super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY) 99 super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY)
71 100
72 def until(self, method, message=''): 101 def until(self, method, message=''):
@@ -85,6 +114,9 @@ class Wait(WebDriverWait):
85 pass 114 pass
86 except StaleElementReferenceException: 115 except StaleElementReferenceException:
87 pass 116 pass
117 except WebDriverException:
118 # selenium.common.exceptions.WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"Node with given id does not belong to the document"}
119 pass
88 120
89 time.sleep(self._poll) 121 time.sleep(self._poll)
90 if time.time() > end_time: 122 if time.time() > end_time:
@@ -138,6 +170,8 @@ class SeleniumTestCaseBase(unittest.TestCase):
138 """ Clean up webdriver driver """ 170 """ Clean up webdriver driver """
139 171
140 cls.driver.quit() 172 cls.driver.quit()
173 # Allow driver resources to be properly freed before proceeding with further tests
174 time.sleep(5)
141 super(SeleniumTestCaseBase, cls).tearDownClass() 175 super(SeleniumTestCaseBase, cls).tearDownClass()
142 176
143 def get(self, url): 177 def get(self, url):
@@ -151,13 +185,20 @@ class SeleniumTestCaseBase(unittest.TestCase):
151 abs_url = '%s%s' % (self.live_server_url, url) 185 abs_url = '%s%s' % (self.live_server_url, url)
152 self.driver.get(abs_url) 186 self.driver.get(abs_url)
153 187
188 try: # Ensure page is loaded before proceeding
189 self.wait_until_visible("#global-nav")
190 except NoSuchElementException:
191 self.driver.implicitly_wait(3)
192 except TimeoutException:
193 self.driver.implicitly_wait(3)
194
154 def find(self, selector): 195 def find(self, selector):
155 """ Find single element by CSS selector """ 196 """ Find single element by CSS selector """
156 return self.driver.find_element_by_css_selector(selector) 197 return self.driver.find_element(By.CSS_SELECTOR, selector)
157 198
158 def find_all(self, selector): 199 def find_all(self, selector):
159 """ Find all elements matching CSS selector """ 200 """ Find all elements matching CSS selector """
160 return self.driver.find_elements_by_css_selector(selector) 201 return self.driver.find_elements(By.CSS_SELECTOR, selector)
161 202
162 def element_exists(self, selector): 203 def element_exists(self, selector):
163 """ 204 """
@@ -170,20 +211,43 @@ class SeleniumTestCaseBase(unittest.TestCase):
170 """ Return the element which currently has focus on the page """ 211 """ Return the element which currently has focus on the page """
171 return self.driver.switch_to.active_element 212 return self.driver.switch_to.active_element
172 213
173 def wait_until_present(self, selector): 214 def wait_until_present(self, selector, timeout=Wait._TIMEOUT):
174 """ Wait until element matching CSS selector is on the page """ 215 """ Wait until element matching CSS selector is on the page """
175 is_present = lambda driver: self.find(selector) 216 is_present = lambda driver: self.find(selector)
176 msg = 'An element matching "%s" should be on the page' % selector 217 msg = 'An element matching "%s" should be on the page' % selector
177 element = Wait(self.driver).until(is_present, msg) 218 element = Wait(self.driver, timeout=timeout).until(is_present, msg)
178 return element 219 return element
179 220
180 def wait_until_visible(self, selector): 221 def wait_until_visible(self, selector, timeout=Wait._TIMEOUT):
181 """ Wait until element matching CSS selector is visible on the page """ 222 """ Wait until element matching CSS selector is visible on the page """
182 is_visible = lambda driver: self.find(selector).is_displayed() 223 is_visible = lambda driver: self.find(selector).is_displayed()
183 msg = 'An element matching "%s" should be visible' % selector 224 msg = 'An element matching "%s" should be visible' % selector
184 Wait(self.driver).until(is_visible, msg) 225 Wait(self.driver, timeout=timeout).until(is_visible, msg)
226 return self.find(selector)
227
228 def wait_until_not_visible(self, selector, timeout=Wait._TIMEOUT):
229 """ Wait until element matching CSS selector is not visible on the page """
230 is_visible = lambda driver: self.find(selector).is_displayed()
231 msg = 'An element matching "%s" should be visible' % selector
232 Wait(self.driver, timeout=timeout).until_not(is_visible, msg)
185 return self.find(selector) 233 return self.find(selector)
186 234
235 def wait_until_clickable(self, selector, timeout=Wait._TIMEOUT):
236 """ Wait until element matching CSS selector is visible on the page """
237 WebDriverWait(self.driver, timeout=timeout).until(lambda driver: self.driver.execute_script("return jQuery.active == 0"))
238 is_clickable = lambda driver: (self.find(selector).is_displayed() and self.find(selector).is_enabled())
239 msg = 'An element matching "%s" should be clickable' % selector
240 Wait(self.driver, timeout=timeout).until(is_clickable, msg)
241 return self.find(selector)
242
243 def wait_until_element_clickable(self, finder, timeout=Wait._TIMEOUT):
244 """ Wait until element is clickable """
245 WebDriverWait(self.driver, timeout=timeout).until(lambda driver: self.driver.execute_script("return jQuery.active == 0"))
246 is_clickable = lambda driver: (finder(driver).is_displayed() and finder(driver).is_enabled())
247 msg = 'A matching element never became be clickable'
248 Wait(self.driver, timeout=timeout).until(is_clickable, msg)
249 return finder(self.driver)
250
187 def wait_until_focused(self, selector): 251 def wait_until_focused(self, selector):
188 """ Wait until element matching CSS selector has focus """ 252 """ Wait until element matching CSS selector has focus """
189 is_focused = \ 253 is_focused = \
diff --git a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
index 8423d3dab2..9ab81fb11b 100644
--- a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
@@ -7,13 +7,18 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10import re 11import re
11 12
12from django.urls import reverse 13from django.urls import reverse
14from selenium.webdriver.support.select import Select
13from django.utils import timezone 15from django.utils import timezone
16from bldcontrol.models import BuildRequest
14from tests.browser.selenium_helpers import SeleniumTestCase 17from tests.browser.selenium_helpers import SeleniumTestCase
15 18
16from orm.models import BitbakeVersion, Release, Project, Build, Target 19from orm.models import BitbakeVersion, Layer, Layer_Version, Recipe, Release, Project, Build, Target, Task
20
21from selenium.webdriver.common.by import By
17 22
18 23
19class TestAllBuildsPage(SeleniumTestCase): 24class TestAllBuildsPage(SeleniumTestCase):
@@ -23,7 +28,8 @@ class TestAllBuildsPage(SeleniumTestCase):
23 CLI_BUILDS_PROJECT_NAME = 'command line builds' 28 CLI_BUILDS_PROJECT_NAME = 'command line builds'
24 29
25 def setUp(self): 30 def setUp(self):
26 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 31 builldir = os.environ.get('BUILDDIR', './')
32 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
27 branch='master', dirpath='') 33 branch='master', dirpath='')
28 release = Release.objects.create(name='release1', 34 release = Release.objects.create(name='release1',
29 bitbake_version=bbv) 35 bitbake_version=bbv)
@@ -69,7 +75,7 @@ class TestAllBuildsPage(SeleniumTestCase):
69 '[data-role="data-recent-build-buildtime-field"]' % build.id 75 '[data-role="data-recent-build-buildtime-field"]' % build.id
70 76
71 # because this loads via Ajax, wait for it to be visible 77 # because this loads via Ajax, wait for it to be visible
72 self.wait_until_present(selector) 78 self.wait_until_visible(selector)
73 79
74 build_time_spans = self.find_all(selector) 80 build_time_spans = self.find_all(selector)
75 81
@@ -79,7 +85,7 @@ class TestAllBuildsPage(SeleniumTestCase):
79 85
80 def _get_row_for_build(self, build): 86 def _get_row_for_build(self, build):
81 """ Get the table row for the build from the all builds table """ 87 """ Get the table row for the build from the all builds table """
82 self.wait_until_present('#allbuildstable') 88 self.wait_until_visible('#allbuildstable')
83 89
84 rows = self.find_all('#allbuildstable tr') 90 rows = self.find_all('#allbuildstable tr')
85 91
@@ -91,7 +97,7 @@ class TestAllBuildsPage(SeleniumTestCase):
91 found_row = None 97 found_row = None
92 for row in rows: 98 for row in rows:
93 99
94 outcome_links = row.find_elements_by_css_selector(selector) 100 outcome_links = row.find_elements(By.CSS_SELECTOR, selector)
95 if len(outcome_links) == 1: 101 if len(outcome_links) == 1:
96 found_row = row 102 found_row = row
97 break 103 break
@@ -100,6 +106,66 @@ class TestAllBuildsPage(SeleniumTestCase):
100 106
101 return found_row 107 return found_row
102 108
109 def _get_create_builds(self, **kwargs):
110 """ Create a build and return the build object """
111 build1 = Build.objects.create(**self.project1_build_success)
112 build2 = Build.objects.create(**self.project1_build_failure)
113
114 # add some targets to these builds so they have recipe links
115 # (and so we can find the row in the ToasterTable corresponding to
116 # a particular build)
117 Target.objects.create(build=build1, target='foo')
118 Target.objects.create(build=build2, target='bar')
119
120 if kwargs:
121 # Create kwargs.get('success') builds with success status with target
122 # and kwargs.get('failure') builds with failure status with target
123 for i in range(kwargs.get('success', 0)):
124 now = timezone.now()
125 self.project1_build_success['started_on'] = now
126 self.project1_build_success[
127 'completed_on'] = now - timezone.timedelta(days=i)
128 build = Build.objects.create(**self.project1_build_success)
129 Target.objects.create(build=build,
130 target=f'{i}_success_recipe',
131 task=f'{i}_success_task')
132
133 self._set_buildRequest_and_task_on_build(build)
134 for i in range(kwargs.get('failure', 0)):
135 now = timezone.now()
136 self.project1_build_failure['started_on'] = now
137 self.project1_build_failure[
138 'completed_on'] = now - timezone.timedelta(days=i)
139 build = Build.objects.create(**self.project1_build_failure)
140 Target.objects.create(build=build,
141 target=f'{i}_fail_recipe',
142 task=f'{i}_fail_task')
143 self._set_buildRequest_and_task_on_build(build)
144 return build1, build2
145
146 def _create_recipe(self):
147 """ Add a recipe to the database and return it """
148 layer = Layer.objects.create()
149 layer_version = Layer_Version.objects.create(layer=layer)
150 return Recipe.objects.create(name='recipe_foo', layer_version=layer_version)
151
152 def _set_buildRequest_and_task_on_build(self, build):
153 """ Set buildRequest and task on build """
154 build.recipes_parsed = 1
155 build.save()
156 buildRequest = BuildRequest.objects.create(
157 build=build,
158 project=self.project1,
159 state=BuildRequest.REQ_COMPLETED)
160 build.build_request = buildRequest
161 recipe = self._create_recipe()
162 task = Task.objects.create(build=build,
163 recipe=recipe,
164 task_name='task',
165 outcome=Task.OUTCOME_SUCCESS)
166 task.save()
167 build.save()
168
103 def test_show_tasks_with_suffix(self): 169 def test_show_tasks_with_suffix(self):
104 """ Task should be shown as suffix on build name """ 170 """ Task should be shown as suffix on build name """
105 build = Build.objects.create(**self.project1_build_success) 171 build = Build.objects.create(**self.project1_build_success)
@@ -109,7 +175,7 @@ class TestAllBuildsPage(SeleniumTestCase):
109 175
110 url = reverse('all-builds') 176 url = reverse('all-builds')
111 self.get(url) 177 self.get(url)
112 self.wait_until_present('td[class="target"]') 178 self.wait_until_visible('td[class="target"]')
113 179
114 cell = self.find('td[class="target"]') 180 cell = self.find('td[class="target"]')
115 content = cell.get_attribute('innerHTML') 181 content = cell.get_attribute('innerHTML')
@@ -126,23 +192,26 @@ class TestAllBuildsPage(SeleniumTestCase):
126 but should be shown for other builds 192 but should be shown for other builds
127 """ 193 """
128 build1 = Build.objects.create(**self.project1_build_success) 194 build1 = Build.objects.create(**self.project1_build_success)
129 default_build = Build.objects.create(**self.default_project_build_success) 195 default_build = Build.objects.create(
196 **self.default_project_build_success)
130 197
131 url = reverse('all-builds') 198 url = reverse('all-builds')
132 self.get(url) 199 self.get(url)
133 200
134 # shouldn't see a rebuild button for command-line builds
135 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % default_build.id
136 run_again_button = self.find_all(selector)
137 self.assertEqual(len(run_again_button), 0,
138 'should not see a rebuild button for cli builds')
139
140 # should see a rebuild button for non-command-line builds 201 # should see a rebuild button for non-command-line builds
202 self.wait_until_visible('#allbuildstable tbody tr')
203 self.wait_until_visible('.rebuild-btn')
141 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % build1.id 204 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % build1.id
142 run_again_button = self.find_all(selector) 205 run_again_button = self.find_all(selector)
143 self.assertEqual(len(run_again_button), 1, 206 self.assertEqual(len(run_again_button), 1,
144 'should see a rebuild button for non-cli builds') 207 'should see a rebuild button for non-cli builds')
145 208
209 # shouldn't see a rebuild button for command-line builds
210 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % default_build.id
211 run_again_button = self.find_all(selector)
212 self.assertEqual(len(run_again_button), 0,
213 'should not see a rebuild button for cli builds')
214
146 def test_tooltips_on_project_name(self): 215 def test_tooltips_on_project_name(self):
147 """ 216 """
148 Test tooltips shown next to project name in the main table 217 Test tooltips shown next to project name in the main table
@@ -156,6 +225,7 @@ class TestAllBuildsPage(SeleniumTestCase):
156 225
157 url = reverse('all-builds') 226 url = reverse('all-builds')
158 self.get(url) 227 self.get(url)
228 self.wait_until_visible('#allbuildstable')
159 229
160 # get the project name cells from the table 230 # get the project name cells from the table
161 cells = self.find_all('#allbuildstable td[class="project"]') 231 cells = self.find_all('#allbuildstable td[class="project"]')
@@ -164,7 +234,7 @@ class TestAllBuildsPage(SeleniumTestCase):
164 234
165 for cell in cells: 235 for cell in cells:
166 content = cell.get_attribute('innerHTML') 236 content = cell.get_attribute('innerHTML')
167 help_icons = cell.find_elements_by_css_selector(selector) 237 help_icons = cell.find_elements(By.CSS_SELECTOR, selector)
168 238
169 if re.search(self.PROJECT_NAME, content): 239 if re.search(self.PROJECT_NAME, content):
170 # no help icon next to non-cli project name 240 # no help icon next to non-cli project name
@@ -184,38 +254,224 @@ class TestAllBuildsPage(SeleniumTestCase):
184 recent builds area; failed builds should not have links on the time column, 254 recent builds area; failed builds should not have links on the time column,
185 or in the recent builds area 255 or in the recent builds area
186 """ 256 """
187 build1 = Build.objects.create(**self.project1_build_success) 257 build1, build2 = self._get_create_builds()
188 build2 = Build.objects.create(**self.project1_build_failure)
189
190 # add some targets to these builds so they have recipe links
191 # (and so we can find the row in the ToasterTable corresponding to
192 # a particular build)
193 Target.objects.create(build=build1, target='foo')
194 Target.objects.create(build=build2, target='bar')
195 258
196 url = reverse('all-builds') 259 url = reverse('all-builds')
197 self.get(url) 260 self.get(url)
261 self.wait_until_visible('#allbuildstable')
198 262
199 # test recent builds area for successful build 263 # test recent builds area for successful build
200 element = self._get_build_time_element(build1) 264 element = self._get_build_time_element(build1)
201 links = element.find_elements_by_css_selector('a') 265 links = element.find_elements(By.CSS_SELECTOR, 'a')
202 msg = 'should be a link on the build time for a successful recent build' 266 msg = 'should be a link on the build time for a successful recent build'
203 self.assertEquals(len(links), 1, msg) 267 self.assertEqual(len(links), 1, msg)
204 268
205 # test recent builds area for failed build 269 # test recent builds area for failed build
206 element = self._get_build_time_element(build2) 270 element = self._get_build_time_element(build2)
207 links = element.find_elements_by_css_selector('a') 271 links = element.find_elements(By.CSS_SELECTOR, 'a')
208 msg = 'should not be a link on the build time for a failed recent build' 272 msg = 'should not be a link on the build time for a failed recent build'
209 self.assertEquals(len(links), 0, msg) 273 self.assertEqual(len(links), 0, msg)
210 274
211 # test the time column for successful build 275 # test the time column for successful build
212 build1_row = self._get_row_for_build(build1) 276 build1_row = self._get_row_for_build(build1)
213 links = build1_row.find_elements_by_css_selector('td.time a') 277 links = build1_row.find_elements(By.CSS_SELECTOR, 'td.time a')
214 msg = 'should be a link on the build time for a successful build' 278 msg = 'should be a link on the build time for a successful build'
215 self.assertEquals(len(links), 1, msg) 279 self.assertEqual(len(links), 1, msg)
216 280
217 # test the time column for failed build 281 # test the time column for failed build
218 build2_row = self._get_row_for_build(build2) 282 build2_row = self._get_row_for_build(build2)
219 links = build2_row.find_elements_by_css_selector('td.time a') 283 links = build2_row.find_elements(By.CSS_SELECTOR, 'td.time a')
220 msg = 'should not be a link on the build time for a failed build' 284 msg = 'should not be a link on the build time for a failed build'
221 self.assertEquals(len(links), 0, msg) 285 self.assertEqual(len(links), 0, msg)
286
287 def test_builds_table_search_box(self):
288 """ Test the search box in the builds table on the all builds page """
289 self._get_create_builds()
290
291 url = reverse('all-builds')
292 self.get(url)
293
294 # Check search box is present and works
295 self.wait_until_visible('#allbuildstable tbody tr')
296 search_box = self.find('#search-input-allbuildstable')
297 self.assertTrue(search_box.is_displayed())
298
299 # Check that we can search for a build by recipe name
300 search_box.send_keys('foo')
301 search_btn = self.find('#search-submit-allbuildstable')
302 search_btn.click()
303 self.wait_until_visible('#allbuildstable tbody tr')
304 rows = self.find_all('#allbuildstable tbody tr')
305 self.assertTrue(len(rows) >= 1)
306
307 def test_filtering_on_failure_tasks_column(self):
308 """ Test the filtering on failure tasks column in the builds table on the all builds page """
309 def _check_if_filter_failed_tasks_column_is_visible():
310 # check if failed tasks filter column is visible, if not click on it
311 # Check edit column
312 edit_column = self.find('#edit-columns-button')
313 self.assertTrue(edit_column.is_displayed())
314 edit_column.click()
315 # Check dropdown is visible
316 self.wait_until_visible('ul.dropdown-menu.editcol')
317 filter_fails_task_checkbox = self.find('#checkbox-failed_tasks')
318 if not filter_fails_task_checkbox.is_selected():
319 filter_fails_task_checkbox.click()
320 edit_column.click()
321
322 self._get_create_builds(success=10, failure=10)
323
324 url = reverse('all-builds')
325 self.get(url)
326
327 # Check filtering on failure tasks column
328 self.wait_until_visible('#allbuildstable tbody tr')
329 _check_if_filter_failed_tasks_column_is_visible()
330 failed_tasks_filter = self.find('#failed_tasks_filter')
331 failed_tasks_filter.click()
332 # Check popup is visible
333 self.wait_until_visible('#filter-modal-allbuildstable')
334 self.assertTrue(
335 self.find('#filter-modal-allbuildstable').is_displayed())
336 # Check that we can filter by failure tasks
337 build_without_failure_tasks = self.find(
338 '#failed_tasks_filter\\:without_failed_tasks')
339 build_without_failure_tasks.click()
340 # click on apply button
341 self.find('#filter-modal-allbuildstable .btn-primary').click()
342 self.wait_until_visible('#allbuildstable tbody tr')
343 # Check if filter is applied, by checking if failed_tasks_filter has btn-primary class
344 self.assertTrue(self.find('#failed_tasks_filter').get_attribute(
345 'class').find('btn-primary') != -1)
346
347 def test_filtering_on_completedOn_column(self):
348 """ Test the filtering on completed_on column in the builds table on the all builds page """
349 self._get_create_builds(success=10, failure=10)
350
351 url = reverse('all-builds')
352 self.get(url)
353
354 # Check filtering on failure tasks column
355 self.wait_until_visible('#allbuildstable tbody tr')
356 completed_on_filter = self.find('#completed_on_filter')
357 completed_on_filter.click()
358 # Check popup is visible
359 self.wait_until_visible('#filter-modal-allbuildstable')
360 self.assertTrue(
361 self.find('#filter-modal-allbuildstable').is_displayed())
362 # Check that we can filter by failure tasks
363 build_without_failure_tasks = self.find(
364 '#completed_on_filter\\:date_range')
365 build_without_failure_tasks.click()
366 # click on apply button
367 self.find('#filter-modal-allbuildstable .btn-primary').click()
368 self.wait_until_visible('#allbuildstable tbody tr')
369 # Check if filter is applied, by checking if completed_on_filter has btn-primary class
370 self.assertTrue(self.find('#completed_on_filter').get_attribute(
371 'class').find('btn-primary') != -1)
372
373 # Filter by date range
374 self.find('#completed_on_filter').click()
375 self.wait_until_visible('#filter-modal-allbuildstable')
376 date_ranges = self.driver.find_elements(
377 By.XPATH, '//input[@class="form-control hasDatepicker"]')
378 today = timezone.now()
379 yestersday = today - timezone.timedelta(days=1)
380 date_ranges[0].send_keys(yestersday.strftime('%Y-%m-%d'))
381 date_ranges[1].send_keys(today.strftime('%Y-%m-%d'))
382 self.find('#filter-modal-allbuildstable .btn-primary').click()
383 self.wait_until_visible('#allbuildstable tbody tr')
384 self.assertTrue(self.find('#completed_on_filter').get_attribute(
385 'class').find('btn-primary') != -1)
386 # Check if filter is applied, number of builds displayed should be 6
387 self.assertTrue(len(self.find_all('#allbuildstable tbody tr')) >= 4)
388
389 def test_builds_table_editColumn(self):
390 """ Test the edit column feature in the builds table on the all builds page """
391 self._get_create_builds(success=10, failure=10)
392
393 def test_edit_column(check_box_id):
394 # Check that we can hide/show table column
395 check_box = self.find(f'#{check_box_id}')
396 th_class = str(check_box_id).replace('checkbox-', '')
397 if check_box.is_selected():
398 # check if column is visible in table
399 self.assertTrue(
400 self.find(
401 f'#allbuildstable thead th.{th_class}'
402 ).is_displayed(),
403 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
404 )
405 check_box.click()
406 # check if column is hidden in table
407 self.assertFalse(
408 self.find(
409 f'#allbuildstable thead th.{th_class}'
410 ).is_displayed(),
411 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
412 )
413 else:
414 # check if column is hidden in table
415 self.assertFalse(
416 self.find(
417 f'#allbuildstable thead th.{th_class}'
418 ).is_displayed(),
419 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
420 )
421 check_box.click()
422 # check if column is visible in table
423 self.assertTrue(
424 self.find(
425 f'#allbuildstable thead th.{th_class}'
426 ).is_displayed(),
427 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
428 )
429 url = reverse('all-builds')
430 self.get(url)
431 self.wait_until_visible('#allbuildstable tbody tr')
432
433 # Check edit column
434 edit_column = self.find('#edit-columns-button')
435 self.assertTrue(edit_column.is_displayed())
436 edit_column.click()
437 # Check dropdown is visible
438 self.wait_until_visible('ul.dropdown-menu.editcol')
439
440 # Check that we can hide the edit column
441 test_edit_column('checkbox-errors_no')
442 test_edit_column('checkbox-failed_tasks')
443 test_edit_column('checkbox-image_files')
444 test_edit_column('checkbox-project')
445 test_edit_column('checkbox-started_on')
446 test_edit_column('checkbox-time')
447 test_edit_column('checkbox-warnings_no')
448
449 def test_builds_table_show_rows(self):
450 """ Test the show rows feature in the builds table on the all builds page """
451 self._get_create_builds(success=100, failure=100)
452
453 def test_show_rows(row_to_show, show_row_link):
454 # Check that we can show rows == row_to_show
455 show_row_link.select_by_value(str(row_to_show))
456 self.wait_until_visible('#allbuildstable tbody tr')
457 # check at least some rows are visible
458 self.assertTrue(
459 len(self.find_all('#allbuildstable tbody tr')) > 0
460 )
461
462 url = reverse('all-builds')
463 self.get(url)
464 self.wait_until_visible('#allbuildstable tbody tr')
465
466 show_rows = self.driver.find_elements(
467 By.XPATH,
468 '//select[@class="form-control pagesize-allbuildstable"]'
469 )
470 # Check show rows
471 for show_row_link in show_rows:
472 show_row_link = Select(show_row_link)
473 test_show_rows(10, show_row_link)
474 test_show_rows(25, show_row_link)
475 test_show_rows(50, show_row_link)
476 test_show_rows(100, show_row_link)
477 test_show_rows(150, show_row_link)
diff --git a/bitbake/lib/toaster/tests/browser/test_all_projects_page.py b/bitbake/lib/toaster/tests/browser/test_all_projects_page.py
index 15b03400f9..05e12892be 100644
--- a/bitbake/lib/toaster/tests/browser/test_all_projects_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_all_projects_page.py
@@ -7,15 +7,20 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10import re 11import re
11 12
12from django.urls import reverse 13from django.urls import reverse
13from django.utils import timezone 14from django.utils import timezone
15from selenium.webdriver.support.select import Select
14from tests.browser.selenium_helpers import SeleniumTestCase 16from tests.browser.selenium_helpers import SeleniumTestCase
15 17
16from orm.models import BitbakeVersion, Release, Project, Build 18from orm.models import BitbakeVersion, Release, Project, Build
17from orm.models import ProjectVariable 19from orm.models import ProjectVariable
18 20
21from selenium.webdriver.common.by import By
22
23
19class TestAllProjectsPage(SeleniumTestCase): 24class TestAllProjectsPage(SeleniumTestCase):
20 """ Browser tests for projects page /projects/ """ 25 """ Browser tests for projects page /projects/ """
21 26
@@ -25,7 +30,8 @@ class TestAllProjectsPage(SeleniumTestCase):
25 30
26 def setUp(self): 31 def setUp(self):
27 """ Add default project manually """ 32 """ Add default project manually """
28 project = Project.objects.create_project(self.CLI_BUILDS_PROJECT_NAME, None) 33 project = Project.objects.create_project(
34 self.CLI_BUILDS_PROJECT_NAME, None)
29 self.default_project = project 35 self.default_project = project
30 self.default_project.is_default = True 36 self.default_project.is_default = True
31 self.default_project.save() 37 self.default_project.save()
@@ -35,6 +41,17 @@ class TestAllProjectsPage(SeleniumTestCase):
35 41
36 self.release = None 42 self.release = None
37 43
44 def _create_projects(self, nb_project=10):
45 projects = []
46 for i in range(1, nb_project + 1):
47 projects.append(
48 Project(
49 name='test project {}'.format(i),
50 release=self.release,
51 )
52 )
53 Project.objects.bulk_create(projects)
54
38 def _add_build_to_default_project(self): 55 def _add_build_to_default_project(self):
39 """ Add a build to the default project (not used in all tests) """ 56 """ Add a build to the default project (not used in all tests) """
40 now = timezone.now() 57 now = timezone.now()
@@ -45,12 +62,14 @@ class TestAllProjectsPage(SeleniumTestCase):
45 62
46 def _add_non_default_project(self): 63 def _add_non_default_project(self):
47 """ Add another project """ 64 """ Add another project """
48 bbv = BitbakeVersion.objects.create(name='test bbv', giturl='/tmp/', 65 builldir = os.environ.get('BUILDDIR', './')
66 bbv = BitbakeVersion.objects.create(name='test bbv', giturl=f'{builldir}/',
49 branch='master', dirpath='') 67 branch='master', dirpath='')
50 self.release = Release.objects.create(name='test release', 68 self.release = Release.objects.create(name='test release',
51 branch_name='master', 69 branch_name='master',
52 bitbake_version=bbv) 70 bitbake_version=bbv)
53 self.project = Project.objects.create_project(self.PROJECT_NAME, self.release) 71 self.project = Project.objects.create_project(
72 self.PROJECT_NAME, self.release)
54 self.project.is_default = False 73 self.project.is_default = False
55 self.project.save() 74 self.project.save()
56 75
@@ -62,7 +81,7 @@ class TestAllProjectsPage(SeleniumTestCase):
62 81
63 def _get_row_for_project(self, project_name): 82 def _get_row_for_project(self, project_name):
64 """ Get the HTML row for a project, or None if not found """ 83 """ Get the HTML row for a project, or None if not found """
65 self.wait_until_present('#projectstable tbody tr') 84 self.wait_until_visible('#projectstable tbody tr')
66 rows = self.find_all('#projectstable tbody tr') 85 rows = self.find_all('#projectstable tbody tr')
67 86
68 # find the row with a project name matching the one supplied 87 # find the row with a project name matching the one supplied
@@ -93,7 +112,8 @@ class TestAllProjectsPage(SeleniumTestCase):
93 url = reverse('all-projects') 112 url = reverse('all-projects')
94 self.get(url) 113 self.get(url)
95 114
96 default_project_row = self._get_row_for_project(self.default_project.name) 115 default_project_row = self._get_row_for_project(
116 self.default_project.name)
97 117
98 self.assertNotEqual(default_project_row, None, 118 self.assertNotEqual(default_project_row, None,
99 'default project "cli builds" should be in page') 119 'default project "cli builds" should be in page')
@@ -113,11 +133,12 @@ class TestAllProjectsPage(SeleniumTestCase):
113 self.wait_until_visible("#projectstable tr") 133 self.wait_until_visible("#projectstable tr")
114 134
115 # find the row for the default project 135 # find the row for the default project
116 default_project_row = self._get_row_for_project(self.default_project.name) 136 default_project_row = self._get_row_for_project(
137 self.default_project.name)
117 138
118 # check the release text for the default project 139 # check the release text for the default project
119 selector = 'span[data-project-field="release"] span.text-muted' 140 selector = 'span[data-project-field="release"] span.text-muted'
120 element = default_project_row.find_element_by_css_selector(selector) 141 element = default_project_row.find_element(By.CSS_SELECTOR, selector)
121 text = element.text.strip() 142 text = element.text.strip()
122 self.assertEqual(text, 'Not applicable', 143 self.assertEqual(text, 'Not applicable',
123 'release should be "not applicable" for default project') 144 'release should be "not applicable" for default project')
@@ -127,7 +148,7 @@ class TestAllProjectsPage(SeleniumTestCase):
127 148
128 # check the link in the release cell for the other project 149 # check the link in the release cell for the other project
129 selector = 'span[data-project-field="release"]' 150 selector = 'span[data-project-field="release"]'
130 element = other_project_row.find_element_by_css_selector(selector) 151 element = other_project_row.find_element(By.CSS_SELECTOR, selector)
131 text = element.text.strip() 152 text = element.text.strip()
132 self.assertEqual(text, self.release.name, 153 self.assertEqual(text, self.release.name,
133 'release name should be shown for non-default project') 154 'release name should be shown for non-default project')
@@ -148,11 +169,12 @@ class TestAllProjectsPage(SeleniumTestCase):
148 self.wait_until_visible("#projectstable tr") 169 self.wait_until_visible("#projectstable tr")
149 170
150 # find the row for the default project 171 # find the row for the default project
151 default_project_row = self._get_row_for_project(self.default_project.name) 172 default_project_row = self._get_row_for_project(
173 self.default_project.name)
152 174
153 # check the machine cell for the default project 175 # check the machine cell for the default project
154 selector = 'span[data-project-field="machine"] span.text-muted' 176 selector = 'span[data-project-field="machine"] span.text-muted'
155 element = default_project_row.find_element_by_css_selector(selector) 177 element = default_project_row.find_element(By.CSS_SELECTOR, selector)
156 text = element.text.strip() 178 text = element.text.strip()
157 self.assertEqual(text, 'Not applicable', 179 self.assertEqual(text, 'Not applicable',
158 'machine should be not applicable for default project') 180 'machine should be not applicable for default project')
@@ -162,7 +184,7 @@ class TestAllProjectsPage(SeleniumTestCase):
162 184
163 # check the link in the machine cell for the other project 185 # check the link in the machine cell for the other project
164 selector = 'span[data-project-field="machine"]' 186 selector = 'span[data-project-field="machine"]'
165 element = other_project_row.find_element_by_css_selector(selector) 187 element = other_project_row.find_element(By.CSS_SELECTOR, selector)
166 text = element.text.strip() 188 text = element.text.strip()
167 self.assertEqual(text, self.MACHINE_NAME, 189 self.assertEqual(text, self.MACHINE_NAME,
168 'machine name should be shown for non-default project') 190 'machine name should be shown for non-default project')
@@ -183,13 +205,15 @@ class TestAllProjectsPage(SeleniumTestCase):
183 self.get(reverse('all-projects')) 205 self.get(reverse('all-projects'))
184 206
185 # find the row for the default project 207 # find the row for the default project
186 default_project_row = self._get_row_for_project(self.default_project.name) 208 default_project_row = self._get_row_for_project(
209 self.default_project.name)
187 210
188 # check the link on the name field 211 # check the link on the name field
189 selector = 'span[data-project-field="name"] a' 212 selector = 'span[data-project-field="name"] a'
190 element = default_project_row.find_element_by_css_selector(selector) 213 element = default_project_row.find_element(By.CSS_SELECTOR, selector)
191 link_url = element.get_attribute('href').strip() 214 link_url = element.get_attribute('href').strip()
192 expected_url = reverse('projectbuilds', args=(self.default_project.id,)) 215 expected_url = reverse(
216 'projectbuilds', args=(self.default_project.id,))
193 msg = 'link on default project name should point to builds but was %s' % link_url 217 msg = 'link on default project name should point to builds but was %s' % link_url
194 self.assertTrue(link_url.endswith(expected_url), msg) 218 self.assertTrue(link_url.endswith(expected_url), msg)
195 219
@@ -198,8 +222,116 @@ class TestAllProjectsPage(SeleniumTestCase):
198 222
199 # check the link for the other project 223 # check the link for the other project
200 selector = 'span[data-project-field="name"] a' 224 selector = 'span[data-project-field="name"] a'
201 element = other_project_row.find_element_by_css_selector(selector) 225 element = other_project_row.find_element(By.CSS_SELECTOR, selector)
202 link_url = element.get_attribute('href').strip() 226 link_url = element.get_attribute('href').strip()
203 expected_url = reverse('project', args=(self.project.id,)) 227 expected_url = reverse('project', args=(self.project.id,))
204 msg = 'link on project name should point to configuration but was %s' % link_url 228 msg = 'link on project name should point to configuration but was %s' % link_url
205 self.assertTrue(link_url.endswith(expected_url), msg) 229 self.assertTrue(link_url.endswith(expected_url), msg)
230
231 def test_allProject_table_search_box(self):
232 """ Test the search box in the all project table on the all projects page """
233 self._create_projects()
234
235 url = reverse('all-projects')
236 self.get(url)
237
238 # Chseck search box is present and works
239 self.wait_until_visible('#projectstable tbody tr')
240 search_box = self.find('#search-input-projectstable')
241 self.assertTrue(search_box.is_displayed())
242
243 # Check that we can search for a project by project name
244 search_box.send_keys('test project 10')
245 search_btn = self.find('#search-submit-projectstable')
246 search_btn.click()
247 self.wait_until_visible('#projectstable tbody tr')
248 rows = self.find_all('#projectstable tbody tr')
249 self.assertTrue(len(rows) == 1)
250
251 def test_allProject_table_editColumn(self):
252 """ Test the edit column feature in the projects table on the all projects page """
253 self._create_projects()
254
255 def test_edit_column(check_box_id):
256 # Check that we can hide/show table column
257 check_box = self.find(f'#{check_box_id}')
258 th_class = str(check_box_id).replace('checkbox-', '')
259 if check_box.is_selected():
260 # check if column is visible in table
261 self.assertTrue(
262 self.find(
263 f'#projectstable thead th.{th_class}'
264 ).is_displayed(),
265 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
266 )
267 check_box.click()
268 # check if column is hidden in table
269 self.assertFalse(
270 self.find(
271 f'#projectstable thead th.{th_class}'
272 ).is_displayed(),
273 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
274 )
275 else:
276 # check if column is hidden in table
277 self.assertFalse(
278 self.find(
279 f'#projectstable thead th.{th_class}'
280 ).is_displayed(),
281 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
282 )
283 check_box.click()
284 # check if column is visible in table
285 self.assertTrue(
286 self.find(
287 f'#projectstable thead th.{th_class}'
288 ).is_displayed(),
289 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
290 )
291 url = reverse('all-projects')
292 self.get(url)
293 self.wait_until_visible('#projectstable tbody tr')
294
295 # Check edit column
296 edit_column = self.find('#edit-columns-button')
297 self.assertTrue(edit_column.is_displayed())
298 edit_column.click()
299 # Check dropdown is visible
300 self.wait_until_visible('ul.dropdown-menu.editcol')
301
302 # Check that we can hide the edit column
303 test_edit_column('checkbox-errors')
304 test_edit_column('checkbox-image_files')
305 test_edit_column('checkbox-last_build_outcome')
306 test_edit_column('checkbox-recipe_name')
307 test_edit_column('checkbox-warnings')
308
309 def test_allProject_table_show_rows(self):
310 """ Test the show rows feature in the projects table on the all projects page """
311 self._create_projects(nb_project=200)
312
313 def test_show_rows(row_to_show, show_row_link):
314 # Check that we can show rows == row_to_show
315 show_row_link.select_by_value(str(row_to_show))
316 self.wait_until_visible('#projectstable tbody tr')
317 # check at least some rows are visible
318 self.assertTrue(
319 len(self.find_all('#projectstable tbody tr')) > 0
320 )
321
322 url = reverse('all-projects')
323 self.get(url)
324 self.wait_until_visible('#projectstable tbody tr')
325
326 show_rows = self.driver.find_elements(
327 By.XPATH,
328 '//select[@class="form-control pagesize-projectstable"]'
329 )
330 # Check show rows
331 for show_row_link in show_rows:
332 show_row_link = Select(show_row_link)
333 test_show_rows(10, show_row_link)
334 test_show_rows(25, show_row_link)
335 test_show_rows(50, show_row_link)
336 test_show_rows(100, show_row_link)
337 test_show_rows(150, show_row_link)
diff --git a/bitbake/lib/toaster/tests/browser/test_builddashboard_page.py b/bitbake/lib/toaster/tests/browser/test_builddashboard_page.py
index efcd89b346..82367108e2 100644
--- a/bitbake/lib/toaster/tests/browser/test_builddashboard_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_builddashboard_page.py
@@ -7,6 +7,7 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10from django.urls import reverse 11from django.urls import reverse
11from django.utils import timezone 12from django.utils import timezone
12 13
@@ -15,11 +16,14 @@ from tests.browser.selenium_helpers import SeleniumTestCase
15from orm.models import Project, Release, BitbakeVersion, Build, LogMessage 16from orm.models import Project, Release, BitbakeVersion, Build, LogMessage
16from orm.models import Layer, Layer_Version, Recipe, CustomImageRecipe, Variable 17from orm.models import Layer, Layer_Version, Recipe, CustomImageRecipe, Variable
17 18
19from selenium.webdriver.common.by import By
20
18class TestBuildDashboardPage(SeleniumTestCase): 21class TestBuildDashboardPage(SeleniumTestCase):
19 """ Tests for the build dashboard /build/X """ 22 """ Tests for the build dashboard /build/X """
20 23
21 def setUp(self): 24 def setUp(self):
22 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 25 builldir = os.environ.get('BUILDDIR', './')
26 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
23 branch='master', dirpath="") 27 branch='master', dirpath="")
24 release = Release.objects.create(name='release1', 28 release = Release.objects.create(name='release1',
25 bitbake_version=bbv) 29 bitbake_version=bbv)
@@ -158,6 +162,7 @@ class TestBuildDashboardPage(SeleniumTestCase):
158 """ 162 """
159 url = reverse('builddashboard', args=(build.id,)) 163 url = reverse('builddashboard', args=(build.id,))
160 self.get(url) 164 self.get(url)
165 self.wait_until_visible('#global-nav')
161 166
162 def _get_build_dashboard_errors(self, build): 167 def _get_build_dashboard_errors(self, build):
163 """ 168 """
@@ -183,7 +188,7 @@ class TestBuildDashboardPage(SeleniumTestCase):
183 188
184 found = False 189 found = False
185 for element in message_elements: 190 for element in message_elements:
186 log_message_text = element.find_element_by_tag_name('pre').text.strip() 191 log_message_text = element.find_element(By.TAG_NAME, 'pre').text.strip()
187 text_matches = (log_message_text == expected_text) 192 text_matches = (log_message_text == expected_text)
188 193
189 log_message_pk = element.get_attribute('data-log-message-id') 194 log_message_pk = element.get_attribute('data-log-message-id')
@@ -213,7 +218,7 @@ class TestBuildDashboardPage(SeleniumTestCase):
213 the WebElement modal match the list of text values in expected 218 the WebElement modal match the list of text values in expected
214 """ 219 """
215 # labels containing the radio buttons we're testing for 220 # labels containing the radio buttons we're testing for
216 labels = modal.find_elements_by_css_selector(".radio") 221 labels = modal.find_elements(By.CSS_SELECTOR,".radio")
217 222
218 labels_text = [lab.text for lab in labels] 223 labels_text = [lab.text for lab in labels]
219 self.assertEqual(len(labels_text), len(expected)) 224 self.assertEqual(len(labels_text), len(expected))
@@ -248,7 +253,7 @@ class TestBuildDashboardPage(SeleniumTestCase):
248 selector = '[data-role="edit-custom-image-trigger"]' 253 selector = '[data-role="edit-custom-image-trigger"]'
249 self.click(selector) 254 self.click(selector)
250 255
251 modal = self.driver.find_element_by_id('edit-custom-image-modal') 256 modal = self.driver.find_element(By.ID, 'edit-custom-image-modal')
252 self.wait_until_visible("#edit-custom-image-modal") 257 self.wait_until_visible("#edit-custom-image-modal")
253 258
254 # recipes we expect to see in the edit custom image modal 259 # recipes we expect to see in the edit custom image modal
@@ -270,7 +275,7 @@ class TestBuildDashboardPage(SeleniumTestCase):
270 selector = '[data-role="new-custom-image-trigger"]' 275 selector = '[data-role="new-custom-image-trigger"]'
271 self.click(selector) 276 self.click(selector)
272 277
273 modal = self.driver.find_element_by_id('new-custom-image-modal') 278 modal = self.driver.find_element(By.ID,'new-custom-image-modal')
274 self.wait_until_visible("#new-custom-image-modal") 279 self.wait_until_visible("#new-custom-image-modal")
275 280
276 # recipes we expect to see in the new custom image modal 281 # recipes we expect to see in the new custom image modal
diff --git a/bitbake/lib/toaster/tests/browser/test_builddashboard_page_artifacts.py b/bitbake/lib/toaster/tests/browser/test_builddashboard_page_artifacts.py
index c6226d60eb..675825bd40 100644
--- a/bitbake/lib/toaster/tests/browser/test_builddashboard_page_artifacts.py
+++ b/bitbake/lib/toaster/tests/browser/test_builddashboard_page_artifacts.py
@@ -7,6 +7,7 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10from django.urls import reverse 11from django.urls import reverse
11from django.utils import timezone 12from django.utils import timezone
12 13
@@ -20,7 +21,8 @@ class TestBuildDashboardPageArtifacts(SeleniumTestCase):
20 """ Tests for artifacts on the build dashboard /build/X """ 21 """ Tests for artifacts on the build dashboard /build/X """
21 22
22 def setUp(self): 23 def setUp(self):
23 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 24 builldir = os.environ.get('BUILDDIR', './')
25 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
24 branch='master', dirpath="") 26 branch='master', dirpath="")
25 release = Release.objects.create(name='release1', 27 release = Release.objects.create(name='release1',
26 bitbake_version=bbv) 28 bitbake_version=bbv)
@@ -197,12 +199,12 @@ class TestBuildDashboardPageArtifacts(SeleniumTestCase):
197 # check package count and size, link on target name 199 # check package count and size, link on target name
198 selector = '[data-value="target-package-count"]' 200 selector = '[data-value="target-package-count"]'
199 element = self.find(selector) 201 element = self.find(selector)
200 self.assertEquals(element.text, '1', 202 self.assertEqual(element.text, '1',
201 'package count should be shown for image builds') 203 'package count should be shown for image builds')
202 204
203 selector = '[data-value="target-package-size"]' 205 selector = '[data-value="target-package-size"]'
204 element = self.find(selector) 206 element = self.find(selector)
205 self.assertEquals(element.text, '1.0 KB', 207 self.assertEqual(element.text, '1.0 KB',
206 'package size should be shown for image builds') 208 'package size should be shown for image builds')
207 209
208 selector = '[data-link="target-packages"]' 210 selector = '[data-link="target-packages"]'
diff --git a/bitbake/lib/toaster/tests/browser/test_delete_project.py b/bitbake/lib/toaster/tests/browser/test_delete_project.py
new file mode 100644
index 0000000000..1941777ccc
--- /dev/null
+++ b/bitbake/lib/toaster/tests/browser/test_delete_project.py
@@ -0,0 +1,103 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# BitBake Toaster UI tests implementation
4#
5# Copyright (C) 2023 Savoir-faire Linux Inc
6#
7# SPDX-License-Identifier: GPL-2.0-only
8
9import pytest
10from django.urls import reverse
11from selenium.webdriver.support.ui import Select
12from tests.browser.selenium_helpers import SeleniumTestCase
13from orm.models import BitbakeVersion, Project, Release
14from selenium.webdriver.common.by import By
15
16class TestDeleteProject(SeleniumTestCase):
17
18 def setUp(self):
19 bitbake, _ = BitbakeVersion.objects.get_or_create(
20 name="master",
21 giturl="git://master",
22 branch="master",
23 dirpath="master")
24
25 self.release, _ = Release.objects.get_or_create(
26 name="master",
27 description="Yocto Project master",
28 branch_name="master",
29 helptext="latest",
30 bitbake_version=bitbake)
31
32 Release.objects.get_or_create(
33 name="foo",
34 description="Yocto Project foo",
35 branch_name="foo",
36 helptext="latest",
37 bitbake_version=bitbake)
38
39 @pytest.mark.django_db
40 def test_delete_project(self):
41 """ Test delete a project
42 - Check delete modal is visible
43 - Check delete modal has right text
44 - Confirm delete
45 - Check project is deleted
46 """
47 project_name = "project_to_delete"
48 url = reverse('newproject')
49 self.get(url)
50 self.enter_text('#new-project-name', project_name)
51 select = Select(self.find('#projectversion'))
52 select.select_by_value(str(self.release.pk))
53 self.click("#create-project-button")
54 # We should get redirected to the new project's page with the
55 # notification at the top
56 element = self.wait_until_visible('#project-created-notification')
57 self.assertTrue(project_name in element.text,
58 "New project name not in new project notification")
59 self.assertTrue(Project.objects.filter(name=project_name).count(),
60 "New project not found in database")
61
62 # Delete project
63 delete_project_link = self.driver.find_element(
64 By.XPATH, '//a[@href="#delete-project-modal"]')
65 delete_project_link.click()
66
67 # Check delete modal is visible
68 self.wait_until_visible('#delete-project-modal')
69
70 # Check delete modal has right text
71 modal_header_text = self.find('#delete-project-modal .modal-header').text
72 self.assertTrue(
73 "Are you sure you want to delete this project?" in modal_header_text,
74 "Delete project modal header text is wrong")
75
76 modal_body_text = self.find('#delete-project-modal .modal-body').text
77 self.assertTrue(
78 "Cancel its builds currently in progress" in modal_body_text,
79 "Modal body doesn't contain: Cancel its builds currently in progress")
80 self.assertTrue(
81 "Remove its configuration information" in modal_body_text,
82 "Modal body doesn't contain: Remove its configuration information")
83 self.assertTrue(
84 "Remove its imported layers" in modal_body_text,
85 "Modal body doesn't contain: Remove its imported layers")
86 self.assertTrue(
87 "Remove its custom images" in modal_body_text,
88 "Modal body doesn't contain: Remove its custom images")
89 self.assertTrue(
90 "Remove all its build information" in modal_body_text,
91 "Modal body doesn't contain: Remove all its build information")
92
93 # Confirm delete
94 delete_btn = self.find('#delete-project-confirmed')
95 delete_btn.click()
96
97 # Check project is deleted
98 self.wait_until_visible('#change-notification')
99 delete_notification = self.find('#change-notification-msg')
100 self.assertTrue("You have deleted 1 project:" in delete_notification.text)
101 self.assertTrue(project_name in delete_notification.text)
102 self.assertFalse(Project.objects.filter(name=project_name).exists(),
103 "Project not deleted from database")
diff --git a/bitbake/lib/toaster/tests/browser/test_landing_page.py b/bitbake/lib/toaster/tests/browser/test_landing_page.py
index 8bb64b9f3e..210359d561 100644
--- a/bitbake/lib/toaster/tests/browser/test_landing_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_landing_page.py
@@ -10,8 +10,10 @@
10from django.urls import reverse 10from django.urls import reverse
11from django.utils import timezone 11from django.utils import timezone
12from tests.browser.selenium_helpers import SeleniumTestCase 12from tests.browser.selenium_helpers import SeleniumTestCase
13from selenium.webdriver.common.by import By
14
15from orm.models import Layer, Layer_Version, Project, Build
13 16
14from orm.models import Project, Build
15 17
16class TestLandingPage(SeleniumTestCase): 18class TestLandingPage(SeleniumTestCase):
17 """ Tests for redirects on the landing page """ 19 """ Tests for redirects on the landing page """
@@ -29,12 +31,147 @@ class TestLandingPage(SeleniumTestCase):
29 self.project.is_default = True 31 self.project.is_default = True
30 self.project.save() 32 self.project.save()
31 33
34 def test_icon_info_visible_and_clickable(self):
35 """ Test that the information icon is visible and clickable """
36 self.get(reverse('landing'))
37 self.wait_until_visible('#toaster-version-info-sign')
38 info_sign = self.find('#toaster-version-info-sign')
39
40 # check that the info sign is visible
41 self.assertTrue(info_sign.is_displayed())
42
43 # check that the info sign is clickable
44 # and info modal is appearing when clicking on the info sign
45 info_sign.click() # click on the info sign make attribute 'aria-describedby' visible
46 info_model_id = info_sign.get_attribute('aria-describedby')
47 self.wait_until_visible(f'#{info_model_id}')
48 info_modal = self.find(f'#{info_model_id}')
49 self.assertTrue(info_modal.is_displayed())
50 self.assertTrue("Toaster version information" in info_modal.text)
51
52 def test_documentation_link_displayed(self):
53 """ Test that the documentation link is displayed """
54 self.get(reverse('landing'))
55 self.wait_until_visible('#navbar-docs')
56 documentation_link = self.find('#navbar-docs > a')
57
58 # check that the documentation link is visible
59 self.assertTrue(documentation_link.is_displayed())
60
61 # check browser open new tab toaster manual when clicking on the documentation link
62 self.assertEqual(documentation_link.get_attribute('target'), '_blank')
63 self.assertEqual(
64 documentation_link.get_attribute('href'),
65 'http://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual')
66 self.assertTrue("Documentation" in documentation_link.text)
67
68 def test_openembedded_jumbotron_link_visible_and_clickable(self):
69 """ Test OpenEmbedded link jumbotron is visible and clickable: """
70 self.get(reverse('landing'))
71 self.wait_until_visible('.jumbotron')
72 jumbotron = self.find('.jumbotron')
73
74 # check OpenEmbedded
75 openembedded = jumbotron.find_element(By.LINK_TEXT, 'OpenEmbedded')
76 self.assertTrue(openembedded.is_displayed())
77 openembedded.click()
78 self.assertTrue("openembedded.org" in self.driver.current_url)
79
80 def test_bitbake_jumbotron_link_visible_and_clickable(self):
81 """ Test BitBake link jumbotron is visible and clickable: """
82 self.get(reverse('landing'))
83 self.wait_until_visible('.jumbotron')
84 jumbotron = self.find('.jumbotron')
85
86 # check BitBake
87 bitbake = jumbotron.find_element(By.LINK_TEXT, 'BitBake')
88 self.assertTrue(bitbake.is_displayed())
89 bitbake.click()
90 self.assertTrue(
91 "docs.yoctoproject.org/bitbake.html" in self.driver.current_url)
92
93 def test_yoctoproject_jumbotron_link_visible_and_clickable(self):
94 """ Test Yocto Project link jumbotron is visible and clickable: """
95 self.get(reverse('landing'))
96 self.wait_until_visible('.jumbotron')
97 jumbotron = self.find('.jumbotron')
98
99 # check Yocto Project
100 yoctoproject = jumbotron.find_element(By.LINK_TEXT, 'Yocto Project')
101 self.assertTrue(yoctoproject.is_displayed())
102 yoctoproject.click()
103 self.assertTrue("yoctoproject.org" in self.driver.current_url)
104
105 def test_link_setup_using_toaster_visible_and_clickable(self):
106 """ Test big magenta button setting up and using toaster link in jumbotron
107 if visible and clickable
108 """
109 self.get(reverse('landing'))
110 self.wait_until_visible('.jumbotron')
111 jumbotron = self.find('.jumbotron')
112
113 # check Big magenta button
114 big_magenta_button = jumbotron.find_element(By.LINK_TEXT,
115 'Toaster is ready to capture your command line builds'
116 )
117 self.assertTrue(big_magenta_button.is_displayed())
118 big_magenta_button.click()
119 self.assertTrue(
120 "docs.yoctoproject.org/toaster-manual/setup-and-use.html#setting-up-and-using-toaster" in self.driver.current_url)
121
122 def test_link_create_new_project_in_jumbotron_visible_and_clickable(self):
123 """ Test big blue button create new project jumbotron if visible and clickable """
124 # Create a layer and a layer version to make visible the big blue button
125 layer = Layer.objects.create(name='bar')
126 Layer_Version.objects.create(layer=layer)
127
128 self.get(reverse('landing'))
129 self.wait_until_visible('.jumbotron')
130 jumbotron = self.find('.jumbotron')
131
132 # check Big Blue button
133 big_blue_button = jumbotron.find_element(By.LINK_TEXT,
134 'Create your first Toaster project to run manage builds'
135 )
136 self.assertTrue(big_blue_button.is_displayed())
137 big_blue_button.click()
138 self.assertTrue("toastergui/newproject/" in self.driver.current_url)
139
140 def test_toaster_manual_link_visible_and_clickable(self):
141 """ Test Read the Toaster manual link jumbotron is visible and clickable: """
142 self.get(reverse('landing'))
143 self.wait_until_visible('.jumbotron')
144 jumbotron = self.find('.jumbotron')
145
146 # check Read the Toaster manual
147 toaster_manual = jumbotron.find_element(
148 By.LINK_TEXT, 'Read the Toaster manual')
149 self.assertTrue(toaster_manual.is_displayed())
150 toaster_manual.click()
151 self.assertTrue(
152 "https://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual" in self.driver.current_url)
153
154 def test_contrib_to_toaster_link_visible_and_clickable(self):
155 """ Test Contribute to Toaster link jumbotron is visible and clickable: """
156 self.get(reverse('landing'))
157 self.wait_until_visible('.jumbotron')
158 jumbotron = self.find('.jumbotron')
159
160 # check Contribute to Toaster
161 contribute_to_toaster = jumbotron.find_element(
162 By.LINK_TEXT, 'Contribute to Toaster')
163 self.assertTrue(contribute_to_toaster.is_displayed())
164 contribute_to_toaster.click()
165 self.assertTrue(
166 "wiki.yoctoproject.org/wiki/contribute_to_toaster" in str(self.driver.current_url).lower())
167
32 def test_only_default_project(self): 168 def test_only_default_project(self):
33 """ 169 """
34 No projects except default 170 No projects except default
35 => should see the landing page 171 => should see the landing page
36 """ 172 """
37 self.get(reverse('landing')) 173 self.get(reverse('landing'))
174 self.wait_until_visible('.jumbotron')
38 self.assertTrue(self.LANDING_PAGE_TITLE in self.get_page_source()) 175 self.assertTrue(self.LANDING_PAGE_TITLE in self.get_page_source())
39 176
40 def test_default_project_has_build(self): 177 def test_default_project_has_build(self):
@@ -67,6 +204,7 @@ class TestLandingPage(SeleniumTestCase):
67 user_project.save() 204 user_project.save()
68 205
69 self.get(reverse('landing')) 206 self.get(reverse('landing'))
207 self.wait_until_visible('#projectstable')
70 208
71 elements = self.find_all('#projectstable') 209 elements = self.find_all('#projectstable')
72 self.assertEqual(len(elements), 1, 'should redirect to projects') 210 self.assertEqual(len(elements), 1, 'should redirect to projects')
@@ -87,10 +225,9 @@ class TestLandingPage(SeleniumTestCase):
87 225
88 self.get(reverse('landing')) 226 self.get(reverse('landing'))
89 227
228 self.wait_until_visible("#latest-builds")
90 elements = self.find_all('#allbuildstable') 229 elements = self.find_all('#allbuildstable')
91 self.assertEqual(len(elements), 1, 'should redirect to builds') 230 self.assertEqual(len(elements), 1, 'should redirect to builds')
92 content = self.get_page_source() 231 content = self.get_page_source()
93 self.assertTrue(self.PROJECT_NAME in content, 232 self.assertTrue(self.PROJECT_NAME in content,
94 'should show builds for project %s' % self.PROJECT_NAME) 233 'should show builds for project %s' % self.PROJECT_NAME)
95 self.assertFalse(self.CLI_BUILDS_PROJECT_NAME in content,
96 'should not show builds for cli project')
diff --git a/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py b/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
index 71bdd2aafd..6abfdef699 100644
--- a/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
@@ -8,6 +8,7 @@
8# 8#
9 9
10from django.urls import reverse 10from django.urls import reverse
11from selenium.common.exceptions import ElementClickInterceptedException, TimeoutException
11from tests.browser.selenium_helpers import SeleniumTestCase 12from tests.browser.selenium_helpers import SeleniumTestCase
12 13
13from orm.models import Layer, Layer_Version, Project, LayerSource, Release 14from orm.models import Layer, Layer_Version, Project, LayerSource, Release
@@ -63,11 +64,12 @@ class TestLayerDetailsPage(SeleniumTestCase):
63 args=(self.project.pk, 64 args=(self.project.pk,
64 self.imported_layer_version.pk)) 65 self.imported_layer_version.pk))
65 66
66 def test_edit_layerdetails(self): 67 def test_edit_layerdetails_page(self):
67 """ Edit all the editable fields for the layer refresh the page and 68 """ Edit all the editable fields for the layer refresh the page and
68 check that the new values exist""" 69 check that the new values exist"""
69 70
70 self.get(self.url) 71 self.get(self.url)
72 self.wait_until_visible("#add-remove-layer-btn")
71 73
72 self.click("#add-remove-layer-btn") 74 self.click("#add-remove-layer-btn")
73 self.click("#edit-layer-source") 75 self.click("#edit-layer-source")
@@ -97,13 +99,21 @@ class TestLayerDetailsPage(SeleniumTestCase):
97 "Expecting any of \"%s\"but got \"%s\"" % 99 "Expecting any of \"%s\"but got \"%s\"" %
98 (self.initial_values, value)) 100 (self.initial_values, value))
99 101
102 # Make sure the input visible beofre sending keys
103 self.wait_until_clickable("#layer-git input[type=text]")
100 inputs.send_keys("-edited") 104 inputs.send_keys("-edited")
101 105
102 # Save the new values 106 # Save the new values
103 for save_btn in self.find_all(".change-btn"): 107 for save_btn in self.find_all(".change-btn"):
104 save_btn.click() 108 save_btn.click()
105 109
106 self.click("#save-changes-for-switch") 110 self.wait_until_visible("#save-changes-for-switch")
111 # Ensure scrolled into view
112 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
113 btn_save_chg_for_switch = self.wait_until_clickable(
114 "#save-changes-for-switch")
115 btn_save_chg_for_switch.click()
116
107 self.wait_until_visible("#edit-layer-source") 117 self.wait_until_visible("#edit-layer-source")
108 118
109 # Refresh the page to see if the new values are returned 119 # Refresh the page to see if the new values are returned
@@ -132,7 +142,11 @@ class TestLayerDetailsPage(SeleniumTestCase):
132 new_dir = "/home/test/my-meta-dir" 142 new_dir = "/home/test/my-meta-dir"
133 dir_input.send_keys(new_dir) 143 dir_input.send_keys(new_dir)
134 144
135 self.click("#save-changes-for-switch") 145 self.wait_until_visible("#save-changes-for-switch")
146 btn_save_chg_for_switch = self.wait_until_clickable(
147 "#save-changes-for-switch")
148 btn_save_chg_for_switch.click()
149
136 self.wait_until_visible("#edit-layer-source") 150 self.wait_until_visible("#edit-layer-source")
137 151
138 # Refresh the page to see if the new values are returned 152 # Refresh the page to see if the new values are returned
@@ -142,6 +156,7 @@ class TestLayerDetailsPage(SeleniumTestCase):
142 "Expected %s in the dir value for layer directory" % 156 "Expected %s in the dir value for layer directory" %
143 new_dir) 157 new_dir)
144 158
159
145 def test_delete_layer(self): 160 def test_delete_layer(self):
146 """ Delete the layer """ 161 """ Delete the layer """
147 162
@@ -178,6 +193,7 @@ class TestLayerDetailsPage(SeleniumTestCase):
178 self.get(self.url) 193 self.get(self.url)
179 194
180 # Add the layer 195 # Add the layer
196 self.wait_until_clickable("#add-remove-layer-btn")
181 self.click("#add-remove-layer-btn") 197 self.click("#add-remove-layer-btn")
182 198
183 notification = self.wait_until_visible("#change-notification-msg") 199 notification = self.wait_until_visible("#change-notification-msg")
@@ -185,12 +201,17 @@ class TestLayerDetailsPage(SeleniumTestCase):
185 expected_text = "You have added 1 layer to your project: %s" % \ 201 expected_text = "You have added 1 layer to your project: %s" % \
186 self.imported_layer_version.layer.name 202 self.imported_layer_version.layer.name
187 203
188 self.assertTrue(expected_text in notification.text, 204 self.assertIn(expected_text, notification.text,
189 "Expected notification text %s not found was " 205 "Expected notification text %s not found was "
190 " \"%s\" instead" % 206 " \"%s\" instead" %
191 (expected_text, notification.text)) 207 (expected_text, notification.text))
192 208
209 hide_button = self.find('#hide-alert')
210 hide_button.click()
211 self.wait_until_not_visible('#change-notification')
212
193 # Remove the layer 213 # Remove the layer
214 self.wait_until_clickable("#add-remove-layer-btn")
194 self.click("#add-remove-layer-btn") 215 self.click("#add-remove-layer-btn")
195 216
196 notification = self.wait_until_visible("#change-notification-msg") 217 notification = self.wait_until_visible("#change-notification-msg")
@@ -198,7 +219,7 @@ class TestLayerDetailsPage(SeleniumTestCase):
198 expected_text = "You have removed 1 layer from your project: %s" % \ 219 expected_text = "You have removed 1 layer from your project: %s" % \
199 self.imported_layer_version.layer.name 220 self.imported_layer_version.layer.name
200 221
201 self.assertTrue(expected_text in notification.text, 222 self.assertIn(expected_text, notification.text,
202 "Expected notification text %s not found was " 223 "Expected notification text %s not found was "
203 " \"%s\" instead" % 224 " \"%s\" instead" %
204 (expected_text, notification.text)) 225 (expected_text, notification.text))
diff --git a/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py b/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py
index 7844aaa395..d7a4c34532 100644
--- a/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py
+++ b/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py
@@ -6,7 +6,6 @@
6# 6#
7# Copyright (C) 2013-2016 Intel Corporation 7# Copyright (C) 2013-2016 Intel Corporation
8# 8#
9
10from django.urls import reverse 9from django.urls import reverse
11from django.utils import timezone 10from django.utils import timezone
12from tests.browser.selenium_helpers import SeleniumTestCase 11from tests.browser.selenium_helpers import SeleniumTestCase
@@ -14,6 +13,8 @@ from tests.browser.selenium_helpers_base import Wait
14from orm.models import Project, Build, Task, Recipe, Layer, Layer_Version 13from orm.models import Project, Build, Task, Recipe, Layer, Layer_Version
15from bldcontrol.models import BuildRequest 14from bldcontrol.models import BuildRequest
16 15
16from selenium.webdriver.common.by import By
17
17class TestMostRecentBuildsStates(SeleniumTestCase): 18class TestMostRecentBuildsStates(SeleniumTestCase):
18 """ Test states update correctly in most recent builds area """ 19 """ Test states update correctly in most recent builds area """
19 20
@@ -45,13 +46,14 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
45 # build queued; check shown as queued 46 # build queued; check shown as queued
46 selector = base_selector + '[data-build-state="Queued"]' 47 selector = base_selector + '[data-build-state="Queued"]'
47 element = self.wait_until_visible(selector) 48 element = self.wait_until_visible(selector)
48 self.assertRegexpMatches(element.get_attribute('innerHTML'), 49 self.assertRegex(element.get_attribute('innerHTML'),
49 'Build queued', 'build should show queued status') 50 'Build queued', 'build should show queued status')
50 51
51 # waiting for recipes to be parsed 52 # waiting for recipes to be parsed
52 build.outcome = Build.IN_PROGRESS 53 build.outcome = Build.IN_PROGRESS
53 build.recipes_to_parse = recipes_to_parse 54 build.recipes_to_parse = recipes_to_parse
54 build.recipes_parsed = 0 55 build.recipes_parsed = 0
56 build.save()
55 57
56 build_request.state = BuildRequest.REQ_INPROGRESS 58 build_request.state = BuildRequest.REQ_INPROGRESS
57 build_request.save() 59 build_request.save()
@@ -62,7 +64,7 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
62 element = self.wait_until_visible(selector) 64 element = self.wait_until_visible(selector)
63 65
64 bar_selector = '#recipes-parsed-percentage-bar-%s' % build.id 66 bar_selector = '#recipes-parsed-percentage-bar-%s' % build.id
65 bar_element = element.find_element_by_css_selector(bar_selector) 67 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector)
66 self.assertEqual(bar_element.value_of_css_property('width'), '0px', 68 self.assertEqual(bar_element.value_of_css_property('width'), '0px',
67 'recipe parse progress should be at 0') 69 'recipe parse progress should be at 0')
68 70
@@ -73,7 +75,7 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
73 self.get(url) 75 self.get(url)
74 76
75 element = self.wait_until_visible(selector) 77 element = self.wait_until_visible(selector)
76 bar_element = element.find_element_by_css_selector(bar_selector) 78 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector)
77 recipe_bar_updated = lambda driver: \ 79 recipe_bar_updated = lambda driver: \
78 bar_element.get_attribute('style') == 'width: 50%;' 80 bar_element.get_attribute('style') == 'width: 50%;'
79 msg = 'recipe parse progress bar should update to 50%' 81 msg = 'recipe parse progress bar should update to 50%'
@@ -94,11 +96,11 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
94 96
95 selector = base_selector + '[data-build-state="Starting"]' 97 selector = base_selector + '[data-build-state="Starting"]'
96 element = self.wait_until_visible(selector) 98 element = self.wait_until_visible(selector)
97 self.assertRegexpMatches(element.get_attribute('innerHTML'), 99 self.assertRegex(element.get_attribute('innerHTML'),
98 'Tasks starting', 'build should show "tasks starting" status') 100 'Tasks starting', 'build should show "tasks starting" status')
99 101
100 # first task finished; check tasks progress bar 102 # first task finished; check tasks progress bar
101 task1.order = 1 103 task1.outcome = Task.OUTCOME_SUCCESS
102 task1.save() 104 task1.save()
103 105
104 self.get(url) 106 self.get(url)
@@ -107,7 +109,7 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
107 element = self.wait_until_visible(selector) 109 element = self.wait_until_visible(selector)
108 110
109 bar_selector = '#build-pc-done-bar-%s' % build.id 111 bar_selector = '#build-pc-done-bar-%s' % build.id
110 bar_element = element.find_element_by_css_selector(bar_selector) 112 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector)
111 113
112 task_bar_updated = lambda driver: \ 114 task_bar_updated = lambda driver: \
113 bar_element.get_attribute('style') == 'width: 50%;' 115 bar_element.get_attribute('style') == 'width: 50%;'
@@ -115,13 +117,13 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
115 element = Wait(self.driver).until(task_bar_updated, msg) 117 element = Wait(self.driver).until(task_bar_updated, msg)
116 118
117 # last task finished; check tasks progress bar updates 119 # last task finished; check tasks progress bar updates
118 task2.order = 2 120 task2.outcome = Task.OUTCOME_SUCCESS
119 task2.save() 121 task2.save()
120 122
121 self.get(url) 123 self.get(url)
122 124
123 element = self.wait_until_visible(selector) 125 element = self.wait_until_visible(selector)
124 bar_element = element.find_element_by_css_selector(bar_selector) 126 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector)
125 task_bar_updated = lambda driver: \ 127 task_bar_updated = lambda driver: \
126 bar_element.get_attribute('style') == 'width: 100%;' 128 bar_element.get_attribute('style') == 'width: 100%;'
127 msg = 'tasks progress bar should update to 100%' 129 msg = 'tasks progress bar should update to 100%'
@@ -183,7 +185,7 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
183 selector = '[data-latest-build-result="%s"] ' \ 185 selector = '[data-latest-build-result="%s"] ' \
184 '[data-build-state="Cancelling"]' % build.id 186 '[data-build-state="Cancelling"]' % build.id
185 element = self.wait_until_visible(selector) 187 element = self.wait_until_visible(selector)
186 self.assertRegexpMatches(element.get_attribute('innerHTML'), 188 self.assertRegex(element.get_attribute('innerHTML'),
187 'Cancelling the build', 'build should show "cancelling" status') 189 'Cancelling the build', 'build should show "cancelling" status')
188 190
189 # check cancelled state 191 # check cancelled state
@@ -195,5 +197,5 @@ class TestMostRecentBuildsStates(SeleniumTestCase):
195 selector = '[data-latest-build-result="%s"] ' \ 197 selector = '[data-latest-build-result="%s"] ' \
196 '[data-build-state="Cancelled"]' % build.id 198 '[data-build-state="Cancelled"]' % build.id
197 element = self.wait_until_visible(selector) 199 element = self.wait_until_visible(selector)
198 self.assertRegexpMatches(element.get_attribute('innerHTML'), 200 self.assertRegex(element.get_attribute('innerHTML'),
199 'Build cancelled', 'build should show "cancelled" status') 201 'Build cancelled', 'build should show "cancelled" status')
diff --git a/bitbake/lib/toaster/tests/browser/test_new_custom_image_page.py b/bitbake/lib/toaster/tests/browser/test_new_custom_image_page.py
index 9906ae42a9..bf0304dbec 100644
--- a/bitbake/lib/toaster/tests/browser/test_new_custom_image_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_new_custom_image_page.py
@@ -6,6 +6,7 @@
6# 6#
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9from bldcontrol.models import BuildEnvironment
9 10
10from django.urls import reverse 11from django.urls import reverse
11from tests.browser.selenium_helpers import SeleniumTestCase 12from tests.browser.selenium_helpers import SeleniumTestCase
@@ -18,6 +19,9 @@ class TestNewCustomImagePage(SeleniumTestCase):
18 CUSTOM_IMAGE_NAME = 'roopa-doopa' 19 CUSTOM_IMAGE_NAME = 'roopa-doopa'
19 20
20 def setUp(self): 21 def setUp(self):
22 BuildEnvironment.objects.get_or_create(
23 betype=BuildEnvironment.TYPE_LOCAL,
24 )
21 release = Release.objects.create( 25 release = Release.objects.create(
22 name='baz', 26 name='baz',
23 bitbake_version=BitbakeVersion.objects.create(name='v1') 27 bitbake_version=BitbakeVersion.objects.create(name='v1')
@@ -41,11 +45,16 @@ class TestNewCustomImagePage(SeleniumTestCase):
41 ) 45 )
42 46
43 # add a fake image recipe to the layer that can be customised 47 # add a fake image recipe to the layer that can be customised
48 builldir = os.environ.get('BUILDDIR', './')
44 self.recipe = Recipe.objects.create( 49 self.recipe = Recipe.objects.create(
45 name='core-image-minimal', 50 name='core-image-minimal',
46 layer_version=layer_version, 51 layer_version=layer_version,
52 file_path=f'{builldir}/core-image-minimal.bb',
47 is_image=True 53 is_image=True
48 ) 54 )
55 # create a tmp file for the recipe
56 with open(self.recipe.file_path, 'w') as f:
57 f.write('foo')
49 58
50 # another project with a custom image already in it 59 # another project with a custom image already in it
51 project2 = Project.objects.create(name='whoop', release=release) 60 project2 = Project.objects.create(name='whoop', release=release)
@@ -81,6 +90,7 @@ class TestNewCustomImagePage(SeleniumTestCase):
81 """ 90 """
82 url = reverse('newcustomimage', args=(self.project.id,)) 91 url = reverse('newcustomimage', args=(self.project.id,))
83 self.get(url) 92 self.get(url)
93 self.wait_until_visible('#global-nav')
84 94
85 self.click('button[data-recipe="%s"]' % self.recipe.id) 95 self.click('button[data-recipe="%s"]' % self.recipe.id)
86 96
@@ -128,7 +138,7 @@ class TestNewCustomImagePage(SeleniumTestCase):
128 """ 138 """
129 self._create_custom_image(self.recipe.name) 139 self._create_custom_image(self.recipe.name)
130 element = self.wait_until_visible('#invalid-name-help') 140 element = self.wait_until_visible('#invalid-name-help')
131 self.assertRegexpMatches(element.text.strip(), 141 self.assertRegex(element.text.strip(),
132 'image with this name already exists') 142 'image with this name already exists')
133 143
134 def test_new_duplicates_project_image(self): 144 def test_new_duplicates_project_image(self):
@@ -146,4 +156,4 @@ class TestNewCustomImagePage(SeleniumTestCase):
146 self._create_custom_image(custom_image_name) 156 self._create_custom_image(custom_image_name)
147 element = self.wait_until_visible('#invalid-name-help') 157 element = self.wait_until_visible('#invalid-name-help')
148 expected = 'An image with this name already exists in this project' 158 expected = 'An image with this name already exists in this project'
149 self.assertRegexpMatches(element.text.strip(), expected) 159 self.assertRegex(element.text.strip(), expected)
diff --git a/bitbake/lib/toaster/tests/browser/test_new_project_page.py b/bitbake/lib/toaster/tests/browser/test_new_project_page.py
index e20a1f686e..e50f236c32 100644
--- a/bitbake/lib/toaster/tests/browser/test_new_project_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_new_project_page.py
@@ -6,11 +6,11 @@
6# 6#
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9
10from django.urls import reverse 9from django.urls import reverse
11from tests.browser.selenium_helpers import SeleniumTestCase 10from tests.browser.selenium_helpers import SeleniumTestCase
12from selenium.webdriver.support.ui import Select 11from selenium.webdriver.support.ui import Select
13from selenium.common.exceptions import InvalidElementStateException 12from selenium.common.exceptions import InvalidElementStateException
13from selenium.webdriver.common.by import By
14 14
15from orm.models import Project, Release, BitbakeVersion 15from orm.models import Project, Release, BitbakeVersion
16 16
@@ -47,7 +47,7 @@ class TestNewProjectPage(SeleniumTestCase):
47 47
48 url = reverse('newproject') 48 url = reverse('newproject')
49 self.get(url) 49 self.get(url)
50 50 self.wait_until_visible('#new-project-name')
51 self.enter_text('#new-project-name', project_name) 51 self.enter_text('#new-project-name', project_name)
52 52
53 select = Select(self.find('#projectversion')) 53 select = Select(self.find('#projectversion'))
@@ -57,7 +57,8 @@ class TestNewProjectPage(SeleniumTestCase):
57 57
58 # We should get redirected to the new project's page with the 58 # We should get redirected to the new project's page with the
59 # notification at the top 59 # notification at the top
60 element = self.wait_until_visible('#project-created-notification') 60 element = self.wait_until_visible(
61 '#project-created-notification')
61 62
62 self.assertTrue(project_name in element.text, 63 self.assertTrue(project_name in element.text,
63 "New project name not in new project notification") 64 "New project name not in new project notification")
@@ -78,15 +79,20 @@ class TestNewProjectPage(SeleniumTestCase):
78 79
79 url = reverse('newproject') 80 url = reverse('newproject')
80 self.get(url) 81 self.get(url)
82 self.wait_until_visible('#new-project-name')
81 83
82 self.enter_text('#new-project-name', project_name) 84 self.enter_text('#new-project-name', project_name)
83 85
84 select = Select(self.find('#projectversion')) 86 select = Select(self.find('#projectversion'))
85 select.select_by_value(str(self.release.pk)) 87 select.select_by_value(str(self.release.pk))
86 88
87 element = self.wait_until_visible('#hint-error-project-name') 89 radio = self.driver.find_element(By.ID, 'type-new')
90 radio.click()
91
92 self.wait_until_visible('#hint-error-project-name')
93 element = self.find('#hint-error-project-name')
88 94
89 self.assertTrue(("Project names must be unique" in element.text), 95 self.assertIn("Project names must be unique", element.text,
90 "Did not find unique project name error message") 96 "Did not find unique project name error message")
91 97
92 # Try and click it anyway, if it submits we'll have a new project in 98 # Try and click it anyway, if it submits we'll have a new project in
diff --git a/bitbake/lib/toaster/tests/browser/test_project_builds_page.py b/bitbake/lib/toaster/tests/browser/test_project_builds_page.py
index 51717e72d4..0dba33b9c8 100644
--- a/bitbake/lib/toaster/tests/browser/test_project_builds_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_project_builds_page.py
@@ -7,6 +7,7 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10import re 11import re
11 12
12from django.urls import reverse 13from django.urls import reverse
@@ -22,7 +23,8 @@ class TestProjectBuildsPage(SeleniumTestCase):
22 CLI_BUILDS_PROJECT_NAME = 'command line builds' 23 CLI_BUILDS_PROJECT_NAME = 'command line builds'
23 24
24 def setUp(self): 25 def setUp(self):
25 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 26 builldir = os.environ.get('BUILDDIR', './')
27 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
26 branch='master', dirpath='') 28 branch='master', dirpath='')
27 release = Release.objects.create(name='release1', 29 release = Release.objects.create(name='release1',
28 bitbake_version=bbv) 30 bitbake_version=bbv)
diff --git a/bitbake/lib/toaster/tests/browser/test_project_config_page.py b/bitbake/lib/toaster/tests/browser/test_project_config_page.py
index 944bcb2631..b9de541efa 100644
--- a/bitbake/lib/toaster/tests/browser/test_project_config_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_project_config_page.py
@@ -7,10 +7,12 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10from django.urls import reverse 11from django.urls import reverse
11from tests.browser.selenium_helpers import SeleniumTestCase 12from tests.browser.selenium_helpers import SeleniumTestCase
12 13
13from orm.models import BitbakeVersion, Release, Project, ProjectVariable 14from orm.models import BitbakeVersion, Release, Project, ProjectVariable
15from selenium.webdriver.common.by import By
14 16
15class TestProjectConfigsPage(SeleniumTestCase): 17class TestProjectConfigsPage(SeleniumTestCase):
16 """ Test data at /project/X/builds is displayed correctly """ 18 """ Test data at /project/X/builds is displayed correctly """
@@ -21,7 +23,8 @@ class TestProjectConfigsPage(SeleniumTestCase):
21 'any of these characters' 23 'any of these characters'
22 24
23 def setUp(self): 25 def setUp(self):
24 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 26 builldir = os.environ.get('BUILDDIR', './')
27 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
25 branch='master', dirpath='') 28 branch='master', dirpath='')
26 release = Release.objects.create(name='release1', 29 release = Release.objects.create(name='release1',
27 bitbake_version=bbv) 30 bitbake_version=bbv)
@@ -66,7 +69,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
66 69
67 self.enter_text('#new-imagefs_types', imagefs_type) 70 self.enter_text('#new-imagefs_types', imagefs_type)
68 71
69 checkboxes = self.driver.find_elements_by_xpath("//input[@class='fs-checkbox-fstypes']") 72 checkboxes = self.driver.find_elements(By.XPATH, "//input[@class='fs-checkbox-fstypes']")
70 73
71 for checkbox in checkboxes: 74 for checkbox in checkboxes:
72 if checkbox.get_attribute("value") == "btrfs": 75 if checkbox.get_attribute("value") == "btrfs":
@@ -95,7 +98,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
95 for checkbox in checkboxes: 98 for checkbox in checkboxes:
96 if checkbox.get_attribute("value") == "cpio": 99 if checkbox.get_attribute("value") == "cpio":
97 checkbox.click() 100 checkbox.click()
98 element = self.driver.find_element_by_id('new-imagefs_types') 101 element = self.driver.find_element(By.ID, 'new-imagefs_types')
99 102
100 self.wait_until_visible('#new-imagefs_types') 103 self.wait_until_visible('#new-imagefs_types')
101 104
@@ -129,7 +132,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
129 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg) 132 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
130 133
131 # downloads dir path has a space 134 # downloads dir path has a space
132 self.driver.find_element_by_id('new-dl_dir').clear() 135 self.driver.find_element(By.ID, 'new-dl_dir').clear()
133 self.enter_text('#new-dl_dir', '/foo/bar a') 136 self.enter_text('#new-dl_dir', '/foo/bar a')
134 137
135 element = self.wait_until_visible('#hintError-dl_dir') 138 element = self.wait_until_visible('#hintError-dl_dir')
@@ -137,7 +140,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
137 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg) 140 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
138 141
139 # downloads dir path starts with ${...} but has a space 142 # downloads dir path starts with ${...} but has a space
140 self.driver.find_element_by_id('new-dl_dir').clear() 143 self.driver.find_element(By.ID,'new-dl_dir').clear()
141 self.enter_text('#new-dl_dir', '${TOPDIR}/down foo') 144 self.enter_text('#new-dl_dir', '${TOPDIR}/down foo')
142 145
143 element = self.wait_until_visible('#hintError-dl_dir') 146 element = self.wait_until_visible('#hintError-dl_dir')
@@ -145,18 +148,18 @@ class TestProjectConfigsPage(SeleniumTestCase):
145 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg) 148 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
146 149
147 # downloads dir path starts with / 150 # downloads dir path starts with /
148 self.driver.find_element_by_id('new-dl_dir').clear() 151 self.driver.find_element(By.ID,'new-dl_dir').clear()
149 self.enter_text('#new-dl_dir', '/bar/foo') 152 self.enter_text('#new-dl_dir', '/bar/foo')
150 153
151 hidden_element = self.driver.find_element_by_id('hintError-dl_dir') 154 hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
152 self.assertEqual(hidden_element.is_displayed(), False, 155 self.assertEqual(hidden_element.is_displayed(), False,
153 'downloads directory path valid but treated as invalid') 156 'downloads directory path valid but treated as invalid')
154 157
155 # downloads dir path starts with ${...} 158 # downloads dir path starts with ${...}
156 self.driver.find_element_by_id('new-dl_dir').clear() 159 self.driver.find_element(By.ID,'new-dl_dir').clear()
157 self.enter_text('#new-dl_dir', '${TOPDIR}/down') 160 self.enter_text('#new-dl_dir', '${TOPDIR}/down')
158 161
159 hidden_element = self.driver.find_element_by_id('hintError-dl_dir') 162 hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
160 self.assertEqual(hidden_element.is_displayed(), False, 163 self.assertEqual(hidden_element.is_displayed(), False,
161 'downloads directory path valid but treated as invalid') 164 'downloads directory path valid but treated as invalid')
162 165
@@ -184,7 +187,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
184 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg) 187 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
185 188
186 # path has a space 189 # path has a space
187 self.driver.find_element_by_id('new-sstate_dir').clear() 190 self.driver.find_element(By.ID, 'new-sstate_dir').clear()
188 self.enter_text('#new-sstate_dir', '/foo/bar a') 191 self.enter_text('#new-sstate_dir', '/foo/bar a')
189 192
190 element = self.wait_until_visible('#hintError-sstate_dir') 193 element = self.wait_until_visible('#hintError-sstate_dir')
@@ -192,7 +195,7 @@ class TestProjectConfigsPage(SeleniumTestCase):
192 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg) 195 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
193 196
194 # path starts with ${...} but has a space 197 # path starts with ${...} but has a space
195 self.driver.find_element_by_id('new-sstate_dir').clear() 198 self.driver.find_element(By.ID,'new-sstate_dir').clear()
196 self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo') 199 self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo')
197 200
198 element = self.wait_until_visible('#hintError-sstate_dir') 201 element = self.wait_until_visible('#hintError-sstate_dir')
@@ -200,18 +203,18 @@ class TestProjectConfigsPage(SeleniumTestCase):
200 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg) 203 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
201 204
202 # path starts with / 205 # path starts with /
203 self.driver.find_element_by_id('new-sstate_dir').clear() 206 self.driver.find_element(By.ID,'new-sstate_dir').clear()
204 self.enter_text('#new-sstate_dir', '/bar/foo') 207 self.enter_text('#new-sstate_dir', '/bar/foo')
205 208
206 hidden_element = self.driver.find_element_by_id('hintError-sstate_dir') 209 hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
207 self.assertEqual(hidden_element.is_displayed(), False, 210 self.assertEqual(hidden_element.is_displayed(), False,
208 'sstate directory path valid but treated as invalid') 211 'sstate directory path valid but treated as invalid')
209 212
210 # paths starts with ${...} 213 # paths starts with ${...}
211 self.driver.find_element_by_id('new-sstate_dir').clear() 214 self.driver.find_element(By.ID, 'new-sstate_dir').clear()
212 self.enter_text('#new-sstate_dir', '${TOPDIR}/down') 215 self.enter_text('#new-sstate_dir', '${TOPDIR}/down')
213 216
214 hidden_element = self.driver.find_element_by_id('hintError-sstate_dir') 217 hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
215 self.assertEqual(hidden_element.is_displayed(), False, 218 self.assertEqual(hidden_element.is_displayed(), False,
216 'sstate directory path valid but treated as invalid') 219 'sstate directory path valid but treated as invalid')
217 220
diff --git a/bitbake/lib/toaster/tests/browser/test_sample.py b/bitbake/lib/toaster/tests/browser/test_sample.py
index b0067c21cd..f04f1d9a16 100644
--- a/bitbake/lib/toaster/tests/browser/test_sample.py
+++ b/bitbake/lib/toaster/tests/browser/test_sample.py
@@ -27,3 +27,13 @@ class TestSample(SeleniumTestCase):
27 self.get(url) 27 self.get(url)
28 brand_link = self.find('.toaster-navbar-brand a.brand') 28 brand_link = self.find('.toaster-navbar-brand a.brand')
29 self.assertEqual(brand_link.text.strip(), 'Toaster') 29 self.assertEqual(brand_link.text.strip(), 'Toaster')
30
31 def test_no_builds_message(self):
32 """ Test that a message is shown when there are no builds """
33 url = reverse('all-builds')
34 self.get(url)
35 self.wait_until_visible('#empty-state-allbuildstable') # wait for the empty state div to appear
36 div_msg = self.find('#empty-state-allbuildstable .alert-info')
37
38 msg = 'Sorry - no data found'
39 self.assertEqual(div_msg.text, msg)
diff --git a/bitbake/lib/toaster/tests/browser/test_toastertable_ui.py b/bitbake/lib/toaster/tests/browser/test_toastertable_ui.py
index e82d5ec654..691aca1ef0 100644
--- a/bitbake/lib/toaster/tests/browser/test_toastertable_ui.py
+++ b/bitbake/lib/toaster/tests/browser/test_toastertable_ui.py
@@ -8,11 +8,13 @@
8# 8#
9 9
10from datetime import datetime 10from datetime import datetime
11import os
11 12
12from django.urls import reverse 13from django.urls import reverse
13from django.utils import timezone 14from django.utils import timezone
14from tests.browser.selenium_helpers import SeleniumTestCase 15from tests.browser.selenium_helpers import SeleniumTestCase
15from orm.models import BitbakeVersion, Release, Project, Build 16from orm.models import BitbakeVersion, Release, Project, Build
17from selenium.webdriver.common.by import By
16 18
17class TestToasterTableUI(SeleniumTestCase): 19class TestToasterTableUI(SeleniumTestCase):
18 """ 20 """
@@ -33,7 +35,7 @@ class TestToasterTableUI(SeleniumTestCase):
33 table: WebElement for a ToasterTable 35 table: WebElement for a ToasterTable
34 """ 36 """
35 selector = 'thead a.sorted' 37 selector = 'thead a.sorted'
36 heading = table.find_element_by_css_selector(selector) 38 heading = table.find_element(By.CSS_SELECTOR, selector)
37 return heading.get_attribute('innerHTML').strip() 39 return heading.get_attribute('innerHTML').strip()
38 40
39 def _get_datetime_from_cell(self, row, selector): 41 def _get_datetime_from_cell(self, row, selector):
@@ -45,7 +47,7 @@ class TestToasterTableUI(SeleniumTestCase):
45 selector: CSS selector to use to find the cell containing the date time 47 selector: CSS selector to use to find the cell containing the date time
46 string 48 string
47 """ 49 """
48 cell = row.find_element_by_css_selector(selector) 50 cell = row.find_element(By.CSS_SELECTOR, selector)
49 cell_text = cell.get_attribute('innerHTML').strip() 51 cell_text = cell.get_attribute('innerHTML').strip()
50 return datetime.strptime(cell_text, '%d/%m/%y %H:%M') 52 return datetime.strptime(cell_text, '%d/%m/%y %H:%M')
51 53
@@ -58,7 +60,8 @@ class TestToasterTableUI(SeleniumTestCase):
58 later = now + timezone.timedelta(hours=1) 60 later = now + timezone.timedelta(hours=1)
59 even_later = later + timezone.timedelta(hours=1) 61 even_later = later + timezone.timedelta(hours=1)
60 62
61 bbv = BitbakeVersion.objects.create(name='test bbv', giturl='/tmp/', 63 builldir = os.environ.get('BUILDDIR', './')
64 bbv = BitbakeVersion.objects.create(name='test bbv', giturl=f'{builldir}/',
62 branch='master', dirpath='') 65 branch='master', dirpath='')
63 release = Release.objects.create(name='test release', 66 release = Release.objects.create(name='test release',
64 branch_name='master', 67 branch_name='master',
@@ -105,7 +108,7 @@ class TestToasterTableUI(SeleniumTestCase):
105 self.click('#checkbox-started_on') 108 self.click('#checkbox-started_on')
106 109
107 # sort by started_on column 110 # sort by started_on column
108 links = table.find_elements_by_css_selector('th.started_on a') 111 links = table.find_elements(By.CSS_SELECTOR, 'th.started_on a')
109 for link in links: 112 for link in links:
110 if link.get_attribute('innerHTML').strip() == 'Started on': 113 if link.get_attribute('innerHTML').strip() == 'Started on':
111 link.click() 114 link.click()
diff --git a/bitbake/lib/toaster/tests/builds/buildtest.py b/bitbake/lib/toaster/tests/builds/buildtest.py
index 872bbd3775..e54d561334 100644
--- a/bitbake/lib/toaster/tests/builds/buildtest.py
+++ b/bitbake/lib/toaster/tests/builds/buildtest.py
@@ -88,7 +88,7 @@ def load_build_environment():
88class BuildTest(unittest.TestCase): 88class BuildTest(unittest.TestCase):
89 89
90 PROJECT_NAME = "Testbuild" 90 PROJECT_NAME = "Testbuild"
91 BUILDDIR = "/tmp/build/" 91 BUILDDIR = os.environ.get("BUILDDIR")
92 92
93 def build(self, target): 93 def build(self, target):
94 # So that the buildinfo helper uses the test database' 94 # So that the buildinfo helper uses the test database'
@@ -116,10 +116,19 @@ class BuildTest(unittest.TestCase):
116 project = Project.objects.create_project(name=BuildTest.PROJECT_NAME, 116 project = Project.objects.create_project(name=BuildTest.PROJECT_NAME,
117 release=release) 117 release=release)
118 118
119 passthrough_variable_names = ["SSTATE_DIR", "DL_DIR", "SSTATE_MIRRORS", "BB_HASHSERVE", "BB_HASHSERVE_UPSTREAM"]
120 for variable_name in passthrough_variable_names:
121 current_variable = os.environ.get(variable_name)
122 if current_variable:
123 ProjectVariable.objects.get_or_create(
124 name=variable_name,
125 value=current_variable,
126 project=project)
127
119 if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"): 128 if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"):
120 ProjectVariable.objects.get_or_create( 129 ProjectVariable.objects.get_or_create(
121 name="SSTATE_MIRRORS", 130 name="SSTATE_MIRRORS",
122 value="file://.* http://autobuilder.yoctoproject.org/pub/sstate/PATH;downloadfilename=PATH", 131 value="file://.* http://sstate.yoctoproject.org/all/PATH;downloadfilename=PATH",
123 project=project) 132 project=project)
124 133
125 ProjectTarget.objects.create(project=project, 134 ProjectTarget.objects.create(project=project,
diff --git a/bitbake/lib/toaster/tests/builds/test_core_image_min.py b/bitbake/lib/toaster/tests/builds/test_core_image_min.py
index 44b6cbec7b..c5bfdbfbb5 100644
--- a/bitbake/lib/toaster/tests/builds/test_core_image_min.py
+++ b/bitbake/lib/toaster/tests/builds/test_core_image_min.py
@@ -10,6 +10,7 @@
10# Ionut Chisanovici, Paul Eggleton and Cristian Iorga 10# Ionut Chisanovici, Paul Eggleton and Cristian Iorga
11 11
12import os 12import os
13import pytest
13 14
14from django.db.models import Q 15from django.db.models import Q
15 16
@@ -20,12 +21,13 @@ from orm.models import CustomImagePackage
20 21
21from tests.builds.buildtest import BuildTest 22from tests.builds.buildtest import BuildTest
22 23
23 24@pytest.mark.order(4)
25@pytest.mark.django_db(True)
24class BuildCoreImageMinimal(BuildTest): 26class BuildCoreImageMinimal(BuildTest):
25 """Build core-image-minimal and test the results""" 27 """Build core-image-minimal and test the results"""
26 28
27 def setUp(self): 29 def setUp(self):
28 self.completed_build = self.build("core-image-minimal") 30 self.completed_build = self.target_already_built("core-image-minimal")
29 31
30 # Check if build name is unique - tc_id=795 32 # Check if build name is unique - tc_id=795
31 def test_Build_Unique_Name(self): 33 def test_Build_Unique_Name(self):
@@ -44,17 +46,6 @@ class BuildCoreImageMinimal(BuildTest):
44 total_builds, 46 total_builds,
45 msg='Build cooker log path is not unique') 47 msg='Build cooker log path is not unique')
46 48
47 # Check if task order is unique for one build - tc=824
48 def test_Task_Unique_Order(self):
49 total_task_order = Task.objects.filter(
50 build=self.built).values('order').count()
51 distinct_task_order = Task.objects.filter(
52 build=self.completed_build).values('order').distinct().count()
53
54 self.assertEqual(total_task_order,
55 distinct_task_order,
56 msg='Errors task order is not unique')
57
58 # Check task order sequence for one build - tc=825 49 # Check task order sequence for one build - tc=825
59 def test_Task_Order_Sequence(self): 50 def test_Task_Order_Sequence(self):
60 cnt_err = [] 51 cnt_err = []
@@ -98,7 +89,6 @@ class BuildCoreImageMinimal(BuildTest):
98 'task_name', 89 'task_name',
99 'sstate_result') 90 'sstate_result')
100 cnt_err = [] 91 cnt_err = []
101
102 for task in tasks: 92 for task in tasks:
103 if (task['sstate_result'] != Task.SSTATE_NA and 93 if (task['sstate_result'] != Task.SSTATE_NA and
104 task['sstate_result'] != Task.SSTATE_MISS): 94 task['sstate_result'] != Task.SSTATE_MISS):
@@ -221,6 +211,7 @@ class BuildCoreImageMinimal(BuildTest):
221 # orm_build.outcome=0 then if the file exists and its size matches 211 # orm_build.outcome=0 then if the file exists and its size matches
222 # the file_size value. Need to add the tc in the test run 212 # the file_size value. Need to add the tc in the test run
223 def test_Target_File_Name_Populated(self): 213 def test_Target_File_Name_Populated(self):
214 cnt_err = []
224 builds = Build.objects.filter(outcome=0).values('id') 215 builds = Build.objects.filter(outcome=0).values('id')
225 for build in builds: 216 for build in builds:
226 targets = Target.objects.filter( 217 targets = Target.objects.filter(
@@ -230,7 +221,6 @@ class BuildCoreImageMinimal(BuildTest):
230 target_id=target['id']).values('id', 221 target_id=target['id']).values('id',
231 'file_name', 222 'file_name',
232 'file_size') 223 'file_size')
233 cnt_err = []
234 for file_info in target_files: 224 for file_info in target_files:
235 target_id = file_info['id'] 225 target_id = file_info['id']
236 target_file_name = file_info['file_name'] 226 target_file_name = file_info['file_name']
diff --git a/bitbake/lib/toaster/tests/commands/test_loaddata.py b/bitbake/lib/toaster/tests/commands/test_loaddata.py
index 9e8d5553cf..7d04f030ee 100644
--- a/bitbake/lib/toaster/tests/commands/test_loaddata.py
+++ b/bitbake/lib/toaster/tests/commands/test_loaddata.py
@@ -6,13 +6,13 @@
6# 6#
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9import pytest
10from django.test import TestCase 10from django.test import TestCase
11from django.core import management 11from django.core import management
12 12
13from orm.models import Layer_Version, Layer, Release, ToasterSetting 13from orm.models import Layer_Version, Layer, Release, ToasterSetting
14 14
15 15@pytest.mark.order(2)
16class TestLoadDataFixtures(TestCase): 16class TestLoadDataFixtures(TestCase):
17 """ Test loading our 3 provided fixtures """ 17 """ Test loading our 3 provided fixtures """
18 def test_run_loaddata_poky_command(self): 18 def test_run_loaddata_poky_command(self):
diff --git a/bitbake/lib/toaster/tests/commands/test_lsupdates.py b/bitbake/lib/toaster/tests/commands/test_lsupdates.py
index 3c4fbe0550..30c6eeb4ac 100644
--- a/bitbake/lib/toaster/tests/commands/test_lsupdates.py
+++ b/bitbake/lib/toaster/tests/commands/test_lsupdates.py
@@ -7,12 +7,13 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import pytest
10from django.test import TestCase 11from django.test import TestCase
11from django.core import management 12from django.core import management
12 13
13from orm.models import Layer_Version, Machine, Recipe 14from orm.models import Layer_Version, Machine, Recipe
14 15
15 16@pytest.mark.order(3)
16class TestLayerIndexUpdater(TestCase): 17class TestLayerIndexUpdater(TestCase):
17 def test_run_lsupdates_command(self): 18 def test_run_lsupdates_command(self):
18 # Load some release information for us to fetch from the layer index 19 # Load some release information for us to fetch from the layer index
diff --git a/bitbake/lib/toaster/tests/commands/test_runbuilds.py b/bitbake/lib/toaster/tests/commands/test_runbuilds.py
index e223b95fcb..849c227edc 100644
--- a/bitbake/lib/toaster/tests/commands/test_runbuilds.py
+++ b/bitbake/lib/toaster/tests/commands/test_runbuilds.py
@@ -19,12 +19,14 @@ import time
19import subprocess 19import subprocess
20import signal 20import signal
21 21
22import logging
23
22 24
23class KillRunbuilds(threading.Thread): 25class KillRunbuilds(threading.Thread):
24 """ Kill the runbuilds process after an amount of time """ 26 """ Kill the runbuilds process after an amount of time """
25 def __init__(self, *args, **kwargs): 27 def __init__(self, *args, **kwargs):
26 super(KillRunbuilds, self).__init__(*args, **kwargs) 28 super(KillRunbuilds, self).__init__(*args, **kwargs)
27 self.setDaemon(True) 29 self.daemon = True
28 30
29 def run(self): 31 def run(self):
30 time.sleep(5) 32 time.sleep(5)
@@ -34,9 +36,12 @@ class KillRunbuilds(threading.Thread):
34 pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."), 36 pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."),
35 ".runbuilds.pid") 37 ".runbuilds.pid")
36 38
37 with open(pidfile_path) as pidfile: 39 try:
38 pid = pidfile.read() 40 with open(pidfile_path) as pidfile:
39 os.kill(int(pid), signal.SIGTERM) 41 pid = pidfile.read()
42 os.kill(int(pid), signal.SIGTERM)
43 except ProcessLookupError:
44 logging.warning("Runbuilds not running or already killed")
40 45
41 46
42class TestCommands(TestCase): 47class TestCommands(TestCase):
diff --git a/bitbake/lib/toaster/tests/db/test_db.py b/bitbake/lib/toaster/tests/db/test_db.py
index 0410422276..072ab94363 100644
--- a/bitbake/lib/toaster/tests/db/test_db.py
+++ b/bitbake/lib/toaster/tests/db/test_db.py
@@ -23,6 +23,7 @@
23# SOFTWARE. 23# SOFTWARE.
24 24
25import sys 25import sys
26import pytest
26 27
27try: 28try:
28 from StringIO import StringIO 29 from StringIO import StringIO
@@ -47,7 +48,7 @@ def capture(command, *args, **kwargs):
47def makemigrations(): 48def makemigrations():
48 management.call_command('makemigrations') 49 management.call_command('makemigrations')
49 50
50 51@pytest.mark.order(1)
51class MigrationTest(TestCase): 52class MigrationTest(TestCase):
52 53
53 def testPendingMigration(self): 54 def testPendingMigration(self):
diff --git a/bitbake/lib/toaster/tests/functional/functional_helpers.py b/bitbake/lib/toaster/tests/functional/functional_helpers.py
index 5c4ea71794..e28f2024f5 100644
--- a/bitbake/lib/toaster/tests/functional/functional_helpers.py
+++ b/bitbake/lib/toaster/tests/functional/functional_helpers.py
@@ -11,35 +11,58 @@ import os
11import logging 11import logging
12import subprocess 12import subprocess
13import signal 13import signal
14import time
15import re 14import re
15import requests
16 16
17from django.urls import reverse
17from tests.browser.selenium_helpers_base import SeleniumTestCaseBase 18from tests.browser.selenium_helpers_base import SeleniumTestCaseBase
18from tests.builds.buildtest import load_build_environment 19from selenium.webdriver.common.by import By
20from selenium.webdriver.support.select import Select
21from selenium.common.exceptions import NoSuchElementException
19 22
20logger = logging.getLogger("toaster") 23logger = logging.getLogger("toaster")
24toaster_processes = []
21 25
22class SeleniumFunctionalTestCase(SeleniumTestCaseBase): 26class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
23 wait_toaster_time = 5 27 wait_toaster_time = 10
24 28
25 @classmethod 29 @classmethod
26 def setUpClass(cls): 30 def setUpClass(cls):
27 # So that the buildinfo helper uses the test database' 31 # So that the buildinfo helper uses the test database'
28 if os.environ.get('DJANGO_SETTINGS_MODULE', '') != \ 32 if os.environ.get('DJANGO_SETTINGS_MODULE', '') != \
29 'toastermain.settings_test': 33 'toastermain.settings_test':
30 raise RuntimeError("Please initialise django with the tests settings: " \ 34 raise RuntimeError("Please initialise django with the tests settings: "
31 "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") 35 "DJANGO_SETTINGS_MODULE='toastermain.settings_test'")
32 36
33 load_build_environment() 37 # Wait for any known toaster processes to exit
38 global toaster_processes
39 for toaster_process in toaster_processes:
40 try:
41 os.waitpid(toaster_process, os.WNOHANG)
42 except ChildProcessError:
43 pass
34 44
35 # start toaster 45 # start toaster
36 cmd = "bash -c 'source toaster start'" 46 cmd = "bash -c 'source toaster start'"
37 p = subprocess.Popen( 47 start_process = subprocess.Popen(
38 cmd, 48 cmd,
39 cwd=os.environ.get("BUILDDIR"), 49 cwd=os.environ.get("BUILDDIR"),
40 shell=True) 50 shell=True)
41 if p.wait() != 0: 51 toaster_processes = [start_process.pid]
42 raise RuntimeError("Can't initialize toaster") 52 if start_process.wait() != 0:
53 port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip()
54 message = ''
55 if port_use:
56 process_id = port_use.split()[1]
57 process = os.popen(f"ps -o cmd= -p {process_id}").read().strip()
58 message = f"Port 8000 occupied by {process}"
59 raise RuntimeError(f"Can't initialize toaster. {message}")
60
61 builddir = os.environ.get("BUILDDIR")
62 with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f:
63 toaster_processes.append(int(f.read()))
64 with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f:
65 toaster_processes.append(int(f.read()))
43 66
44 super(SeleniumFunctionalTestCase, cls).setUpClass() 67 super(SeleniumFunctionalTestCase, cls).setUpClass()
45 cls.live_server_url = 'http://localhost:8000/' 68 cls.live_server_url = 'http://localhost:8000/'
@@ -48,22 +71,30 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
48 def tearDownClass(cls): 71 def tearDownClass(cls):
49 super(SeleniumFunctionalTestCase, cls).tearDownClass() 72 super(SeleniumFunctionalTestCase, cls).tearDownClass()
50 73
51 # XXX: source toaster stop gets blocked, to review why? 74 global toaster_processes
52 # from now send SIGTERM by hand
53 time.sleep(cls.wait_toaster_time)
54 builddir = os.environ.get("BUILDDIR")
55 75
56 with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: 76 cmd = "bash -c 'source toaster stop'"
57 toastermain_pid = int(f.read()) 77 stop_process = subprocess.Popen(
58 os.kill(toastermain_pid, signal.SIGTERM) 78 cmd,
59 with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: 79 cwd=os.environ.get("BUILDDIR"),
60 runbuilds_pid = int(f.read()) 80 shell=True)
61 os.kill(runbuilds_pid, signal.SIGTERM) 81 # Toaster stop has been known to hang in these tests so force kill if it stalls
82 try:
83 if stop_process.wait(cls.wait_toaster_time) != 0:
84 raise Exception('Toaster stop process failed')
85 except Exception as e:
86 if e is subprocess.TimeoutExpired:
87 print('Toaster stop process took too long. Force killing toaster...')
88 else:
89 print('Toaster stop process failed. Force killing toaster...')
90 stop_process.kill()
91 for toaster_process in toaster_processes:
92 os.kill(toaster_process, signal.SIGTERM)
62 93
63 94
64 def get_URL(self): 95 def get_URL(self):
65 rc=self.get_page_source() 96 rc=self.get_page_source()
66 project_url=re.search("(projectPageUrl\s:\s\")(.*)(\",)",rc) 97 project_url=re.search(r"(projectPageUrl\s:\s\")(.*)(\",)",rc)
67 return project_url.group(2) 98 return project_url.group(2)
68 99
69 100
@@ -74,8 +105,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
74 """ 105 """
75 try: 106 try:
76 table_element = self.get_table_element(table_id) 107 table_element = self.get_table_element(table_id)
77 element = table_element.find_element_by_link_text(link_text) 108 element = table_element.find_element(By.LINK_TEXT, link_text)
78 except self.NoSuchElementException: 109 except NoSuchElementException:
79 print('no element found') 110 print('no element found')
80 raise 111 raise
81 return element 112 return element
@@ -85,8 +116,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
85#return whole-table element 116#return whole-table element
86 element_xpath = "//*[@id='" + table_id + "']" 117 element_xpath = "//*[@id='" + table_id + "']"
87 try: 118 try:
88 element = self.driver.find_element_by_xpath(element_xpath) 119 element = self.driver.find_element(By.XPATH, element_xpath)
89 except self.NoSuchElementException: 120 except NoSuchElementException:
90 raise 121 raise
91 return element 122 return element
92 row = coordinate[0] 123 row = coordinate[0]
@@ -95,8 +126,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
95#return whole-row element 126#return whole-row element
96 element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]" 127 element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]"
97 try: 128 try:
98 element = self.driver.find_element_by_xpath(element_xpath) 129 element = self.driver.find_element(By.XPATH, element_xpath)
99 except self.NoSuchElementException: 130 except NoSuchElementException:
100 return False 131 return False
101 return element 132 return element
102#now we are looking for an element with specified X and Y 133#now we are looking for an element with specified X and Y
@@ -104,7 +135,90 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
104 135
105 element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]/td[" + str(column) + "]" 136 element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]/td[" + str(column) + "]"
106 try: 137 try:
107 element = self.driver.find_element_by_xpath(element_xpath) 138 element = self.driver.find_element(By.XPATH, element_xpath)
108 except self.NoSuchElementException: 139 except NoSuchElementException:
109 return False 140 return False
110 return element 141 return element
142
143 def create_new_project(
144 self,
145 project_name,
146 release,
147 release_title,
148 merge_toaster_settings,
149 ):
150 """ Create/Test new project using:
151 - Project Name: Any string
152 - Release: Any string
153 - Merge Toaster settings: True or False
154 """
155
156 # Obtain a CSRF token from a suitable URL
157 projs = requests.get(self.live_server_url + reverse('newproject'))
158 csrftoken = projs.cookies.get('csrftoken')
159
160 # Use the projects typeahead to find out if the project already exists
161 req = requests.get(self.live_server_url + reverse('xhr_projectstypeahead'), {'search': project_name, 'format' : 'json'})
162 data = req.json()
163 # Delete any existing projects
164 for result in data['results']:
165 del_url = reverse('xhr_project', args=(result['id'],))
166 del_response = requests.delete(self.live_server_url + del_url, cookies={'csrftoken': csrftoken}, headers={'X-CSRFToken': csrftoken})
167 self.assertEqual(del_response.status_code, 200)
168
169 self.get(reverse('newproject'))
170 self.wait_until_visible('#new-project-name')
171 self.driver.find_element(By.ID,
172 "new-project-name").send_keys(project_name)
173
174 select = Select(self.find('#projectversion'))
175 select.select_by_value(release)
176
177 # check merge toaster settings
178 checkbox = self.find('.checkbox-mergeattr')
179 if merge_toaster_settings:
180 if not checkbox.is_selected():
181 checkbox.click()
182 else:
183 if checkbox.is_selected():
184 checkbox.click()
185
186 self.wait_until_clickable('#create-project-button')
187
188 self.driver.find_element(By.ID, "create-project-button").click()
189
190 element = self.wait_until_visible('#project-created-notification')
191 self.assertTrue(
192 self.element_exists('#project-created-notification'),
193 f"Project:{project_name} creation notification not shown"
194 )
195 self.assertTrue(
196 project_name in element.text,
197 f"New project name:{project_name} not in new project notification"
198 )
199
200 # Use the projects typeahead again to check the project now exists
201 req = requests.get(self.live_server_url + reverse('xhr_projectstypeahead'), {'search': project_name, 'format' : 'json'})
202 data = req.json()
203 self.assertGreater(len(data['results']), 0, f"New project:{project_name} not found in database")
204
205 project_id = data['results'][0]['id']
206
207 self.wait_until_visible('#project-release-title')
208
209 # check release
210 if release_title is not None:
211 self.assertTrue(re.search(
212 release_title,
213 self.driver.find_element(By.XPATH,
214 "//span[@id='project-release-title']"
215 ).text),
216 'The project release is not defined')
217
218 return project_id
219
220 def load_projects_page_helper(self):
221 self.wait_until_present('#projectstable')
222 # Need to wait for some data in the table too
223 self.wait_until_present('td[class="updated"]')
224
diff --git a/bitbake/lib/toaster/tests/functional/test_create_new_project.py b/bitbake/lib/toaster/tests/functional/test_create_new_project.py
new file mode 100644
index 0000000000..66213c736e
--- /dev/null
+++ b/bitbake/lib/toaster/tests/functional/test_create_new_project.py
@@ -0,0 +1,124 @@
1#! /usr/bin/env python3
2# BitBake Toaster UI tests implementation
3#
4# Copyright (C) 2023 Savoir-faire Linux
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import re
10import pytest
11from django.urls import reverse
12from selenium.webdriver.support.select import Select
13from tests.functional.functional_helpers import SeleniumFunctionalTestCase
14from selenium.webdriver.common.by import By
15
16class TestCreateNewProject(SeleniumFunctionalTestCase):
17
18 def test_create_new_project_master(self):
19 """ Test create new project using:
20 - Project Name: Any string
21 - Release: Yocto Project master (option value: 3)
22 - Merge Toaster settings: False
23 """
24 release = '3'
25 release_title = 'Yocto Project master'
26 project_name = 'projectmaster'
27 self.create_new_project(
28 project_name,
29 release,
30 release_title,
31 False,
32 )
33
34 def test_create_new_project_scarthgap(self):
35 """ Test create new project using:
36 - Project Name: Any string
37 - Release: Yocto Project 5.0 "Scarthgap" (option value: 1)
38 - Merge Toaster settings: True
39 """
40 release = '1'
41 release_title = 'Yocto Project 5.0 "Scarthgap"'
42 project_name = 'projectscarthgap'
43 self.create_new_project(
44 project_name,
45 release,
46 release_title,
47 True,
48 )
49
50 def test_create_new_project_kirkstone(self):
51 """ Test create new project using:
52 - Project Name: Any string
53 - Release: Yocto Project 4.0 "Kirkstone" (option value: 6)
54 - Merge Toaster settings: True
55 """
56 release = '7'
57 release_title = 'Yocto Project 4.0 "Kirkstone"'
58 project_name = 'projectkirkstone'
59 self.create_new_project(
60 project_name,
61 release,
62 release_title,
63 True,
64 )
65
66 def test_create_new_project_local(self):
67 """ Test create new project using:
68 - Project Name: Any string
69 - Release: Local Yocto Project (option value: 2)
70 - Merge Toaster settings: True
71 """
72 release = '2'
73 release_title = 'Local Yocto Project'
74 project_name = 'projectlocal'
75 self.create_new_project(
76 project_name,
77 release,
78 release_title,
79 True,
80 )
81
82 def test_create_new_project_without_name(self):
83 """ Test create new project without project name """
84 self.get(reverse('newproject'))
85
86 select = Select(self.find('#projectversion'))
87 select.select_by_value(str(3))
88
89 # Check input name has required attribute
90 input_name = self.driver.find_element(By.ID, "new-project-name")
91 self.assertIsNotNone(input_name.get_attribute('required'),
92 'Input name has not required attribute')
93
94 # Check create button is disabled
95 create_btn = self.driver.find_element(By.ID, "create-project-button")
96 self.assertIsNotNone(create_btn.get_attribute('disabled'),
97 'Create button is not disabled')
98
99 def test_import_new_project(self):
100 """ Test import new project using:
101 - Project Name: Any string
102 - Project type: select (Import command line project)
103 - Import existing project directory: Wrong Path
104 """
105 project_name = 'projectimport'
106 self.get(reverse('newproject'))
107 self.driver.find_element(By.ID,
108 "new-project-name").send_keys(project_name)
109 # select import project
110 self.find('#type-import').click()
111
112 # set wrong path
113 wrong_path = '/wrongpath'
114 self.driver.find_element(By.ID,
115 "import-project-dir").send_keys(wrong_path)
116 self.driver.find_element(By.ID, "create-project-button").click()
117
118 self.wait_until_visible('.alert-danger')
119
120 # check error message
121 self.assertTrue(self.element_exists('.alert-danger'),
122 'Alert message not shown')
123 self.assertTrue(wrong_path in self.find('.alert-danger').text,
124 "Wrong path not in alert message")
diff --git a/bitbake/lib/toaster/tests/functional/test_functional_basic.py b/bitbake/lib/toaster/tests/functional/test_functional_basic.py
index 5683e3873e..d5c9708617 100644
--- a/bitbake/lib/toaster/tests/functional/test_functional_basic.py
+++ b/bitbake/lib/toaster/tests/functional/test_functional_basic.py
@@ -8,223 +8,250 @@
8# 8#
9 9
10import re 10import re
11from django.urls import reverse
12import pytest
11from tests.functional.functional_helpers import SeleniumFunctionalTestCase 13from tests.functional.functional_helpers import SeleniumFunctionalTestCase
12from orm.models import Project 14from orm.models import Project
15from selenium.webdriver.common.by import By
16
17from tests.functional.utils import get_projectId_from_url
18
13 19
14class FuntionalTestBasic(SeleniumFunctionalTestCase): 20class FuntionalTestBasic(SeleniumFunctionalTestCase):
21 """Basic functional tests for Toaster"""
22 project_id = None
23 project_url = None
15 24
16# testcase (1514) 25 def setUp(self):
17 def test_create_slenium_project(self): 26 super(FuntionalTestBasic, self).setUp()
18 project_name = 'selenium-project' 27 if not FuntionalTestBasic.project_id:
19 self.get('') 28 FuntionalTestBasic.project_id = self.create_new_project('selenium-project', '3', None, False)
20 self.driver.find_element_by_link_text("To start building, create your first Toaster project").click()
21 self.driver.find_element_by_id("new-project-name").send_keys(project_name)
22 self.driver.find_element_by_id('projectversion').click()
23 self.driver.find_element_by_id("create-project-button").click()
24 element = self.wait_until_visible('#project-created-notification')
25 self.assertTrue(self.element_exists('#project-created-notification'),'Project creation notification not shown')
26 self.assertTrue(project_name in element.text,
27 "New project name not in new project notification")
28 self.assertTrue(Project.objects.filter(name=project_name).count(),
29 "New project not found in database")
30 29
31 # testcase (1515) 30 # testcase (1515)
32 def test_verify_left_bar_menu(self): 31 def test_verify_left_bar_menu(self):
33 self.get('') 32 self.get(reverse('all-projects'))
34 self.wait_until_visible('#projectstable') 33 self.load_projects_page_helper()
35 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 34 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
35 self.wait_until_present('#config-nav')
36 self.assertTrue(self.element_exists('#config-nav'),'Configuration Tab does not exist') 36 self.assertTrue(self.element_exists('#config-nav'),'Configuration Tab does not exist')
37 project_URL=self.get_URL() 37 project_URL=self.get_URL()
38 self.driver.find_element_by_xpath('//a[@href="'+project_URL+'"]').click() 38 self.driver.find_element(By.XPATH, '//a[@href="'+project_URL+'"]').click()
39 39
40 try: 40 try:
41 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'customimages/"'+"]").click() 41 self.wait_until_present('#config-nav')
42 self.assertTrue(re.search("Custom images",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'Custom images information is not loading properly') 42 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'customimages/"'+"]").click()
43 self.wait_until_present('#filter-modal-customimagestable')
43 except: 44 except:
44 self.fail(msg='No Custom images tab available') 45 self.fail(msg='No Custom images tab available')
46 self.assertTrue(re.search("Custom images",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'Custom images information is not loading properly')
45 47
46 try: 48 try:
47 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'images/"'+"]").click() 49 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'images/"'+"]").click()
48 self.assertTrue(re.search("Compatible image recipes",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Compatible image recipes information is not loading properly') 50 self.wait_until_present('#filter-modal-imagerecipestable')
49 except: 51 except:
50 self.fail(msg='No Compatible image tab available') 52 self.fail(msg='No Compatible image tab available')
53 self.assertTrue(re.search("Compatible image recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible image recipes information is not loading properly')
51 54
52 try: 55 try:
53 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'softwarerecipes/"'+"]").click() 56 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'softwarerecipes/"'+"]").click()
54 self.assertTrue(re.search("Compatible software recipes",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Compatible software recipe information is not loading properly') 57 self.wait_until_present('#filter-modal-softwarerecipestable')
55 except: 58 except:
56 self.fail(msg='No Compatible software recipe tab available') 59 self.fail(msg='No Compatible software recipe tab available')
60 self.assertTrue(re.search("Compatible software recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible software recipe information is not loading properly')
57 61
58 try: 62 try:
59 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'machines/"'+"]").click() 63 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'machines/"'+"]").click()
60 self.assertTrue(re.search("Compatible machines",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Compatible machine information is not loading properly') 64 self.wait_until_present('#filter-modal-machinestable')
61 except: 65 except:
62 self.fail(msg='No Compatible machines tab available') 66 self.fail(msg='No Compatible machines tab available')
67 self.assertTrue(re.search("Compatible machines",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible machine information is not loading properly')
63 68
64 try: 69 try:
65 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'layers/"'+"]").click() 70 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'layers/"'+"]").click()
66 self.assertTrue(re.search("Compatible layers",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Compatible layer information is not loading properly') 71 self.wait_until_present('#filter-modal-layerstable')
67 except: 72 except:
68 self.fail(msg='No Compatible layers tab available') 73 self.fail(msg='No Compatible layers tab available')
74 self.assertTrue(re.search("Compatible layers",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible layer information is not loading properly')
69 75
70 try: 76 try:
71 self.driver.find_element_by_xpath("//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'configuration"'+"]").click() 77 self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'configuration"'+"]").click()
72 self.assertTrue(re.search("Bitbake variables",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Bitbake variables information is not loading properly') 78 self.wait_until_present('#configvar-list')
73 except: 79 except:
74 self.fail(msg='No Bitbake variables tab available') 80 self.fail(msg='No Bitbake variables tab available')
81 self.assertTrue(re.search("Bitbake variables",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Bitbake variables information is not loading properly')
75 82
76# testcase (1516) 83# testcase (1516)
77 def test_review_configuration_information(self): 84 def test_review_configuration_information(self):
78 self.get('') 85 self.get(reverse('all-projects'))
79 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 86 self.load_projects_page_helper()
80 self.wait_until_visible('#projectstable')
81 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 87 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
82 project_URL=self.get_URL() 88 project_URL=self.get_URL()
83 89
90 # Machine section of page
91 self.wait_until_visible('#machine-section')
92 self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist')
93 self.assertTrue(re.search("qemux86-64",self.driver.find_element(By.XPATH, "//span[@id='project-machine-name']").text),'The machine type is not assigned')
84 try: 94 try:
85 self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist') 95 self.driver.find_element(By.XPATH, "//span[@id='change-machine-toggle']").click()
86 self.assertTrue(re.search("qemux86",self.driver.find_element_by_xpath("//span[@id='project-machine-name']").text),'The machine type is not assigned')
87 self.driver.find_element_by_xpath("//span[@id='change-machine-toggle']").click()
88 self.wait_until_visible('#select-machine-form') 96 self.wait_until_visible('#select-machine-form')
89 self.wait_until_visible('#cancel-machine-change') 97 self.wait_until_visible('#cancel-machine-change')
90 self.driver.find_element_by_xpath("//form[@id='select-machine-form']/a[@id='cancel-machine-change']").click() 98 self.driver.find_element(By.XPATH, "//form[@id='select-machine-form']/a[@id='cancel-machine-change']").click()
91 except: 99 except:
92 self.fail(msg='The machine information is wrong in the configuration page') 100 self.fail(msg='The machine information is wrong in the configuration page')
93 101
102 # Most built recipes section
103 self.wait_until_visible('#no-most-built')
94 try: 104 try:
95 self.driver.find_element_by_id('no-most-built') 105 self.driver.find_element(By.ID, 'no-most-built')
96 except: 106 except:
97 self.fail(msg='No Most built information in project detail page') 107 self.fail(msg='No Most built information in project detail page')
98 108
99 try: 109 # Project Release title
100 self.assertTrue(re.search("Yocto Project master",self.driver.find_element_by_xpath("//span[@id='project-release-title']").text),'The project release is not defined') 110 self.assertTrue(re.search("Yocto Project master",self.driver.find_element(By.XPATH, "//span[@id='project-release-title']").text), 'The project release is not defined in the project detail page')
101 except:
102 self.fail(msg='No project release title information in project detail page')
103 111
112 # List of layers in project
113 self.wait_until_visible('#layer-container')
114 self.driver.find_element(By.XPATH, "//div[@id='layer-container']")
115 self.assertTrue(re.search("3",self.driver.find_element(By.ID, "project-layers-count").text),'There should be 3 layers listed in the layer count')
104 try: 116 try:
105 self.driver.find_element_by_xpath("//div[@id='layer-container']") 117 layer_list = self.driver.find_element(By.ID, "layers-in-project-list")
106 self.assertTrue(re.search("3",self.driver.find_element_by_id("project-layers-count").text),'There should be 3 layers listed in the layer count') 118 layers = layer_list.find_elements(By.TAG_NAME, "li")
107 layer_list = self.driver.find_element_by_id("layers-in-project-list")
108 layers = layer_list.find_elements_by_tag_name("li")
109 for layer in layers:
110 if re.match ("openembedded-core",layer.text):
111 print ("openembedded-core layer is a default layer in the project configuration")
112 elif re.match ("meta-poky",layer.text):
113 print ("meta-poky layer is a default layer in the project configuration")
114 elif re.match ("meta-yocto-bsp",layer.text):
115 print ("meta-yocto-bsp is a default layer in the project configuratoin")
116 else:
117 self.fail(msg='default layers are missing from the project configuration')
118 except: 119 except:
119 self.fail(msg='No Layer information in project detail page') 120 self.fail(msg='No Layer information in project detail page')
120 121
122 for layer in layers:
123 if re.match ("openembedded-core", layer.text):
124 print ("openembedded-core layer is a default layer in the project configuration")
125 elif re.match ("meta-poky", layer.text):
126 print ("meta-poky layer is a default layer in the project configuration")
127 elif re.match ("meta-yocto-bsp", layer.text):
128 print ("meta-yocto-bsp is a default layer in the project configuratoin")
129 else:
130 self.fail(msg='default layers are missing from the project configuration')
131
121# testcase (1517) 132# testcase (1517)
122 def test_verify_machine_information(self): 133 def test_verify_machine_information(self):
123 self.get('') 134 self.get(reverse('all-projects'))
124 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 135 self.load_projects_page_helper()
125 self.wait_until_visible('#projectstable')
126 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 136 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
127 137
138 self.wait_until_visible('#machine-section')
139 self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist')
140 self.wait_until_visible('#project-machine-name')
141 self.assertTrue(re.search("qemux86-64",self.driver.find_element(By.ID, "project-machine-name").text),'The machine type is not assigned')
128 try: 142 try:
129 self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist') 143 self.driver.find_element(By.ID, "change-machine-toggle").click()
130 self.assertTrue(re.search("qemux86",self.driver.find_element_by_id("project-machine-name").text),'The machine type is not assigned')
131 self.driver.find_element_by_id("change-machine-toggle").click()
132 self.wait_until_visible('#select-machine-form') 144 self.wait_until_visible('#select-machine-form')
133 self.wait_until_visible('#cancel-machine-change') 145 self.wait_until_visible('#cancel-machine-change')
134 self.driver.find_element_by_id("cancel-machine-change").click() 146 self.driver.find_element(By.ID, "cancel-machine-change").click()
135 except: 147 except:
136 self.fail(msg='The machine information is wrong in the configuration page') 148 self.fail(msg='The machine information is wrong in the configuration page')
137 149
138# testcase (1518) 150# testcase (1518)
139 def test_verify_most_built_recipes_information(self): 151 def test_verify_most_built_recipes_information(self):
140 self.get('') 152 self.get(reverse('all-projects'))
141 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 153 self.load_projects_page_helper()
142 self.wait_until_visible('#projectstable')
143 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 154 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
155 self.wait_until_present('#config-nav')
144 project_URL=self.get_URL() 156 project_URL=self.get_URL()
145 157
158 self.wait_until_visible('#no-most-built')
159 self.assertTrue(re.search("You haven't built any recipes yet",self.driver.find_element(By.ID, "no-most-built").text),'Default message of no builds is not present')
146 try: 160 try:
147 self.assertTrue(re.search("You haven't built any recipes yet",self.driver.find_element_by_id("no-most-built").text),'Default message of no builds is not present') 161 self.driver.find_element(By.XPATH, "//div[@id='no-most-built']/p/a[@href="+'"'+project_URL+'images/"'+"]").click()
148 self.driver.find_element_by_xpath("//div[@id='no-most-built']/p/a[@href="+'"'+project_URL+'images/"'+"]").click()
149 self.assertTrue(re.search("Compatible image recipes",self.driver.find_element_by_xpath("//div[@class='col-md-10']").text),'The Choose a recipe to build link is not working properly')
150 except: 162 except:
151 self.fail(msg='No Most built information in project detail page') 163 self.fail(msg='No Most built information in project detail page')
164 self.wait_until_visible('#config-nav')
165 self.assertTrue(re.search("Compatible image recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Choose a recipe to build link is not working properly')
152 166
153# testcase (1519) 167# testcase (1519)
154 def test_verify_project_release_information(self): 168 def test_verify_project_release_information(self):
155 self.get('') 169 self.get(reverse('all-projects'))
156 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 170 self.load_projects_page_helper()
157 self.wait_until_visible('#projectstable')
158 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 171 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
159 172 self.wait_until_visible('#project-release-title')
160 try: 173 self.assertTrue(re.search("Yocto Project master",self.driver.find_element(By.ID, "project-release-title").text), 'No project release title information in project detail page')
161 self.assertTrue(re.search("Yocto Project master",self.driver.find_element_by_id("project-release-title").text),'The project release is not defined')
162 except:
163 self.fail(msg='No project release title information in project detail page')
164 174
165# testcase (1520) 175# testcase (1520)
166 def test_verify_layer_information(self): 176 def test_verify_layer_information(self):
167 self.get('') 177 self.get(reverse('all-projects'))
168 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 178 self.load_projects_page_helper()
169 self.wait_until_visible('#projectstable')
170 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 179 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
180 self.wait_until_present('#config-nav')
171 project_URL=self.get_URL() 181 project_URL=self.get_URL()
182 self.wait_until_visible('#layer-container')
183 self.driver.find_element(By.XPATH, "//div[@id='layer-container']")
184 self.wait_until_visible('#project-layers-count')
185 self.assertTrue(re.search("3",self.driver.find_element(By.ID, "project-layers-count").text),'There should be 3 layers listed in the layer count')
172 186
173 try: 187 try:
174 self.driver.find_element_by_xpath("//div[@id='layer-container']") 188 layer_list = self.driver.find_element(By.ID, "layers-in-project-list")
175 self.assertTrue(re.search("3",self.driver.find_element_by_id("project-layers-count").text),'There should be 3 layers listed in the layer count') 189 layers = layer_list.find_elements(By.TAG_NAME, "li")
176 layer_list = self.driver.find_element_by_id("layers-in-project-list") 190 except:
177 layers = layer_list.find_elements_by_tag_name("li") 191 self.fail(msg='No Layer information in project detail page')
178 192
179 for layer in layers: 193 for layer in layers:
180 if re.match ("openembedded-core",layer.text): 194 if re.match ("openembedded-core",layer.text):
181 print ("openembedded-core layer is a default layer in the project configuration") 195 print ("openembedded-core layer is a default layer in the project configuration")
182 elif re.match ("meta-poky",layer.text): 196 elif re.match ("meta-poky",layer.text):
183 print ("meta-poky layer is a default layer in the project configuration") 197 print ("meta-poky layer is a default layer in the project configuration")
184 elif re.match ("meta-yocto-bsp",layer.text): 198 elif re.match ("meta-yocto-bsp",layer.text):
185 print ("meta-yocto-bsp is a default layer in the project configuratoin") 199 print ("meta-yocto-bsp is a default layer in the project configuratoin")
186 else: 200 else:
187 self.fail(msg='default layers are missing from the project configuration') 201 self.fail(msg='default layers are missing from the project configuration')
188 202
189 self.driver.find_element_by_xpath("//input[@id='layer-add-input']") 203 try:
190 self.driver.find_element_by_xpath("//button[@id='add-layer-btn']") 204 self.driver.find_element(By.XPATH, "//input[@id='layer-add-input']")
191 self.driver.find_element_by_xpath("//div[@id='layer-container']/form[@class='form-inline']/p/a[@id='view-compatible-layers']") 205 self.driver.find_element(By.XPATH, "//button[@id='add-layer-btn']")
192 self.driver.find_element_by_xpath("//div[@id='layer-container']/form[@class='form-inline']/p/a[@href="+'"'+project_URL+'importlayer"'+"]") 206 self.driver.find_element(By.XPATH, "//div[@id='layer-container']/form[@class='form-inline']/p/a[@id='view-compatible-layers']")
207 self.driver.find_element(By.XPATH, "//div[@id='layer-container']/form[@class='form-inline']/p/a[@href="+'"'+project_URL+'importlayer"'+"]")
193 except: 208 except:
194 self.fail(msg='No Layer information in project detail page') 209 self.fail(msg='Layer configuration controls missing')
195 210
196# testcase (1521) 211# testcase (1521)
197 def test_verify_project_detail_links(self): 212 def test_verify_project_detail_links(self):
198 self.get('') 213 self.get(reverse('all-projects'))
199 self.driver.find_element_by_xpath("//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click() 214 self.load_projects_page_helper()
200 self.wait_until_visible('#projectstable')
201 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click() 215 self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
216 self.wait_until_present('#config-nav')
202 project_URL=self.get_URL() 217 project_URL=self.get_URL()
218 self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").click()
219 self.wait_until_visible('#topbar-configuration-tab')
220 self.assertTrue(re.search("Configuration",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").text), 'Configuration tab in project topbar is misspelled')
203 221
204 self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").click() 222 try:
205 self.assertTrue(re.search("Configuration",self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").text), 'Configuration tab in project topbar is misspelled') 223 self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").click()
224 except:
225 self.fail(msg='Builds tab information is not present')
206 226
227 self.wait_until_visible('#project-topbar')
228 self.assertTrue(re.search("Builds",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").text), 'Builds tab in project topbar is misspelled')
207 try: 229 try:
208 self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").click() 230 self.driver.find_element(By.XPATH, "//div[@id='empty-state-projectbuildstable']")
209 self.assertTrue(re.search("Builds",self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").text), 'Builds tab in project topbar is misspelled')
210 self.driver.find_element_by_xpath("//div[@id='empty-state-projectbuildstable']")
211 except: 231 except:
212 self.fail(msg='Builds tab information is not present') 232 self.fail(msg='Builds tab information is not present')
213 233
214 try: 234 try:
215 self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").click() 235 self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").click()
216 self.assertTrue(re.search("Import layer",self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").text), 'Import layer tab in project topbar is misspelled')
217 self.driver.find_element_by_xpath("//fieldset[@id='repo-select']")
218 self.driver.find_element_by_xpath("//fieldset[@id='git-repo']")
219 except: 236 except:
220 self.fail(msg='Import layer tab not loading properly') 237 self.fail(msg='Import layer tab not loading properly')
221 238
239 self.wait_until_visible('#project-topbar')
240 self.assertTrue(re.search("Import layer",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").text), 'Import layer tab in project topbar is misspelled')
222 try: 241 try:
223 self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").click() 242 self.driver.find_element(By.XPATH, "//fieldset[@id='repo-select']")
224 self.assertTrue(re.search("New custom image",self.driver.find_element_by_xpath("//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").text), 'New custom image tab in project topbar is misspelled') 243 self.driver.find_element(By.XPATH, "//fieldset[@id='git-repo']")
225 self.assertTrue(re.search("Select the image recipe you want to customise",self.driver.find_element_by_xpath("//div[@class='col-md-12']/h2").text),'The new custom image tab is not loading correctly') 244 except:
245 self.fail(msg='Import layer tab not loading properly')
246
247 try:
248 self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").click()
226 except: 249 except:
227 self.fail(msg='New custom image tab not loading properly') 250 self.fail(msg='New custom image tab not loading properly')
228 251
252 self.wait_until_visible('#project-topbar')
253 self.assertTrue(re.search("New custom image",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").text), 'New custom image tab in project topbar is misspelled')
254 self.assertTrue(re.search("Select the image recipe you want to customise",self.driver.find_element(By.XPATH, "//div[@class='col-md-12']/h2").text),'The new custom image tab is not loading correctly')
255
229 256
230 257
diff --git a/bitbake/lib/toaster/tests/functional/test_project_config.py b/bitbake/lib/toaster/tests/functional/test_project_config.py
new file mode 100644
index 0000000000..fcb1bc3284
--- /dev/null
+++ b/bitbake/lib/toaster/tests/functional/test_project_config.py
@@ -0,0 +1,294 @@
1#! /usr/bin/env python3 #
2# BitBake Toaster UI tests implementation
3#
4# Copyright (C) 2023 Savoir-faire Linux
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import string
10import pytest
11from django.urls import reverse
12from selenium.webdriver import Keys
13from selenium.webdriver.support.select import Select
14from selenium.common.exceptions import TimeoutException
15from tests.functional.functional_helpers import SeleniumFunctionalTestCase
16from selenium.webdriver.common.by import By
17
18from .utils import get_projectId_from_url
19
20class TestProjectConfig(SeleniumFunctionalTestCase):
21 project_id = None
22 PROJECT_NAME = 'TestProjectConfig'
23 INVALID_PATH_START_TEXT = 'The directory path should either start with a /'
24 INVALID_PATH_CHAR_TEXT = 'The directory path cannot include spaces or ' \
25 'any of these characters'
26
27 def _get_config_nav_item(self, index):
28 config_nav = self.find('#config-nav')
29 return config_nav.find_elements(By.TAG_NAME, 'li')[index]
30
31 def _navigate_bbv_page(self):
32 """ Navigate to project BitBake variables page """
33 # check if the menu is displayed
34 if TestProjectConfig.project_id is None:
35 TestProjectConfig.project_id = self.create_new_project(self.PROJECT_NAME, '3', None, True)
36
37 url = reverse('projectconf', args=(TestProjectConfig.project_id,))
38 self.get(url)
39 self.wait_until_visible('#config-nav')
40 bbv_page_link = self._get_config_nav_item(9)
41 bbv_page_link.click()
42 self.wait_until_visible('#config-nav')
43
44 def test_no_underscore_iamgefs_type(self):
45 """
46 Should not accept IMAGEFS_TYPE with an underscore
47 """
48 self._navigate_bbv_page()
49 imagefs_type = "foo_bar"
50
51 self.wait_until_visible('#change-image_fstypes-icon')
52
53 self.click('#change-image_fstypes-icon')
54
55 self.enter_text('#new-imagefs_types', imagefs_type)
56
57 element = self.wait_until_visible('#hintError-image-fs_type')
58
59 self.assertTrue(("A valid image type cannot include underscores" in element.text),
60 "Did not find underscore error message")
61
62 def test_checkbox_verification(self):
63 """
64 Should automatically check the checkbox if user enters value
65 text box, if value is there in the checkbox.
66 """
67 self._navigate_bbv_page()
68
69 imagefs_type = "btrfs"
70
71 self.wait_until_visible('#change-image_fstypes-icon')
72
73 self.click('#change-image_fstypes-icon')
74
75 self.enter_text('#new-imagefs_types', imagefs_type)
76
77 checkboxes = self.driver.find_elements(By.XPATH, "//input[@class='fs-checkbox-fstypes']")
78
79 for checkbox in checkboxes:
80 if checkbox.get_attribute("value") == "btrfs":
81 self.assertEqual(checkbox.is_selected(), True)
82
83 def test_textbox_with_checkbox_verification(self):
84 """
85 Should automatically add or remove value in textbox, if user checks
86 or unchecks checkboxes.
87 """
88 self._navigate_bbv_page()
89
90 self.wait_until_visible('#change-image_fstypes-icon')
91 self.click('#change-image_fstypes-icon')
92
93 checkboxes_selector = '.fs-checkbox-fstypes'
94
95 self.wait_until_visible(checkboxes_selector)
96 checkboxes = self.find_all(checkboxes_selector)
97
98 for checkbox in checkboxes:
99 if checkbox.get_attribute("value") == "cpio":
100 checkbox.click()
101 self.wait_until_visible('#new-imagefs_types')
102 element = self.driver.find_element(By.ID, 'new-imagefs_types')
103
104 self.assertTrue(("cpio" in element.get_attribute('value'),
105 "Imagefs not added into the textbox"))
106 checkbox.click()
107 self.assertTrue(("cpio" not in element.text),
108 "Image still present in the textbox")
109
110 def test_set_download_dir(self):
111 """
112 Validate the allowed and disallowed types in the directory field for
113 DL_DIR
114 """
115 self._navigate_bbv_page()
116
117 # activate the input to edit download dir
118 try:
119 change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon')
120 except TimeoutException:
121 # If download dir is not displayed, test is skipped
122 change_dl_dir_btn = None
123
124 if change_dl_dir_btn:
125 change_dl_dir_btn.click()
126
127 # downloads dir path doesn't start with / or ${...}
128 input_field = self.wait_until_visible('#new-dl_dir')
129 input_field.clear()
130 self.enter_text('#new-dl_dir', 'home/foo')
131 element = self.wait_until_visible('#hintError-initialChar-dl_dir')
132
133 msg = 'downloads directory path starts with invalid character but ' \
134 'treated as valid'
135 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
136
137 # downloads dir path has a space
138 self.driver.find_element(By.ID, 'new-dl_dir').clear()
139 self.enter_text('#new-dl_dir', '/foo/bar a')
140
141 element = self.wait_until_visible('#hintError-dl_dir')
142 msg = 'downloads directory path characters invalid but treated as valid'
143 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
144
145 # downloads dir path starts with ${...} but has a space
146 self.driver.find_element(By.ID,'new-dl_dir').clear()
147 self.enter_text('#new-dl_dir', '${TOPDIR}/down foo')
148
149 element = self.wait_until_visible('#hintError-dl_dir')
150 msg = 'downloads directory path characters invalid but treated as valid'
151 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
152
153 # downloads dir path starts with /
154 self.driver.find_element(By.ID,'new-dl_dir').clear()
155 self.enter_text('#new-dl_dir', '/bar/foo')
156
157 hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
158 self.assertEqual(hidden_element.is_displayed(), False,
159 'downloads directory path valid but treated as invalid')
160
161 # downloads dir path starts with ${...}
162 self.driver.find_element(By.ID,'new-dl_dir').clear()
163 self.enter_text('#new-dl_dir', '${TOPDIR}/down')
164
165 hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
166 self.assertEqual(hidden_element.is_displayed(), False,
167 'downloads directory path valid but treated as invalid')
168
169 def test_set_sstate_dir(self):
170 """
171 Validate the allowed and disallowed types in the directory field for
172 SSTATE_DIR
173 """
174 self._navigate_bbv_page()
175
176 try:
177 btn_chg_sstate_dir = self.wait_until_visible('#change-sstate_dir-icon')
178 self.click('#change-sstate_dir-icon')
179 except TimeoutException:
180 # If sstate_dir is not displayed, test is skipped
181 btn_chg_sstate_dir = None
182
183 if btn_chg_sstate_dir: # Skip continuation if sstate_dir is not displayed
184 # path doesn't start with / or ${...}
185 input_field = self.wait_until_visible('#new-sstate_dir')
186 input_field.clear()
187 self.enter_text('#new-sstate_dir', 'home/foo')
188 element = self.wait_until_visible('#hintError-initialChar-sstate_dir')
189
190 msg = 'sstate directory path starts with invalid character but ' \
191 'treated as valid'
192 self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
193
194 # path has a space
195 self.driver.find_element(By.ID, 'new-sstate_dir').clear()
196 self.enter_text('#new-sstate_dir', '/foo/bar a')
197
198 element = self.wait_until_visible('#hintError-sstate_dir')
199 msg = 'sstate directory path characters invalid but treated as valid'
200 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
201
202 # path starts with ${...} but has a space
203 self.driver.find_element(By.ID,'new-sstate_dir').clear()
204 self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo')
205
206 element = self.wait_until_visible('#hintError-sstate_dir')
207 msg = 'sstate directory path characters invalid but treated as valid'
208 self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
209
210 # path starts with /
211 self.driver.find_element(By.ID,'new-sstate_dir').clear()
212 self.enter_text('#new-sstate_dir', '/bar/foo')
213
214 hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
215 self.assertEqual(hidden_element.is_displayed(), False,
216 'sstate directory path valid but treated as invalid')
217
218 # paths starts with ${...}
219 self.driver.find_element(By.ID, 'new-sstate_dir').clear()
220 self.enter_text('#new-sstate_dir', '${TOPDIR}/down')
221
222 hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
223 self.assertEqual(hidden_element.is_displayed(), False,
224 'sstate directory path valid but treated as invalid')
225
226 def _change_bbv_value(self, **kwargs):
227 var_name, field, btn_id, input_id, value, save_btn, *_ = kwargs.values()
228 """ Change bitbake variable value """
229 self._navigate_bbv_page()
230 self.wait_until_visible(f'#{btn_id}')
231 if kwargs.get('new_variable'):
232 self.find(f"#{btn_id}").clear()
233 self.enter_text(f"#{btn_id}", f"{var_name}")
234 else:
235 self.click(f'#{btn_id}')
236
237 self.wait_until_visible(f'#{input_id}')
238
239 if kwargs.get('is_select'):
240 select = Select(self.find(f'#{input_id}'))
241 select.select_by_visible_text(value)
242 else:
243 self.find(f"#{input_id}").clear()
244 self.enter_text(f'#{input_id}', f'{value}')
245 self.click(f'#{save_btn}')
246 value_displayed = str(self.wait_until_visible(f'#{field}').text).lower()
247 msg = f'{var_name} variable not changed'
248 self.assertTrue(str(value).lower() in value_displayed, msg)
249
250 def test_change_distro_var(self):
251 """ Test changing distro variable """
252 self._change_bbv_value(
253 var_name='DISTRO',
254 field='distro',
255 btn_id='change-distro-icon',
256 input_id='new-distro',
257 value='poky-changed',
258 save_btn="apply-change-distro",
259 )
260
261 def test_set_image_install_append_var(self):
262 """ Test setting IMAGE_INSTALL:append variable """
263 self._change_bbv_value(
264 var_name='IMAGE_INSTALL:append',
265 field='image_install',
266 btn_id='change-image_install-icon',
267 input_id='new-image_install',
268 value='bash, apt, busybox',
269 save_btn="apply-change-image_install",
270 )
271
272 def test_set_package_classes_var(self):
273 """ Test setting PACKAGE_CLASSES variable """
274 self._change_bbv_value(
275 var_name='PACKAGE_CLASSES',
276 field='package_classes',
277 btn_id='change-package_classes-icon',
278 input_id='package_classes-select',
279 value='package_deb',
280 save_btn="apply-change-package_classes",
281 is_select=True,
282 )
283
284 def test_create_new_bbv(self):
285 """ Test creating new bitbake variable """
286 self._change_bbv_value(
287 var_name='New_Custom_Variable',
288 field='configvar-list',
289 btn_id='variable',
290 input_id='value',
291 value='new variable value',
292 save_btn="add-configvar-button",
293 new_variable=True
294 )
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page.py b/bitbake/lib/toaster/tests/functional/test_project_page.py
new file mode 100644
index 0000000000..429d86feba
--- /dev/null
+++ b/bitbake/lib/toaster/tests/functional/test_project_page.py
@@ -0,0 +1,775 @@
1#! /usr/bin/env python3 #
2# BitBake Toaster UI tests implementation
3#
4# Copyright (C) 2023 Savoir-faire Linux
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import os
10import string
11import time
12from unittest import skip
13import pytest
14from django.urls import reverse
15from django.utils import timezone
16from selenium.webdriver.common.keys import Keys
17from selenium.webdriver.support.select import Select
18from selenium.common.exceptions import TimeoutException
19from tests.functional.functional_helpers import SeleniumFunctionalTestCase
20from orm.models import Build, Project, Target
21from selenium.webdriver.common.by import By
22
23from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled
24
25class TestProjectPageBase(SeleniumFunctionalTestCase):
26 project_id = None
27 PROJECT_NAME = 'TestProjectPage'
28
29 def _navigate_to_project_page(self):
30 # Navigate to project page
31 if TestProjectPageBase.project_id is None:
32 TestProjectPageBase.project_id = self.create_new_project(self.PROJECT_NAME, '3', None, True)
33
34 url = reverse('project', args=(TestProjectPageBase.project_id,))
35 self.get(url)
36 self.wait_until_visible('#config-nav')
37
38 def _get_create_builds(self, **kwargs):
39 """ Create a build and return the build object """
40 # parameters for builds to associate with the projects
41 now = timezone.now()
42 self.project1_build_success = {
43 'project': Project.objects.get(id=TestProjectPageBase.project_id),
44 'started_on': now,
45 'completed_on': now,
46 'outcome': Build.SUCCEEDED
47 }
48
49 self.project1_build_failure = {
50 'project': Project.objects.get(id=TestProjectPageBase.project_id),
51 'started_on': now,
52 'completed_on': now,
53 'outcome': Build.FAILED
54 }
55 build1 = Build.objects.create(**self.project1_build_success)
56 build2 = Build.objects.create(**self.project1_build_failure)
57
58 # add some targets to these builds so they have recipe links
59 # (and so we can find the row in the ToasterTable corresponding to
60 # a particular build)
61 Target.objects.create(build=build1, target='foo')
62 Target.objects.create(build=build2, target='bar')
63
64 if kwargs:
65 # Create kwargs.get('success') builds with success status with target
66 # and kwargs.get('failure') builds with failure status with target
67 for i in range(kwargs.get('success', 0)):
68 now = timezone.now()
69 self.project1_build_success['started_on'] = now
70 self.project1_build_success[
71 'completed_on'] = now - timezone.timedelta(days=i)
72 build = Build.objects.create(**self.project1_build_success)
73 Target.objects.create(build=build,
74 target=f'{i}_success_recipe',
75 task=f'{i}_success_task')
76
77 for i in range(kwargs.get('failure', 0)):
78 now = timezone.now()
79 self.project1_build_failure['started_on'] = now
80 self.project1_build_failure[
81 'completed_on'] = now - timezone.timedelta(days=i)
82 build = Build.objects.create(**self.project1_build_failure)
83 Target.objects.create(build=build,
84 target=f'{i}_fail_recipe',
85 task=f'{i}_fail_task')
86 return build1, build2
87
88 def _mixin_test_table_edit_column(
89 self,
90 table_id,
91 edit_btn_id,
92 list_check_box_id: list
93 ):
94 # Check edit column
95 finder = lambda driver: self.find(f'#{edit_btn_id}')
96 edit_column = self.wait_until_element_clickable(finder)
97 self.assertTrue(edit_column.is_displayed())
98 edit_column.click()
99 # Check dropdown is visible
100 self.wait_until_visible('ul.dropdown-menu.editcol')
101 for check_box_id in list_check_box_id:
102 # Check that we can hide/show table column
103 check_box = self.find(f'#{check_box_id}')
104 th_class = str(check_box_id).replace('checkbox-', '')
105 if check_box.is_selected():
106 # check if column is visible in table
107 self.assertTrue(
108 self.find(
109 f'#{table_id} thead th.{th_class}'
110 ).is_displayed(),
111 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
112 )
113 check_box.click()
114 # check if column is hidden in table
115 self.assertFalse(
116 self.find(
117 f'#{table_id} thead th.{th_class}'
118 ).is_displayed(),
119 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
120 )
121 else:
122 # check if column is hidden in table
123 self.assertFalse(
124 self.find(
125 f'#{table_id} thead th.{th_class}'
126 ).is_displayed(),
127 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
128 )
129 check_box.click()
130 # check if column is visible in table
131 self.assertTrue(
132 self.find(
133 f'#{table_id} thead th.{th_class}'
134 ).is_displayed(),
135 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
136 )
137
138 def _get_config_nav_item(self, index):
139 config_nav = self.find('#config-nav')
140 return config_nav.find_elements(By.TAG_NAME, 'li')[index]
141
142 def _navigate_to_config_nav(self, nav_id, nav_index):
143 # navigate to the project page
144 self._navigate_to_project_page()
145 # click on "Software recipe" tab
146 soft_recipe = self._get_config_nav_item(nav_index)
147 soft_recipe.click()
148 self.wait_until_visible(f'#{nav_id}')
149
150 def _mixin_test_table_show_rows(self, table_selector, **kwargs):
151 """ Test the show rows feature in the builds table on the all builds page """
152 def test_show_rows(row_to_show, show_row_link):
153 # Check that we can show rows == row_to_show
154 show_row_link.select_by_value(str(row_to_show))
155 self.wait_until_visible(f'#{table_selector} tbody tr')
156 # check at least some rows are visible
157 self.assertTrue(
158 len(self.find_all(f'#{table_selector} tbody tr')) > 0
159 )
160 self.wait_until_present(f'#{table_selector} tbody tr')
161 show_rows = self.driver.find_elements(
162 By.XPATH,
163 f'//select[@class="form-control pagesize-{table_selector}"]'
164 )
165 rows_to_show = [10, 25, 50, 100, 150]
166 to_skip = kwargs.get('to_skip', [])
167 # Check show rows
168 for show_row_link in show_rows:
169 show_row_link = Select(show_row_link)
170 for row_to_show in rows_to_show:
171 if row_to_show not in to_skip:
172 test_show_rows(row_to_show, show_row_link)
173
174 def _mixin_test_table_search_input(self, **kwargs):
175 input_selector, input_text, searchBtn_selector, table_selector, *_ = kwargs.values()
176 # Test search input
177 self.wait_until_visible(f'#{input_selector}')
178 recipe_input = self.find(f'#{input_selector}')
179 recipe_input.send_keys(input_text)
180 self.find(f'#{searchBtn_selector}').click()
181 self.wait_until_visible(f'#{table_selector} tbody tr')
182 rows = self.find_all(f'#{table_selector} tbody tr')
183 self.assertTrue(len(rows) > 0)
184
185class TestProjectPage(TestProjectPageBase):
186
187 def test_page_header_on_project_page(self):
188 """ Check page header in project page:
189 - AT LEFT -> Logo of Yocto project, displayed, clickable
190 - "Toaster"+" Information icon", displayed, clickable
191 - "Server Icon" + "All builds", displayed, clickable
192 - "Directory Icon" + "All projects", displayed, clickable
193 - "Book Icon" + "Documentation", displayed, clickable
194 - AT RIGHT -> button "New project", displayed, clickable
195 """
196 # navigate to the project page
197 self._navigate_to_project_page()
198
199 # check page header
200 # AT LEFT -> Logo of Yocto project
201 logo = self.driver.find_element(
202 By.XPATH,
203 "//div[@class='toaster-navbar-brand']",
204 )
205 logo_img = logo.find_element(By.TAG_NAME, 'img')
206 self.assertTrue(logo_img.is_displayed(),
207 'Logo of Yocto project not found')
208 self.assertIn(
209 '/static/img/logo.png', str(logo_img.get_attribute('src')),
210 'Logo of Yocto project not found'
211 )
212 # "Toaster"+" Information icon", clickable
213 toaster = self.driver.find_element(
214 By.XPATH,
215 "//div[@class='toaster-navbar-brand']//a[@class='brand']",
216 )
217 self.assertTrue(toaster.is_displayed(), 'Toaster not found')
218 self.assertEqual(toaster.text, 'Toaster')
219 info_sign = self.find('.glyphicon-info-sign')
220 self.assertTrue(info_sign.is_displayed())
221
222 # "Server Icon" + "All builds"
223 all_builds = self.find('#navbar-all-builds')
224 all_builds_link = all_builds.find_element(By.TAG_NAME, 'a')
225 self.assertIn("All builds", all_builds_link.text)
226 self.assertIn(
227 '/toastergui/builds/', str(all_builds_link.get_attribute('href'))
228 )
229 server_icon = all_builds.find_element(By.TAG_NAME, 'i')
230 self.assertEqual(
231 server_icon.get_attribute('class'), 'glyphicon glyphicon-tasks'
232 )
233 self.assertTrue(server_icon.is_displayed())
234
235 # "Directory Icon" + "All projects"
236 all_projects = self.find('#navbar-all-projects')
237 all_projects_link = all_projects.find_element(By.TAG_NAME, 'a')
238 self.assertIn("All projects", all_projects_link.text)
239 self.assertIn(
240 '/toastergui/projects/', str(all_projects_link.get_attribute(
241 'href'))
242 )
243 dir_icon = all_projects.find_element(By.TAG_NAME, 'i')
244 self.assertEqual(
245 dir_icon.get_attribute('class'), 'icon-folder-open'
246 )
247 self.assertTrue(dir_icon.is_displayed())
248
249 # "Book Icon" + "Documentation"
250 toaster_docs_link = self.find('#navbar-docs')
251 toaster_docs_link_link = toaster_docs_link.find_element(By.TAG_NAME,
252 'a')
253 self.assertIn("Documentation", toaster_docs_link_link.text)
254 self.assertEqual(
255 toaster_docs_link_link.get_attribute('href'), 'http://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual'
256 )
257 book_icon = toaster_docs_link.find_element(By.TAG_NAME, 'i')
258 self.assertEqual(
259 book_icon.get_attribute('class'), 'glyphicon glyphicon-book'
260 )
261 self.assertTrue(book_icon.is_displayed())
262
263 # AT RIGHT -> button "New project"
264 new_project_button = self.find('#new-project-button')
265 self.assertTrue(new_project_button.is_displayed())
266 self.assertEqual(new_project_button.text, 'New project')
267 new_project_button.click()
268 self.assertIn(
269 '/toastergui/newproject/', str(self.driver.current_url)
270 )
271
272 def test_edit_project_name(self):
273 """ Test edit project name:
274 - Click on "Edit" icon button
275 - Change project name
276 - Click on "Save" button
277 - Check project name is changed
278 """
279 # navigate to the project page
280 self._navigate_to_project_page()
281
282 # click on "Edit" icon button
283 self.wait_until_visible('#project-name-container')
284 finder = lambda driver: self.find('#project-change-form-toggle')
285 edit_button = self.wait_until_element_clickable(finder)
286 edit_button.click()
287 project_name_input = self.find('#project-name-change-input')
288 self.assertTrue(project_name_input.is_displayed())
289 project_name_input.clear()
290 project_name_input.send_keys('New Name')
291 self.find('#project-name-change-btn').click()
292
293 # check project name is changed
294 self.wait_until_visible('#project-name-container')
295 self.assertIn(
296 'New Name', str(self.find('#project-name-container').text)
297 )
298
299 def test_project_page_tabs(self):
300 """ Test project tabs:
301 - "configuration" tab
302 - "Builds" tab
303 - "Import layers" tab
304 - "New custom image" tab
305 Check search box used to build recipes
306 """
307 # navigate to the project page
308 self._navigate_to_project_page()
309
310 # check "configuration" tab
311 self.wait_until_visible('#topbar-configuration-tab')
312 config_tab = self.find('#topbar-configuration-tab')
313 self.assertEqual(config_tab.get_attribute('class'), 'active')
314 self.assertIn('Configuration', str(config_tab.text))
315 self.assertIn(
316 f"/toastergui/project/{TestProjectPageBase.project_id}", str(self.driver.current_url)
317 )
318
319 def get_tabs():
320 # tabs links list
321 return self.driver.find_elements(
322 By.XPATH,
323 '//div[@id="project-topbar"]//li'
324 )
325
326 def check_tab_link(tab_index, tab_name, url):
327 tab = get_tabs()[tab_index]
328 tab_link = tab.find_element(By.TAG_NAME, 'a')
329 self.assertIn(url, tab_link.get_attribute('href'))
330 self.assertIn(tab_name, tab_link.text)
331 self.assertEqual(tab.get_attribute('class'), 'active')
332
333 # check "Builds" tab
334 builds_tab = get_tabs()[1]
335 builds_tab.find_element(By.TAG_NAME, 'a').click()
336 check_tab_link(
337 1,
338 'Builds',
339 f"/toastergui/project/{TestProjectPageBase.project_id}/builds"
340 )
341
342 # check "Import layers" tab
343 import_layers_tab = get_tabs()[2]
344 import_layers_tab.find_element(By.TAG_NAME, 'a').click()
345 check_tab_link(
346 2,
347 'Import layer',
348 f"/toastergui/project/{TestProjectPageBase.project_id}/importlayer"
349 )
350
351 # check "New custom image" tab
352 new_custom_image_tab = get_tabs()[3]
353 new_custom_image_tab.find_element(By.TAG_NAME, 'a').click()
354 check_tab_link(
355 3,
356 'New custom image',
357 f"/toastergui/project/{TestProjectPageBase.project_id}/newcustomimage"
358 )
359
360 # check search box can be use to build recipes
361 search_box = self.find('#build-input')
362 search_box.send_keys('core-image-minimal')
363 self.find('#build-button').click()
364 self.wait_until_visible('#latest-builds')
365 buildtext = "Loading"
366 while "Loading" in buildtext:
367 time.sleep(1)
368 lastest_builds = self.driver.find_elements(
369 By.XPATH,
370 '//div[@id="latest-builds"]',
371 )
372 last_build = lastest_builds[0]
373 buildtext = last_build.text
374 self.assertIn(
375 'core-image-minimal', str(last_build.text)
376 )
377
378 def test_softwareRecipe_page(self):
379 """ Test software recipe page
380 - Check title "Compatible software recipes" is displayed
381 - Check search input
382 - Check "build recipe" button works
383 - Check software recipe table feature(show/hide column, pagination)
384 """
385 self._navigate_to_config_nav('softwarerecipestable', 4)
386 # check title "Compatible software recipes" is displayed
387 self.assertIn("Compatible software recipes", self.get_page_source())
388 # Test search input
389 self._mixin_test_table_search_input(
390 input_selector='search-input-softwarerecipestable',
391 input_text='busybox',
392 searchBtn_selector='search-submit-softwarerecipestable',
393 table_selector='softwarerecipestable'
394 )
395 # check "build recipe" button works
396 finder = lambda driver: self.find_all('#softwarerecipestable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]/a')
397 build_btn = self.wait_until_element_clickable(finder)
398 build_btn.click()
399 build_state = wait_until_build(self, 'queued cloning starting parsing failed')
400 lastest_builds = self.driver.find_elements(
401 By.XPATH,
402 '//div[@id="latest-builds"]/div'
403 )
404 self.assertTrue(len(lastest_builds) > 0)
405 # Find the latest builds, the last build and then the cancel button
406
407 finder = lambda driver: driver.find_elements(By.XPATH, '//div[@id="latest-builds"]/div')[0].find_element(By.XPATH, '//span[@class="cancel-build-btn pull-right alert-link"]')
408 cancel_button = self.wait_until_element_clickable(finder)
409 cancel_button.click()
410 if 'starting' not in build_state: # change build state when cancelled in starting state
411 wait_until_build_cancelled(self)
412
413 # check software recipe table feature(show/hide column, pagination)
414 self._navigate_to_config_nav('softwarerecipestable', 4)
415 column_list = [
416 'get_description_or_summary',
417 'layer_version__get_vcs_reference',
418 'layer_version__layer__name',
419 'license',
420 'recipe-file',
421 'section',
422 'version',
423 ]
424 self._mixin_test_table_edit_column(
425 'softwarerecipestable',
426 'edit-columns-button',
427 [f'checkbox-{column}' for column in column_list]
428 )
429 self._navigate_to_config_nav('softwarerecipestable', 4)
430 # check show rows(pagination)
431 self._mixin_test_table_show_rows(
432 table_selector='softwarerecipestable',
433 to_skip=[150],
434 )
435
436 def test_machines_page(self):
437 """ Test Machine page
438 - Check if title "Compatible machines" is displayed
439 - Check search input
440 - Check "Select machine" button works
441 - Check "Add layer" button works
442 - Check Machine table feature(show/hide column, pagination)
443 """
444 self._navigate_to_config_nav('machinestable', 5)
445 # check title "Compatible software recipes" is displayed
446 self.assertIn("Compatible machines", self.get_page_source())
447 # Test search input
448 self._mixin_test_table_search_input(
449 input_selector='search-input-machinestable',
450 input_text='qemux86-64',
451 searchBtn_selector='search-submit-machinestable',
452 table_selector='machinestable'
453 )
454 # check "Select machine" button works
455 finder = lambda driver: self.find_all('#machinestable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]')
456 select_btn = self.wait_until_element_clickable(finder)
457 select_btn.click()
458 self.wait_until_visible('#project-machine-name')
459 project_machine_name = self.find('#project-machine-name')
460 self.assertIn(
461 'qemux86-64', project_machine_name.text
462 )
463 # check "Add layer" button works
464 self._navigate_to_config_nav('machinestable', 5)
465 # Search for a machine whit layer not in project
466 self._mixin_test_table_search_input(
467 input_selector='search-input-machinestable',
468 input_text='qemux86-64-tpm2',
469 searchBtn_selector='search-submit-machinestable',
470 table_selector='machinestable'
471 )
472
473 self.wait_until_visible('#machinestable tbody tr')
474 # Locate a machine to add button
475 finder = lambda driver: self.find_all('#machinestable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]')
476 add_btn = self.wait_until_element_clickable(finder)
477 add_btn.click()
478 self.wait_until_visible('#change-notification')
479 change_notification = self.find('#change-notification')
480 self.assertIn(
481 f'You have added 1 layer to your project', str(change_notification.text)
482 )
483
484 finder = lambda driver: self.find('#hide-alert')
485 hide_button = self.wait_until_element_clickable(finder)
486 hide_button.click()
487 self.wait_until_not_visible('#change-notification')
488
489 # check Machine table feature(show/hide column, pagination)
490 self._navigate_to_config_nav('machinestable', 5)
491 column_list = [
492 'description',
493 'layer_version__get_vcs_reference',
494 'layer_version__layer__name',
495 'machinefile',
496 ]
497 self._mixin_test_table_edit_column(
498 'machinestable',
499 'edit-columns-button',
500 [f'checkbox-{column}' for column in column_list]
501 )
502 self._navigate_to_config_nav('machinestable', 5)
503 # check show rows(pagination)
504 self._mixin_test_table_show_rows(
505 table_selector='machinestable',
506 to_skip=[150],
507 )
508
509 def test_layers_page(self):
510 """ Test layers page
511 - Check if title "Compatible layerss" is displayed
512 - Check search input
513 - Check "Add layer" button works
514 - Check "Remove layer" button works
515 - Check layers table feature(show/hide column, pagination)
516 """
517 self._navigate_to_config_nav('layerstable', 6)
518 # check title "Compatible layers" is displayed
519 self.assertIn("Compatible layers", self.get_page_source())
520 # Test search input
521 input_text='meta-tanowrt'
522 self._mixin_test_table_search_input(
523 input_selector='search-input-layerstable',
524 input_text=input_text,
525 searchBtn_selector='search-submit-layerstable',
526 table_selector='layerstable'
527 )
528 # check "Add layer" button works
529 self.wait_until_visible('#layerstable tbody tr')
530 finder = lambda driver: self.find_all('#layerstable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]/a[@data-directive="add"]')
531 add_btn = self.wait_until_element_clickable(finder)
532 add_btn.click()
533 # check modal is displayed
534 self.wait_until_visible('#dependencies-modal')
535 list_dependencies = self.find_all('#dependencies-list li')
536 # click on add-layers button
537 finder = lambda driver: self.driver.find_element(By.XPATH, '//form[@id="dependencies-modal-form"]//button[@class="btn btn-primary"]')
538 add_layers_btn = self.wait_until_element_clickable(finder)
539 add_layers_btn.click()
540 self.wait_until_visible('#change-notification')
541 change_notification = self.find('#change-notification')
542 self.assertIn(
543 f'You have added {len(list_dependencies)+1} layers to your project: {input_text} and its dependencies', str(change_notification.text)
544 )
545
546 finder = lambda driver: self.find('#hide-alert')
547 hide_button = self.wait_until_element_clickable(finder)
548 hide_button.click()
549 self.wait_until_not_visible('#change-notification')
550
551 # check "Remove layer" button works
552 self.wait_until_visible('#layerstable tbody tr')
553 finder = lambda driver: self.find_all('#layerstable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]/a[@data-directive="remove"]')
554 remove_btn = self.wait_until_element_clickable(finder)
555 remove_btn.click()
556 self.wait_until_visible('#change-notification')
557 change_notification = self.find('#change-notification')
558 self.assertIn(
559 f'You have removed 1 layer from your project: {input_text}', str(change_notification.text)
560 )
561
562 finder = lambda driver: self.find('#hide-alert')
563 hide_button = self.wait_until_element_clickable(finder)
564 hide_button.click()
565 self.wait_until_not_visible('#change-notification')
566
567 # check layers table feature(show/hide column, pagination)
568 self._navigate_to_config_nav('layerstable', 6)
569 column_list = [
570 'dependencies',
571 'revision',
572 'layer__vcs_url',
573 'git_subdir',
574 'layer__summary',
575 ]
576 self._mixin_test_table_edit_column(
577 'layerstable',
578 'edit-columns-button',
579 [f'checkbox-{column}' for column in column_list]
580 )
581 self._navigate_to_config_nav('layerstable', 6)
582 # check show rows(pagination)
583 self._mixin_test_table_show_rows(
584 table_selector='layerstable',
585 to_skip=[150],
586 )
587
588 def test_distro_page(self):
589 """ Test distros page
590 - Check if title "Compatible distros" is displayed
591 - Check search input
592 - Check "Add layer" button works
593 - Check distro table feature(show/hide column, pagination)
594 """
595 self._navigate_to_config_nav('distrostable', 7)
596 # check title "Compatible distros" is displayed
597 self.assertIn("Compatible Distros", self.get_page_source())
598 # Test search input
599 input_text='poky-altcfg'
600 self._mixin_test_table_search_input(
601 input_selector='search-input-distrostable',
602 input_text=input_text,
603 searchBtn_selector='search-submit-distrostable',
604 table_selector='distrostable'
605 )
606 # check "Add distro" button works
607 self.wait_until_visible(".add-del-layers")
608 finder = lambda driver: self.find_all('#distrostable tbody tr')[0].find_element(By.XPATH, '//td[@class="add-del-layers"]')
609 add_btn = self.wait_until_element_clickable(finder)
610 add_btn.click()
611 self.wait_until_visible('#change-notification')
612 change_notification = self.find('#change-notification')
613 self.assertIn(
614 f'You have changed the distro to: {input_text}', str(change_notification.text)
615 )
616 # check distro table feature(show/hide column, pagination)
617 self._navigate_to_config_nav('distrostable', 7)
618 column_list = [
619 'description',
620 'templatefile',
621 'layer_version__get_vcs_reference',
622 'layer_version__layer__name',
623 ]
624 self._mixin_test_table_edit_column(
625 'distrostable',
626 'edit-columns-button',
627 [f'checkbox-{column}' for column in column_list]
628 )
629 self._navigate_to_config_nav('distrostable', 7)
630 # check show rows(pagination)
631 self._mixin_test_table_show_rows(
632 table_selector='distrostable',
633 to_skip=[150],
634 )
635
636 def test_single_layer_page(self):
637 """ Test layer details page using meta-poky as an example (assumes is added to start with)
638 - Check if title is displayed
639 - Check add/remove layer button works
640 - Check tabs(layers, recipes, machines) are displayed
641 - Check left section is displayed
642 - Check layer name
643 - Check layer summary
644 - Check layer description
645 """
646 self._navigate_to_config_nav('layerstable', 6)
647 layer_link = self.driver.find_element(By.XPATH, '//tr/td[@class="layer__name"]/a[contains(text(),"meta-poky")]')
648 layer_link.click()
649 self.wait_until_visible('.page-header')
650 # check title is displayed
651 self.assertTrue(self.find('.page-header h1').is_displayed())
652
653 # check remove layer button works
654 finder = lambda driver: self.find('#add-remove-layer-btn')
655 remove_layer_btn = self.wait_until_element_clickable(finder)
656 remove_layer_btn.click()
657 self.wait_until_visible('#change-notification')
658 change_notification = self.find('#change-notification')
659 self.assertIn(
660 f'You have removed 1 layer from your project', str(change_notification.text)
661 )
662 finder = lambda driver: self.find('#hide-alert')
663 hide_button = self.wait_until_element_clickable(finder)
664 hide_button.click()
665 # check add layer button works
666 self.wait_until_not_visible('#change-notification')
667 finder = lambda driver: self.find('#add-remove-layer-btn')
668 add_layer_btn = self.wait_until_element_clickable(finder)
669 add_layer_btn.click()
670 self.wait_until_visible('#change-notification')
671 change_notification = self.find('#change-notification')
672 self.assertIn(
673 f'You have added 1 layer to your project', str(change_notification.text)
674 )
675 finder = lambda driver: self.find('#hide-alert')
676 hide_button = self.wait_until_element_clickable(finder)
677 hide_button.click()
678 self.wait_until_not_visible('#change-notification')
679 # check tabs(layers, recipes, machines) are displayed
680 tabs = self.find_all('.nav-tabs li')
681 self.assertEqual(len(tabs), 3)
682 # Check first tab
683 tabs[0].click()
684 self.assertIn(
685 'active', str(self.find('#information').get_attribute('class'))
686 )
687 # Check second tab (recipes)
688 self.wait_until_visible('.nav-tabs')
689 # Ensure page is scrolled to the top
690 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
691 tabs[1].click()
692 self.assertIn(
693 'active', str(self.find('#recipes').get_attribute('class'))
694 )
695 # Check third tab (machines)
696 self.wait_until_visible('.nav-tabs')
697 # Ensure page is scrolled to the top
698 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
699 tabs[2].click()
700 self.assertIn(
701 'active', str(self.find('#machines').get_attribute('class'))
702 )
703 # Check left section is displayed
704 section = self.find('.well')
705 # Check layer name
706 self.assertTrue(
707 section.find_element(By.XPATH, '//h2[1]').is_displayed()
708 )
709 # Check layer summary
710 self.assertIn("Summary", section.text)
711 # Check layer description
712 self.assertIn("Description", section.text)
713
714@pytest.mark.django_db
715@pytest.mark.order("last")
716class TestProjectPageRecipes(TestProjectPageBase):
717
718 def test_single_recipe_page(self):
719 """ Test recipe page
720 - Check if title is displayed
721 - Check add recipe layer displayed
722 - Check left section is displayed
723 - Check recipe: name, summary, description, Version, Section,
724 License, Approx. packages included, Approx. size, Recipe file
725 """
726 # Use a recipe which is likely to exist in the layer index but not enabled
727 # in poky out the box - xen-image-minimal from meta-virtualization
728 self._navigate_to_project_page()
729 prj = Project.objects.get(pk=TestProjectPageBase.project_id)
730 recipe_id = prj.get_all_compatible_recipes().get(name="xen-image-minimal").pk
731 url = reverse("recipedetails", args=(TestProjectPageBase.project_id, recipe_id))
732 self.get(url)
733 self.wait_until_visible('.page-header')
734 # check title is displayed
735 self.assertTrue(self.find('.page-header h1').is_displayed())
736 # check add recipe layer displayed
737 add_recipe_layer_btn = self.find('#add-layer-btn')
738 self.assertTrue(add_recipe_layer_btn.is_displayed())
739 # check left section is displayed
740 section = self.find('.well')
741 # Check recipe name
742 self.assertTrue(
743 section.find_element(By.XPATH, '//h2[1]').is_displayed()
744 )
745 # Check recipe sections details info are displayed
746 self.assertIn("Summary", section.text)
747 self.assertIn("Description", section.text)
748 self.assertIn("Version", section.text)
749 self.assertIn("Section", section.text)
750 self.assertIn("License", section.text)
751 self.assertIn("Approx. packages included", section.text)
752 self.assertIn("Approx. package size", section.text)
753 self.assertIn("Recipe file", section.text)
754
755 def test_image_recipe_editColumn(self):
756 """ Test the edit column feature in image recipe table on project page """
757 self._get_create_builds(success=10, failure=10)
758
759 url = reverse('projectimagerecipes', args=(TestProjectPageBase.project_id,))
760 self.get(url)
761 self.wait_until_present('#imagerecipestable tbody tr')
762
763 column_list = [
764 'get_description_or_summary', 'layer_version__get_vcs_reference',
765 'layer_version__layer__name', 'license', 'recipe-file', 'section',
766 'version'
767 ]
768
769 # Check that we can hide the edit column
770 self._mixin_test_table_edit_column(
771 'imagerecipestable',
772 'edit-columns-button',
773 [f'checkbox-{column}' for column in column_list]
774 )
775
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py
new file mode 100644
index 0000000000..80c53e1544
--- /dev/null
+++ b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py
@@ -0,0 +1,507 @@
1#! /usr/bin/env python3 #
2# BitBake Toaster UI tests implementation
3#
4# Copyright (C) 2023 Savoir-faire Linux
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import string
10import time
11import pytest
12from django.urls import reverse
13from selenium.webdriver import Keys
14from selenium.webdriver.support.select import Select
15from selenium.common.exceptions import ElementClickInterceptedException, NoSuchElementException, TimeoutException
16from tests.functional.functional_helpers import SeleniumFunctionalTestCase
17from selenium.webdriver.common.by import By
18
19from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled
20
21class TestProjectConfigTabBase(SeleniumFunctionalTestCase):
22 PROJECT_NAME = 'TestProjectConfigTab'
23 project_id = None
24
25 def _navigate_to_project_page(self):
26 # Navigate to project page
27 if TestProjectConfigTabBase.project_id is None:
28 TestProjectConfigTabBase.project_id = self.create_new_project(self.PROJECT_NAME, '3', None, True)
29 url = reverse('project', args=(TestProjectConfigTabBase.project_id,))
30 self.get(url)
31 self.wait_until_visible('#config-nav')
32
33 def _create_builds(self):
34 # check search box can be use to build recipes
35 search_box = self.find('#build-input')
36 search_box.send_keys('foo')
37 self.find('#build-button').click()
38 self.wait_until_present('#latest-builds')
39 # loop until reach the parsing state
40 wait_until_build(self, 'queued cloning starting parsing failed')
41 lastest_builds = self.driver.find_elements(
42 By.XPATH,
43 '//div[@id="latest-builds"]/div',
44 )
45 last_build = lastest_builds[0]
46 self.assertIn(
47 'foo', str(last_build.text)
48 )
49 last_build = lastest_builds[0]
50 try:
51 cancel_button = last_build.find_element(
52 By.XPATH,
53 '//span[@class="cancel-build-btn pull-right alert-link"]',
54 )
55 cancel_button.click()
56 except NoSuchElementException:
57 # Skip if the build is already cancelled
58 pass
59 wait_until_build_cancelled(self)
60
61 def _get_tabs(self):
62 # tabs links list
63 return self.driver.find_elements(
64 By.XPATH,
65 '//div[@id="project-topbar"]//li'
66 )
67
68 def _get_config_nav_item(self, index):
69 config_nav = self.find('#config-nav')
70 return config_nav.find_elements(By.TAG_NAME, 'li')[index]
71
72class TestProjectConfigTab(TestProjectConfigTabBase):
73
74 def test_project_config_nav(self):
75 """ Test project config tab navigation:
76 - Check if the menu is displayed and contains the right elements:
77 - Configuration
78 - COMPATIBLE METADATA
79 - Custom images
80 - Image recipes
81 - Software recipes
82 - Machines
83 - Layers
84 - Distro
85 - EXTRA CONFIGURATION
86 - Bitbake variables
87 - Actions
88 - Delete project
89 """
90 self._navigate_to_project_page()
91
92 def _get_config_nav_item(index):
93 config_nav = self.find('#config-nav')
94 return config_nav.find_elements(By.TAG_NAME, 'li')[index]
95
96 def check_config_nav_item(index, item_name, url):
97 item = _get_config_nav_item(index)
98 self.assertIn(item_name, item.text)
99 self.assertEqual(item.get_attribute('class'), 'active')
100 self.assertIn(url, self.driver.current_url)
101
102 # check if the menu contains the right elements
103 # COMPATIBLE METADATA
104 compatible_metadata = _get_config_nav_item(1)
105 self.assertIn(
106 "compatible metadata", compatible_metadata.text.lower()
107 )
108 # EXTRA CONFIGURATION
109 extra_configuration = _get_config_nav_item(8)
110 self.assertIn(
111 "extra configuration", extra_configuration.text.lower()
112 )
113 # Actions
114 actions = _get_config_nav_item(10)
115 self.assertIn("actions", str(actions.text).lower())
116
117 conf_nav_list = [
118 # config
119 [0, 'Configuration',
120 f"/toastergui/project/{TestProjectConfigTabBase.project_id}"],
121 # custom images
122 [2, 'Custom images',
123 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/customimages"],
124 # image recipes
125 [3, 'Image recipes',
126 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/images"],
127 # software recipes
128 [4, 'Software recipes',
129 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/softwarerecipes"],
130 # machines
131 [5, 'Machines',
132 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/machines"],
133 # layers
134 [6, 'Layers',
135 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/layers"],
136 # distro
137 [7, 'Distros',
138 f"/toastergui/project/{TestProjectConfigTabBase.project_id}/distros"],
139 # [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTabBase.project_id}/configuration"], # bitbake variables
140 ]
141 for index, item_name, url in conf_nav_list:
142 item = _get_config_nav_item(index)
143 if item.get_attribute('class') != 'active':
144 item.click()
145 check_config_nav_item(index, item_name, url)
146
147 def test_image_recipe_editColumn(self):
148 """ Test the edit column feature in image recipe table on project page """
149 def test_edit_column(check_box_id):
150 # Check that we can hide/show table column
151 check_box = self.find(f'#{check_box_id}')
152 th_class = str(check_box_id).replace('checkbox-', '')
153 if check_box.is_selected():
154 # check if column is visible in table
155 self.assertTrue(
156 self.find(
157 f'#imagerecipestable thead th.{th_class}'
158 ).is_displayed(),
159 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
160 )
161 check_box.click()
162 # check if column is hidden in table
163 self.assertFalse(
164 self.find(
165 f'#imagerecipestable thead th.{th_class}'
166 ).is_displayed(),
167 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
168 )
169 else:
170 # check if column is hidden in table
171 self.assertFalse(
172 self.find(
173 f'#imagerecipestable thead th.{th_class}'
174 ).is_displayed(),
175 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
176 )
177 check_box.click()
178 # check if column is visible in table
179 self.assertTrue(
180 self.find(
181 f'#imagerecipestable thead th.{th_class}'
182 ).is_displayed(),
183 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
184 )
185
186 self._navigate_to_project_page()
187 # navigate to project image recipe page
188 recipe_image_page_link = self._get_config_nav_item(3)
189 recipe_image_page_link.click()
190 self.wait_until_present('#imagerecipestable tbody tr')
191
192 # Check edit column
193 edit_column = self.find('#edit-columns-button')
194 self.assertTrue(edit_column.is_displayed())
195 edit_column.click()
196 # Check dropdown is visible
197 self.wait_until_visible('ul.dropdown-menu.editcol')
198
199 # Check that we can hide the edit column
200 test_edit_column('checkbox-get_description_or_summary')
201 test_edit_column('checkbox-layer_version__get_vcs_reference')
202 test_edit_column('checkbox-layer_version__layer__name')
203 test_edit_column('checkbox-license')
204 test_edit_column('checkbox-recipe-file')
205 test_edit_column('checkbox-section')
206 test_edit_column('checkbox-version')
207
208 def test_image_recipe_show_rows(self):
209 """ Test the show rows feature in image recipe table on project page """
210 def test_show_rows(row_to_show, show_row_link):
211 # Check that we can show rows == row_to_show
212 show_row_link.select_by_value(str(row_to_show))
213 self.wait_until_visible('#imagerecipestable tbody tr')
214 # check at least some rows are visible
215 self.assertTrue(
216 len(self.find_all('#imagerecipestable tbody tr')) > 0
217 )
218
219 self._navigate_to_project_page()
220 # navigate to project image recipe page
221 recipe_image_page_link = self._get_config_nav_item(3)
222 recipe_image_page_link.click()
223 self.wait_until_present('#imagerecipestable tbody tr')
224
225 show_rows = self.driver.find_elements(
226 By.XPATH,
227 '//select[@class="form-control pagesize-imagerecipestable"]'
228 )
229 # Check show rows
230 for show_row_link in show_rows:
231 show_row_link = Select(show_row_link)
232 test_show_rows(10, show_row_link)
233 test_show_rows(25, show_row_link)
234 test_show_rows(50, show_row_link)
235 test_show_rows(100, show_row_link)
236 test_show_rows(150, show_row_link)
237
238 def test_project_config_tab_right_section(self):
239 """ Test project config tab right section contains five blocks:
240 - Machine:
241 - check 'Machine' is displayed
242 - check can change Machine
243 - Distro:
244 - check 'Distro' is displayed
245 - check can change Distro
246 - Most built recipes:
247 - check 'Most built recipes' is displayed
248 - check can select a recipe and build it
249 - Project release:
250 - check 'Project release' is displayed
251 - check project has right release displayed
252 - Layers:
253 - check can add a layer if exists
254 - check at least three layers are displayed
255 - openembedded-core
256 - meta-poky
257 - meta-yocto-bsp
258 """
259 project_id = self.create_new_project(self.PROJECT_NAME + "-ST", '3', None, True)
260 url = reverse('project', args=(project_id,))
261 self.get(url)
262 self.wait_until_visible('#config-nav')
263
264 # check if the menu is displayed
265 self.wait_until_visible('#project-page')
266 block_l = self.driver.find_element(
267 By.XPATH, '//*[@id="project-page"]/div[2]')
268 project_release = self.driver.find_element(
269 By.XPATH, '//*[@id="project-page"]/div[1]/div[4]')
270 layers = block_l.find_element(By.ID, 'layer-container')
271
272 def check_machine_distro(self, item_name, new_item_name, block_id):
273 block = self.find(f'#{block_id}')
274 title = block.find_element(By.TAG_NAME, 'h3')
275 self.assertIn(item_name.capitalize(), title.text)
276 edit_btn = self.find(f'#change-{item_name}-toggle')
277 edit_btn.click()
278 self.wait_until_visible(f'#{item_name}-change-input')
279 name_input = self.find(f'#{item_name}-change-input')
280 name_input.clear()
281 name_input.send_keys(new_item_name)
282 change_btn = self.find(f'#{item_name}-change-btn')
283 change_btn.click()
284 self.wait_until_visible(f'#project-{item_name}-name')
285 project_name = self.find(f'#project-{item_name}-name')
286 self.assertIn(new_item_name, project_name.text)
287 # check change notificaiton is displayed
288 change_notification = self.find('#change-notification')
289 self.assertIn(
290 f'You have changed the {item_name} to: {new_item_name}', change_notification.text
291 )
292 hide_button = self.find('#hide-alert')
293 hide_button.click()
294 self.wait_until_not_visible('#change-notification')
295
296 # Machine
297 check_machine_distro(self, 'machine', 'qemux86-64', 'machine-section')
298 # Distro
299 check_machine_distro(self, 'distro', 'poky-altcfg', 'distro-section')
300
301 # Project release
302 title = project_release.find_element(By.TAG_NAME, 'h3')
303 self.assertIn("Project release", title.text)
304 self.assertIn(
305 "Yocto Project master", self.find('#project-release-title').text
306 )
307 # Layers
308 title = layers.find_element(By.TAG_NAME, 'h3')
309 self.assertIn("Layers", title.text)
310 self.wait_until_clickable('#layer-add-input')
311 # check at least three layers are displayed
312 # openembedded-core
313 # meta-poky
314 # meta-yocto-bsp
315 layer_list_items = []
316 starttime = time.time()
317 while len(layer_list_items) < 3:
318 layers_list = self.driver.find_element(By.ID, 'layers-in-project-list')
319 layer_list_items = layers_list.find_elements(By.TAG_NAME, 'li')
320 if time.time() > (starttime + 30):
321 self.fail("Layer list didn't contain at least 3 items within 30s (contained %d)" % len(layer_list_items))
322
323 # remove all layers except the first three layers
324 for i in range(3, len(layer_list_items)):
325 layer_list_items[i].find_element(By.TAG_NAME, 'span').click()
326
327 # check can add a layer if exists
328 add_layer_input = layers.find_element(By.ID, 'layer-add-input')
329 add_layer_input.send_keys('meta-oe')
330 self.wait_until_visible('#layer-container > form > div > span > div')
331 self.wait_until_visible('.dropdown-menu')
332 finder = lambda driver: driver.find_element(By.XPATH, '//*[@id="layer-container"]/form/div/span/div/div/div')
333 dropdown_item = self.wait_until_element_clickable(finder)
334 dropdown_item.click()
335 self.wait_until_clickable('#add-layer-btn')
336 add_layer_btn = layers.find_element(By.ID, 'add-layer-btn')
337 add_layer_btn.click()
338 self.wait_until_visible('#layers-in-project-list')
339
340 # check layer is added
341 layer_list_items = []
342 starttime = time.time()
343 while len(layer_list_items) < 4:
344 layers_list = self.driver.find_element(By.ID, 'layers-in-project-list')
345 layer_list_items = layers_list.find_elements(By.TAG_NAME, 'li')
346 if time.time() > (starttime + 30):
347 self.fail("Layer list didn't contain at least 4 items within 30s (contained %d)" % len(layer_list_items))
348
349 def test_project_page_tab_importlayer(self):
350 """ Test project page tab import layer """
351 self._navigate_to_project_page()
352 # navigate to "Import layers" tab
353 import_layers_tab = self._get_tabs()[2]
354 import_layers_tab.find_element(By.TAG_NAME, 'a').click()
355 self.wait_until_visible('#layer-git-repo-url')
356
357 # Check git repo radio button
358 git_repo_radio = self.find('#git-repo-radio')
359 git_repo_radio.click()
360
361 # Set git repo url
362 input_repo_url = self.find('#layer-git-repo-url')
363 input_repo_url.send_keys('git://git.yoctoproject.org/meta-fake')
364 # Blur the input to trigger the validation
365 input_repo_url.send_keys(Keys.TAB)
366
367 # Check name is set
368 input_layer_name = self.find('#import-layer-name')
369 self.assertTrue(input_layer_name.get_attribute('value') == 'meta-fake')
370
371 # Set branch
372 input_branch = self.find('#layer-git-ref')
373 input_branch.send_keys('master')
374
375 # Import layer
376 self.find('#import-and-add-btn').click()
377
378 # Check layer is added
379 self.wait_until_visible('#layer-container')
380 block_l = self.driver.find_element(
381 By.XPATH, '//*[@id="project-page"]/div[2]')
382 layers = block_l.find_element(By.ID, 'layer-container')
383 layers_list = layers.find_element(By.ID, 'layers-in-project-list')
384 layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li')
385 self.assertIn(
386 'meta-fake', str(layers_list_items[-1].text)
387 )
388
389 def test_project_page_custom_image_no_image(self):
390 """ Test project page tab "New custom image" when no custom image """
391 project_id = self.create_new_project(self.PROJECT_NAME + "-CustomImage", '3', None, True)
392 url = reverse('project', args=(project_id,))
393 self.get(url)
394 self.wait_until_visible('#config-nav')
395
396 # navigate to "Custom image" tab
397 custom_image_section = self._get_config_nav_item(2)
398 custom_image_section.click()
399 self.wait_until_visible('#empty-state-customimagestable')
400
401 # Check message when no custom image
402 self.assertIn(
403 "You have not created any custom images yet.", str(
404 self.find('#empty-state-customimagestable').text
405 )
406 )
407 div_empty_msg = self.find('#empty-state-customimagestable')
408 link_create_custom_image = div_empty_msg.find_element(
409 By.TAG_NAME, 'a')
410 self.assertTrue(TestProjectConfigTabBase.project_id is not None)
411 self.assertIn(
412 f"/toastergui/project/{project_id}/newcustomimage", str(
413 link_create_custom_image.get_attribute('href')
414 )
415 )
416 self.assertIn(
417 "Create your first custom image", str(
418 link_create_custom_image.text
419 )
420 )
421
422 def test_project_page_image_recipe(self):
423 """ Test project page section images
424 - Check image recipes are displayed
425 - Check search input
426 - Check image recipe build button works
427 - Check image recipe table features(show/hide column, pagination)
428 """
429 self._navigate_to_project_page()
430 # navigate to "Images section"
431 images_section = self._get_config_nav_item(3)
432 images_section.click()
433 self.wait_until_visible('#imagerecipestable')
434 rows = self.find_all('#imagerecipestable tbody tr')
435 self.assertTrue(len(rows) > 0)
436
437 # Test search input
438 self.wait_until_visible('#search-input-imagerecipestable')
439 recipe_input = self.find('#search-input-imagerecipestable')
440 recipe_input.send_keys('core-image-minimal')
441 self.find('#search-submit-imagerecipestable').click()
442 self.wait_until_visible('#imagerecipestable tbody tr')
443 rows = self.find_all('#imagerecipestable tbody tr')
444 self.assertTrue(len(rows) > 0)
445
446@pytest.mark.django_db
447@pytest.mark.order("last")
448class TestProjectConfigTabDB(TestProjectConfigTabBase):
449
450 def test_most_build_recipes(self):
451 """ Test most build recipes block contains"""
452 def rebuild_from_most_build_recipes(recipe_list_items):
453 checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input')
454 checkbox.click()
455 build_btn = self.find('#freq-build-btn')
456 build_btn.click()
457 self.wait_until_visible('#latest-builds')
458 wait_until_build(self, 'queued cloning starting parsing failed')
459 lastest_builds = self.driver.find_elements(
460 By.XPATH,
461 '//div[@id="latest-builds"]/div'
462 )
463 self.assertTrue(len(lastest_builds) >= 2)
464 last_build = lastest_builds[0]
465 try:
466 cancel_button = last_build.find_element(
467 By.XPATH,
468 '//span[@class="cancel-build-btn pull-right alert-link"]',
469 )
470 cancel_button.click()
471 except NoSuchElementException:
472 # Skip if the build is already cancelled
473 pass
474 wait_until_build_cancelled(self)
475
476 # Create a new project for remaining asserts
477 project_id = self.create_new_project(self.PROJECT_NAME + "-MostBuilt", '2', None, True)
478 url = reverse('project', args=(project_id,))
479 self.get(url)
480 self.wait_until_visible('#config-nav')
481
482 current_url = self.driver.current_url
483 url = current_url.split('?')[0]
484
485 # Create a new builds
486 self._create_builds()
487
488 # back to project page
489 self.driver.get(url)
490
491 self.wait_until_visible('#project-page')
492
493 # Most built recipes
494 most_built_recipes = self.driver.find_element(
495 By.XPATH, '//*[@id="project-page"]/div[1]/div[3]')
496 title = most_built_recipes.find_element(By.TAG_NAME, 'h3')
497 self.assertIn("Most built recipes", title.text)
498 # check can select a recipe and build it
499 self.wait_until_visible('#freq-build-list')
500 recipe_list = self.find('#freq-build-list')
501 recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li')
502 self.assertTrue(
503 len(recipe_list_items) > 0,
504 msg="No recipes found in the most built recipes list",
505 )
506 rebuild_from_most_build_recipes(recipe_list_items)
507
diff --git a/bitbake/lib/toaster/tests/functional/utils.py b/bitbake/lib/toaster/tests/functional/utils.py
new file mode 100644
index 0000000000..72345aef9f
--- /dev/null
+++ b/bitbake/lib/toaster/tests/functional/utils.py
@@ -0,0 +1,86 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# BitBake Toaster UI tests implementation
4#
5# Copyright (C) 2023 Savoir-faire Linux
6#
7# SPDX-License-Identifier: GPL-2.0-only
8
9
10from time import sleep
11from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, TimeoutException, WebDriverException
12from selenium.webdriver.common.by import By
13
14from orm.models import Build
15
16
17def wait_until_build(test_instance, state):
18 timeout = 60
19 start_time = 0
20 build_state = ''
21 while True:
22 try:
23 if start_time > timeout:
24 raise TimeoutException(
25 f'Build did not reach {state} state within {timeout} seconds'
26 )
27 last_build_state = test_instance.driver.find_element(
28 By.XPATH,
29 '//*[@id="latest-builds"]/div[1]//div[@class="build-state"]',
30 )
31 build_state = last_build_state.get_attribute(
32 'data-build-state')
33 state_text = state.lower().split()
34 if any(x in str(build_state).lower() for x in state_text):
35 return str(build_state).lower()
36 if 'failed' in str(build_state).lower():
37 break
38 except NoSuchElementException:
39 pass
40 except TimeoutException:
41 break
42 start_time += 1
43 sleep(1) # take a breath and try again
44
45def wait_until_build_cancelled(test_instance):
46 """ Cancel build take a while sometime, the method is to wait driver action
47 until build being cancelled
48 """
49 timeout = 30
50 start_time = 0
51 while True:
52 try:
53 if start_time > timeout:
54 raise TimeoutException(
55 f'Build did not reach cancelled state within {timeout} seconds'
56 )
57 last_build_state = test_instance.driver.find_element(
58 By.XPATH,
59 '//*[@id="latest-builds"]/div[1]//div[@class="build-state"]',
60 )
61 build_state = last_build_state.get_attribute(
62 'data-build-state')
63 if 'failed' in str(build_state).lower():
64 break
65 if 'cancelling' in str(build_state).lower():
66 pass
67 if 'cancelled' in str(build_state).lower():
68 break
69 except TimeoutException:
70 break
71 except NoSuchElementException:
72 pass
73 except StaleElementReferenceException:
74 pass
75 except WebDriverException:
76 pass
77 start_time += 1
78 sleep(1) # take a breath and try again
79
80def get_projectId_from_url(url):
81 # url = 'http://domainename.com/toastergui/project/1656/whatever
82 # or url = 'http://domainename.com/toastergui/project/1/
83 # or url = 'http://domainename.com/toastergui/project/186
84 assert '/toastergui/project/' in url, "URL is not valid"
85 url_to_list = url.split('/toastergui/project/')
86 return int(url_to_list[1].split('/')[0]) # project_id
diff --git a/bitbake/lib/toaster/tests/toaster-tests-requirements.txt b/bitbake/lib/toaster/tests/toaster-tests-requirements.txt
index 4f9fcc46d2..6243c00a36 100644
--- a/bitbake/lib/toaster/tests/toaster-tests-requirements.txt
+++ b/bitbake/lib/toaster/tests/toaster-tests-requirements.txt
@@ -1 +1,9 @@
1selenium==2.49.2 1selenium>=4.13.0
2pytest==7.4.2
3pytest-django==4.5.2
4pytest-env==1.1.0
5pytest-html==4.0.2
6pytest-metadata==3.0.0
7pytest-order==1.1.0
8requests
9
diff --git a/bitbake/lib/toaster/tests/views/test_views.py b/bitbake/lib/toaster/tests/views/test_views.py
index 735d596bcc..e1adfcf86a 100644
--- a/bitbake/lib/toaster/tests/views/test_views.py
+++ b/bitbake/lib/toaster/tests/views/test_views.py
@@ -9,6 +9,8 @@
9 9
10"""Test cases for Toaster GUI and ReST.""" 10"""Test cases for Toaster GUI and ReST."""
11 11
12import os
13import pytest
12from django.test import TestCase 14from django.test import TestCase
13from django.test.client import RequestFactory 15from django.test.client import RequestFactory
14from django.urls import reverse 16from django.urls import reverse
@@ -19,6 +21,7 @@ from orm.models import Layer_Version, Recipe
19from orm.models import CustomImageRecipe 21from orm.models import CustomImageRecipe
20from orm.models import CustomImagePackage 22from orm.models import CustomImagePackage
21 23
24from bldcontrol.models import BuildEnvironment
22import inspect 25import inspect
23import toastergui 26import toastergui
24 27
@@ -32,19 +35,32 @@ PROJECT_NAME2 = "test project 2"
32CLI_BUILDS_PROJECT_NAME = 'Command line builds' 35CLI_BUILDS_PROJECT_NAME = 'Command line builds'
33 36
34 37
38
35class ViewTests(TestCase): 39class ViewTests(TestCase):
36 """Tests to verify view APIs.""" 40 """Tests to verify view APIs."""
37 41
38 fixtures = ['toastergui-unittest-data'] 42 fixtures = ['toastergui-unittest-data']
43 builldir = os.environ.get('BUILDDIR')
39 44
40 def setUp(self): 45 def setUp(self):
41 46
42 self.project = Project.objects.first() 47 self.project = Project.objects.first()
48
43 self.recipe1 = Recipe.objects.get(pk=2) 49 self.recipe1 = Recipe.objects.get(pk=2)
50 # create a file and to recipe1 file_path
51 file_path = f"{self.builldir}/{self.recipe1.name.strip().replace(' ', '-')}.bb"
52 with open(file_path, 'w') as f:
53 f.write('foo')
54 self.recipe1.file_path = file_path
55 self.recipe1.save()
56
44 self.customr = CustomImageRecipe.objects.first() 57 self.customr = CustomImageRecipe.objects.first()
45 self.cust_package = CustomImagePackage.objects.first() 58 self.cust_package = CustomImagePackage.objects.first()
46 self.package = Package.objects.first() 59 self.package = Package.objects.first()
47 self.lver = Layer_Version.objects.first() 60 self.lver = Layer_Version.objects.first()
61 if BuildEnvironment.objects.count() == 0:
62 BuildEnvironment.objects.create(betype=BuildEnvironment.TYPE_LOCAL)
63
48 64
49 def test_get_base_call_returns_html(self): 65 def test_get_base_call_returns_html(self):
50 """Basic test for all-projects view""" 66 """Basic test for all-projects view"""
@@ -226,7 +242,7 @@ class ViewTests(TestCase):
226 recipe = CustomImageRecipe.objects.create( 242 recipe = CustomImageRecipe.objects.create(
227 name=name, project=self.project, 243 name=name, project=self.project,
228 base_recipe=self.recipe1, 244 base_recipe=self.recipe1,
229 file_path="/tmp/testing", 245 file_path=f"{self.builldir}/testing",
230 layer_version=self.customr.layer_version) 246 layer_version=self.customr.layer_version)
231 url = reverse('xhr_customrecipe_id', args=(recipe.id,)) 247 url = reverse('xhr_customrecipe_id', args=(recipe.id,))
232 response = self.client.delete(url) 248 response = self.client.delete(url)
@@ -297,7 +313,7 @@ class ViewTests(TestCase):
297 """Download the recipe file generated for the custom image""" 313 """Download the recipe file generated for the custom image"""
298 314
299 # Create a dummy recipe file for the custom image generation to read 315 # Create a dummy recipe file for the custom image generation to read
300 open("/tmp/a_recipe.bb", 'a').close() 316 open(f"{self.builldir}/a_recipe.bb", 'a').close()
301 response = self.client.get(reverse('customrecipedownload', 317 response = self.client.get(reverse('customrecipedownload',
302 args=(self.project.id, 318 args=(self.project.id,
303 self.customr.id))) 319 self.customr.id)))
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py
index b4cdc335ef..e367bd910e 100644
--- a/bitbake/lib/toaster/toastergui/api.py
+++ b/bitbake/lib/toaster/toastergui/api.py
@@ -11,7 +11,7 @@ import os
11import re 11import re
12import logging 12import logging
13import json 13import json
14import subprocess 14import glob
15from collections import Counter 15from collections import Counter
16 16
17from orm.models import Project, ProjectTarget, Build, Layer_Version 17from orm.models import Project, ProjectTarget, Build, Layer_Version
@@ -227,20 +227,18 @@ class XhrSetDefaultImageUrl(View):
227# same logical name 227# same logical name
228# * Each project that uses a layer will have its own 228# * Each project that uses a layer will have its own
229# LayerVersion and Project Layer for it 229# LayerVersion and Project Layer for it
230# * During the Paroject delete process, when the last 230# * During the Project delete process, when the last
231# LayerVersion for a 'local_source_dir' layer is deleted 231# LayerVersion for a 'local_source_dir' layer is deleted
232# then the Layer record is deleted to remove orphans 232# then the Layer record is deleted to remove orphans
233# 233#
234 234
235def scan_layer_content(layer,layer_version): 235def scan_layer_content(layer,layer_version):
236 # if this is a local layer directory, we can immediately scan its content 236 # if this is a local layer directory, we can immediately scan its content
237 if layer.local_source_dir: 237 if os.path.isdir(layer.local_source_dir):
238 try: 238 try:
239 # recipes-*/*/*.bb 239 # recipes-*/*/*.bb
240 cmd = '%s %s' % ('ls', os.path.join(layer.local_source_dir,'recipes-*/*/*.bb')) 240 recipes_list = glob.glob(os.path.join(layer.local_source_dir, 'recipes-*/*/*.bb'))
241 recipes_list = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read() 241 for recipe in recipes_list:
242 recipes_list = recipes_list.decode("utf-8").strip()
243 if recipes_list and 'No such' not in recipes_list:
244 for recipe in recipes_list.split('\n'): 242 for recipe in recipes_list.split('\n'):
245 recipe_path = recipe[recipe.rfind('recipes-'):] 243 recipe_path = recipe[recipe.rfind('recipes-'):]
246 recipe_name = recipe[recipe.rfind('/')+1:].replace('.bb','') 244 recipe_name = recipe[recipe.rfind('/')+1:].replace('.bb','')
@@ -260,6 +258,9 @@ def scan_layer_content(layer,layer_version):
260 258
261 except Exception as e: 259 except Exception as e:
262 logger.warning("ERROR:scan_layer_content: %s" % e) 260 logger.warning("ERROR:scan_layer_content: %s" % e)
261 else:
262 logger.warning("ERROR: wrong path given")
263 raise KeyError("local_source_dir")
263 264
264class XhrLayer(View): 265class XhrLayer(View):
265 """ Delete, Get, Add and Update Layer information 266 """ Delete, Get, Add and Update Layer information
@@ -456,15 +457,18 @@ class XhrLayer(View):
456 'layerdetailurl': 457 'layerdetailurl':
457 layer_dep.get_detailspage_url(project.pk)}) 458 layer_dep.get_detailspage_url(project.pk)})
458 459
459 # Scan the layer's content and update components 460 # Only scan_layer_content if layer is local
460 scan_layer_content(layer,layer_version) 461 if layer_data.get('local_source_dir', None):
462 # Scan the layer's content and update components
463 scan_layer_content(layer,layer_version)
461 464
462 except Layer_Version.DoesNotExist: 465 except Layer_Version.DoesNotExist:
463 return error_response("layer-dep-not-found") 466 return error_response("layer-dep-not-found")
464 except Project.DoesNotExist: 467 except Project.DoesNotExist:
465 return error_response("project-not-found") 468 return error_response("project-not-found")
466 except KeyError: 469 except KeyError as e:
467 return error_response("incorrect-parameters") 470 _log("KeyError: %s" % e)
471 return error_response(f"incorrect-parameters")
468 472
469 return JsonResponse({'error': "ok", 473 return JsonResponse({'error': "ok",
470 'imported_layer': { 474 'imported_layer': {
diff --git a/bitbake/lib/toaster/toastergui/fixtures/toastergui-unittest-data.xml b/bitbake/lib/toaster/toastergui/fixtures/toastergui-unittest-data.xml
index 4517ed1765..f626572fd1 100644
--- a/bitbake/lib/toaster/toastergui/fixtures/toastergui-unittest-data.xml
+++ b/bitbake/lib/toaster/toastergui/fixtures/toastergui-unittest-data.xml
@@ -6,10 +6,22 @@
6 <field type="CharField" name="dirpath">b</field> 6 <field type="CharField" name="dirpath">b</field>
7 <field type="CharField" name="branch">a</field> 7 <field type="CharField" name="branch">a</field>
8 </object> 8 </object>
9 <object pk="1" model="orm.distro">
10 <field type="DateTimeField" name="up_date"><None></None></field>
11 <field to="orm.layer_version" name="layer_version" rel="ManyToOneRel">1</field>
12 <field type="CharField" name="name">poky_distro1</field>
13 <field type="CharField" name="description">poky_distro1 description</field>
14 </object>
15 <object pk="2" model="orm.distro">
16 <field type="DateTimeField" name="up_date"><None></None></field>
17 <field to="orm.layer_version" name="layer_version" rel="ManyToOneRel">2</field>
18 <field type="CharField" name="name">poky_distro2</field>
19 <field type="CharField" name="description">poky_distro2 description</field>
20 </object>
9 <object pk="1" model="orm.release"> 21 <object pk="1" model="orm.release">
10 <field type="CharField" name="name">master</field> 22 <field type="CharField" name="name">foo_master</field>
11 <field type="CharField" name="description">master project</field> 23 <field type="CharField" name="description">master project</field>
12 <field to="orm.bitbake_version" name="bitbake_version">1</field> 24 <field to="orm.bitbakeversion" name="bitbake_version">1</field>
13 </object> 25 </object>
14 <object pk="1" model="orm.project"> 26 <object pk="1" model="orm.project">
15 <field type="CharField" name="name">a test project</field> 27 <field type="CharField" name="name">a test project</field>
@@ -34,12 +46,12 @@
34 <object pk="1" model="orm.ProjectVariable"> 46 <object pk="1" model="orm.ProjectVariable">
35 <field to="orm.project" name="project" rel="ManyToOneRel">1</field> 47 <field to="orm.project" name="project" rel="ManyToOneRel">1</field>
36 <field type="CharField" name="name">MACHINE</field> 48 <field type="CharField" name="name">MACHINE</field>
37 <field type="TextField" name="value">qemux86</field> 49 <field type="TextField" name="value">qemux86-64</field>
38 </object> 50 </object>
39 <object pk="2" model="orm.ProjectVariable"> 51 <object pk="2" model="orm.ProjectVariable">
40 <field to="orm.project" name="project" rel="ManyToOneRel">2</field> 52 <field to="orm.project" name="project" rel="ManyToOneRel">2</field>
41 <field type="CharField" name="name">MACHINE</field> 53 <field type="CharField" name="name">MACHINE</field>
42 <field type="TextField" name="value">qemux86</field> 54 <field type="TextField" name="value">qemux86-64</field>
43 </object> 55 </object>
44 <object pk="1" model="orm.build"> 56 <object pk="1" model="orm.build">
45 <field to="orm.project" name="project" rel="ManyToOneRel">1</field> 57 <field to="orm.project" name="project" rel="ManyToOneRel">1</field>
@@ -67,7 +79,7 @@
67 </object> 79 </object>
68 <object pk="3" model="orm.build"> 80 <object pk="3" model="orm.build">
69 <field to="orm.project" name="project" rel="ManyToOneRel">1</field> 81 <field to="orm.project" name="project" rel="ManyToOneRel">1</field>
70 <field type="CharField" name="machine">qemux86</field> 82 <field type="CharField" name="machine">qemux86-64</field>
71 <field type="CharField" name="distro"></field> 83 <field type="CharField" name="distro"></field>
72 <field type="CharField" name="distro_version"></field> 84 <field type="CharField" name="distro_version"></field>
73 <field type="DateTimeField" name="started_on">2016-02-12T18:46:20.114530+00:00</field> 85 <field type="DateTimeField" name="started_on">2016-02-12T18:46:20.114530+00:00</field>
@@ -79,7 +91,7 @@
79 </object> 91 </object>
80 <object pk="4" model="orm.build"> 92 <object pk="4" model="orm.build">
81 <field to="orm.project" name="project" rel="ManyToOneRel">2</field> 93 <field to="orm.project" name="project" rel="ManyToOneRel">2</field>
82 <field type="CharField" name="machine">qemux86</field> 94 <field type="CharField" name="machine">qemux86-64</field>
83 <field type="CharField" name="distro"></field> 95 <field type="CharField" name="distro"></field>
84 <field type="CharField" name="distro_version"></field> 96 <field type="CharField" name="distro_version"></field>
85 <field type="DateTimeField" name="started_on">2016-02-11T18:46:20.114530+00:00</field> 97 <field type="DateTimeField" name="started_on">2016-02-11T18:46:20.114530+00:00</field>
diff --git a/bitbake/lib/toaster/toastergui/forms.py b/bitbake/lib/toaster/toastergui/forms.py
new file mode 100644
index 0000000000..0f279e06c5
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/forms.py
@@ -0,0 +1,14 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# BitBake Toaster UI tests implementation
4#
5# Copyright (C) 2023 Savoir-faire Linux
6#
7# SPDX-License-Identifier: GPL-2.0-only
8#
9
10from django import forms
11from django.core.validators import FileExtensionValidator
12
13class LoadFileForm(forms.Form):
14 eventlog_file = forms.FileField(widget=forms.FileInput(attrs={'accept': '.json'}))
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css
index 5cd7e211a0..284355e70b 100644
--- a/bitbake/lib/toaster/toastergui/static/css/default.css
+++ b/bitbake/lib/toaster/toastergui/static/css/default.css
@@ -367,3 +367,31 @@ h2.panel-title { font-size: 30px; }
367 } 367 }
368} 368}
369/* End copied in from newer version of Font-Awesome 4.3.0 */ 369/* End copied in from newer version of Font-Awesome 4.3.0 */
370
371
372#overlay {
373 display: flex;
374 position: fixed;
375 top: 0;
376 left: 0;
377 width: 100%;
378 height: 100%;
379 background-color: rgba(0, 0, 0, 0.7);
380 align-items: center;
381 justify-content: center;
382 z-index: 999;
383}
384
385.spinner {
386 border: 6px solid rgba(255, 255, 255, 0.3);
387 border-radius: 50%;
388 border-top: 6px solid #3498db;
389 width: 50px;
390 height: 50px;
391 animation: spin 1s linear infinite;
392}
393
394@keyframes spin {
395 0% { transform: rotate(0deg); }
396 100% { transform: rotate(360deg); }
397}
diff --git a/bitbake/lib/toaster/toastergui/static/css/jquery.dataTables-1.13.8.min.css b/bitbake/lib/toaster/toastergui/static/css/jquery.dataTables-1.13.8.min.css
new file mode 100644
index 0000000000..c0a442ce07
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/css/jquery.dataTables-1.13.8.min.css
@@ -0,0 +1 @@
:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"â–¶"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"â–¼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"â–²";content:"â–²"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"â–¼";content:"â–¼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px;z-index:10}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a}
diff --git a/bitbake/lib/toaster/toastergui/static/js/bootstrap.js b/bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.js
index d47d640feb..170bd608f7 100644
--- a/bitbake/lib/toaster/toastergui/static/js/bootstrap.js
+++ b/bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.js
@@ -1,6 +1,6 @@
1/*! 1/*!
2 * Bootstrap v3.3.6 (http://getbootstrap.com) 2 * Bootstrap v3.4.1 (https://getbootstrap.com/)
3 * Copyright 2011-2016 Twitter, Inc. 3 * Copyright 2011-2019 Twitter, Inc.
4 * Licensed under the MIT license 4 * Licensed under the MIT license
5 */ 5 */
6 6
@@ -11,16 +11,16 @@ if (typeof jQuery === 'undefined') {
11+function ($) { 11+function ($) {
12 'use strict'; 12 'use strict';
13 var version = $.fn.jquery.split(' ')[0].split('.') 13 var version = $.fn.jquery.split(' ')[0].split('.')
14 if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) { 14 if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
15 throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3') 15 throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
16 } 16 }
17}(jQuery); 17}(jQuery);
18 18
19/* ======================================================================== 19/* ========================================================================
20 * Bootstrap: transition.js v3.3.6 20 * Bootstrap: transition.js v3.4.1
21 * http://getbootstrap.com/javascript/#transitions 21 * https://getbootstrap.com/docs/3.4/javascript/#transitions
22 * ======================================================================== 22 * ========================================================================
23 * Copyright 2011-2015 Twitter, Inc. 23 * Copyright 2011-2019 Twitter, Inc.
24 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
25 * ======================================================================== */ 25 * ======================================================================== */
26 26
@@ -28,7 +28,7 @@ if (typeof jQuery === 'undefined') {
28+function ($) { 28+function ($) {
29 'use strict'; 29 'use strict';
30 30
31 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 31 // CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
32 // ============================================================ 32 // ============================================================
33 33
34 function transitionEnd() { 34 function transitionEnd() {
@@ -50,7 +50,7 @@ if (typeof jQuery === 'undefined') {
50 return false // explicit for ie8 ( ._.) 50 return false // explicit for ie8 ( ._.)
51 } 51 }
52 52
53 // http://blog.alexmaccaw.com/css-transitions 53 // https://blog.alexmaccaw.com/css-transitions
54 $.fn.emulateTransitionEnd = function (duration) { 54 $.fn.emulateTransitionEnd = function (duration) {
55 var called = false 55 var called = false
56 var $el = this 56 var $el = this
@@ -77,10 +77,10 @@ if (typeof jQuery === 'undefined') {
77}(jQuery); 77}(jQuery);
78 78
79/* ======================================================================== 79/* ========================================================================
80 * Bootstrap: alert.js v3.3.6 80 * Bootstrap: alert.js v3.4.1
81 * http://getbootstrap.com/javascript/#alerts 81 * https://getbootstrap.com/docs/3.4/javascript/#alerts
82 * ======================================================================== 82 * ========================================================================
83 * Copyright 2011-2015 Twitter, Inc. 83 * Copyright 2011-2019 Twitter, Inc.
84 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 84 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
85 * ======================================================================== */ 85 * ======================================================================== */
86 86
@@ -96,7 +96,7 @@ if (typeof jQuery === 'undefined') {
96 $(el).on('click', dismiss, this.close) 96 $(el).on('click', dismiss, this.close)
97 } 97 }
98 98
99 Alert.VERSION = '3.3.6' 99 Alert.VERSION = '3.4.1'
100 100
101 Alert.TRANSITION_DURATION = 150 101 Alert.TRANSITION_DURATION = 150
102 102
@@ -109,7 +109,8 @@ if (typeof jQuery === 'undefined') {
109 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 109 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
110 } 110 }
111 111
112 var $parent = $(selector) 112 selector = selector === '#' ? [] : selector
113 var $parent = $(document).find(selector)
113 114
114 if (e) e.preventDefault() 115 if (e) e.preventDefault()
115 116
@@ -172,10 +173,10 @@ if (typeof jQuery === 'undefined') {
172}(jQuery); 173}(jQuery);
173 174
174/* ======================================================================== 175/* ========================================================================
175 * Bootstrap: button.js v3.3.6 176 * Bootstrap: button.js v3.4.1
176 * http://getbootstrap.com/javascript/#buttons 177 * https://getbootstrap.com/docs/3.4/javascript/#buttons
177 * ======================================================================== 178 * ========================================================================
178 * Copyright 2011-2015 Twitter, Inc. 179 * Copyright 2011-2019 Twitter, Inc.
179 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 180 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
180 * ======================================================================== */ 181 * ======================================================================== */
181 182
@@ -192,7 +193,7 @@ if (typeof jQuery === 'undefined') {
192 this.isLoading = false 193 this.isLoading = false
193 } 194 }
194 195
195 Button.VERSION = '3.3.6' 196 Button.VERSION = '3.4.1'
196 197
197 Button.DEFAULTS = { 198 Button.DEFAULTS = {
198 loadingText: 'loading...' 199 loadingText: 'loading...'
@@ -214,10 +215,10 @@ if (typeof jQuery === 'undefined') {
214 215
215 if (state == 'loadingText') { 216 if (state == 'loadingText') {
216 this.isLoading = true 217 this.isLoading = true
217 $el.addClass(d).attr(d, d) 218 $el.addClass(d).attr(d, d).prop(d, true)
218 } else if (this.isLoading) { 219 } else if (this.isLoading) {
219 this.isLoading = false 220 this.isLoading = false
220 $el.removeClass(d).removeAttr(d) 221 $el.removeClass(d).removeAttr(d).prop(d, false)
221 } 222 }
222 }, this), 0) 223 }, this), 0)
223 } 224 }
@@ -281,10 +282,15 @@ if (typeof jQuery === 'undefined') {
281 282
282 $(document) 283 $(document)
283 .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 284 .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
284 var $btn = $(e.target) 285 var $btn = $(e.target).closest('.btn')
285 if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
286 Plugin.call($btn, 'toggle') 286 Plugin.call($btn, 'toggle')
287 if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() 287 if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
288 // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
289 e.preventDefault()
290 // The target component still receive the focus
291 if ($btn.is('input,button')) $btn.trigger('focus')
292 else $btn.find('input:visible,button:visible').first().trigger('focus')
293 }
288 }) 294 })
289 .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 295 .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
290 $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 296 $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
@@ -293,10 +299,10 @@ if (typeof jQuery === 'undefined') {
293}(jQuery); 299}(jQuery);
294 300
295/* ======================================================================== 301/* ========================================================================
296 * Bootstrap: carousel.js v3.3.6 302 * Bootstrap: carousel.js v3.4.1
297 * http://getbootstrap.com/javascript/#carousel 303 * https://getbootstrap.com/docs/3.4/javascript/#carousel
298 * ======================================================================== 304 * ========================================================================
299 * Copyright 2011-2015 Twitter, Inc. 305 * Copyright 2011-2019 Twitter, Inc.
300 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 306 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
301 * ======================================================================== */ 307 * ======================================================================== */
302 308
@@ -324,7 +330,7 @@ if (typeof jQuery === 'undefined') {
324 .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 330 .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
325 } 331 }
326 332
327 Carousel.VERSION = '3.3.6' 333 Carousel.VERSION = '3.4.1'
328 334
329 Carousel.TRANSITION_DURATION = 600 335 Carousel.TRANSITION_DURATION = 600
330 336
@@ -438,7 +444,9 @@ if (typeof jQuery === 'undefined') {
438 var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 444 var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
439 if ($.support.transition && this.$element.hasClass('slide')) { 445 if ($.support.transition && this.$element.hasClass('slide')) {
440 $next.addClass(type) 446 $next.addClass(type)
441 $next[0].offsetWidth // force reflow 447 if (typeof $next === 'object' && $next.length) {
448 $next[0].offsetWidth // force reflow
449 }
442 $active.addClass(direction) 450 $active.addClass(direction)
443 $next.addClass(direction) 451 $next.addClass(direction)
444 $active 452 $active
@@ -500,10 +508,17 @@ if (typeof jQuery === 'undefined') {
500 // ================= 508 // =================
501 509
502 var clickHandler = function (e) { 510 var clickHandler = function (e) {
503 var href
504 var $this = $(this) 511 var $this = $(this)
505 var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 512 var href = $this.attr('href')
513 if (href) {
514 href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
515 }
516
517 var target = $this.attr('data-target') || href
518 var $target = $(document).find(target)
519
506 if (!$target.hasClass('carousel')) return 520 if (!$target.hasClass('carousel')) return
521
507 var options = $.extend({}, $target.data(), $this.data()) 522 var options = $.extend({}, $target.data(), $this.data())
508 var slideIndex = $this.attr('data-slide-to') 523 var slideIndex = $this.attr('data-slide-to')
509 if (slideIndex) options.interval = false 524 if (slideIndex) options.interval = false
@@ -531,13 +546,14 @@ if (typeof jQuery === 'undefined') {
531}(jQuery); 546}(jQuery);
532 547
533/* ======================================================================== 548/* ========================================================================
534 * Bootstrap: collapse.js v3.3.6 549 * Bootstrap: collapse.js v3.4.1
535 * http://getbootstrap.com/javascript/#collapse 550 * https://getbootstrap.com/docs/3.4/javascript/#collapse
536 * ======================================================================== 551 * ========================================================================
537 * Copyright 2011-2015 Twitter, Inc. 552 * Copyright 2011-2019 Twitter, Inc.
538 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 553 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
539 * ======================================================================== */ 554 * ======================================================================== */
540 555
556/* jshint latedef: false */
541 557
542+function ($) { 558+function ($) {
543 'use strict'; 559 'use strict';
@@ -561,7 +577,7 @@ if (typeof jQuery === 'undefined') {
561 if (this.options.toggle) this.toggle() 577 if (this.options.toggle) this.toggle()
562 } 578 }
563 579
564 Collapse.VERSION = '3.3.6' 580 Collapse.VERSION = '3.4.1'
565 581
566 Collapse.TRANSITION_DURATION = 350 582 Collapse.TRANSITION_DURATION = 350
567 583
@@ -668,7 +684,7 @@ if (typeof jQuery === 'undefined') {
668 } 684 }
669 685
670 Collapse.prototype.getParent = function () { 686 Collapse.prototype.getParent = function () {
671 return $(this.options.parent) 687 return $(document).find(this.options.parent)
672 .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 688 .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
673 .each($.proxy(function (i, element) { 689 .each($.proxy(function (i, element) {
674 var $element = $(element) 690 var $element = $(element)
@@ -691,7 +707,7 @@ if (typeof jQuery === 'undefined') {
691 var target = $trigger.attr('data-target') 707 var target = $trigger.attr('data-target')
692 || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 708 || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
693 709
694 return $(target) 710 return $(document).find(target)
695 } 711 }
696 712
697 713
@@ -743,10 +759,10 @@ if (typeof jQuery === 'undefined') {
743}(jQuery); 759}(jQuery);
744 760
745/* ======================================================================== 761/* ========================================================================
746 * Bootstrap: dropdown.js v3.3.6 762 * Bootstrap: dropdown.js v3.4.1
747 * http://getbootstrap.com/javascript/#dropdowns 763 * https://getbootstrap.com/docs/3.4/javascript/#dropdowns
748 * ======================================================================== 764 * ========================================================================
749 * Copyright 2011-2015 Twitter, Inc. 765 * Copyright 2011-2019 Twitter, Inc.
750 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 766 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
751 * ======================================================================== */ 767 * ======================================================================== */
752 768
@@ -763,7 +779,7 @@ if (typeof jQuery === 'undefined') {
763 $(element).on('click.bs.dropdown', this.toggle) 779 $(element).on('click.bs.dropdown', this.toggle)
764 } 780 }
765 781
766 Dropdown.VERSION = '3.3.6' 782 Dropdown.VERSION = '3.4.1'
767 783
768 function getParent($this) { 784 function getParent($this) {
769 var selector = $this.attr('data-target') 785 var selector = $this.attr('data-target')
@@ -773,7 +789,7 @@ if (typeof jQuery === 'undefined') {
773 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 789 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
774 } 790 }
775 791
776 var $parent = selector && $(selector) 792 var $parent = selector !== '#' ? $(document).find(selector) : null
777 793
778 return $parent && $parent.length ? $parent : $this.parent() 794 return $parent && $parent.length ? $parent : $this.parent()
779 } 795 }
@@ -909,10 +925,10 @@ if (typeof jQuery === 'undefined') {
909}(jQuery); 925}(jQuery);
910 926
911/* ======================================================================== 927/* ========================================================================
912 * Bootstrap: modal.js v3.3.6 928 * Bootstrap: modal.js v3.4.1
913 * http://getbootstrap.com/javascript/#modals 929 * https://getbootstrap.com/docs/3.4/javascript/#modals
914 * ======================================================================== 930 * ========================================================================
915 * Copyright 2011-2015 Twitter, Inc. 931 * Copyright 2011-2019 Twitter, Inc.
916 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 932 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
917 * ======================================================================== */ 933 * ======================================================================== */
918 934
@@ -924,15 +940,16 @@ if (typeof jQuery === 'undefined') {
924 // ====================== 940 // ======================
925 941
926 var Modal = function (element, options) { 942 var Modal = function (element, options) {
927 this.options = options 943 this.options = options
928 this.$body = $(document.body) 944 this.$body = $(document.body)
929 this.$element = $(element) 945 this.$element = $(element)
930 this.$dialog = this.$element.find('.modal-dialog') 946 this.$dialog = this.$element.find('.modal-dialog')
931 this.$backdrop = null 947 this.$backdrop = null
932 this.isShown = null 948 this.isShown = null
933 this.originalBodyPad = null 949 this.originalBodyPad = null
934 this.scrollbarWidth = 0 950 this.scrollbarWidth = 0
935 this.ignoreBackdropClick = false 951 this.ignoreBackdropClick = false
952 this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
936 953
937 if (this.options.remote) { 954 if (this.options.remote) {
938 this.$element 955 this.$element
@@ -943,7 +960,7 @@ if (typeof jQuery === 'undefined') {
943 } 960 }
944 } 961 }
945 962
946 Modal.VERSION = '3.3.6' 963 Modal.VERSION = '3.4.1'
947 964
948 Modal.TRANSITION_DURATION = 300 965 Modal.TRANSITION_DURATION = 300
949 Modal.BACKDROP_TRANSITION_DURATION = 150 966 Modal.BACKDROP_TRANSITION_DURATION = 150
@@ -960,7 +977,7 @@ if (typeof jQuery === 'undefined') {
960 977
961 Modal.prototype.show = function (_relatedTarget) { 978 Modal.prototype.show = function (_relatedTarget) {
962 var that = this 979 var that = this
963 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 980 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
964 981
965 this.$element.trigger(e) 982 this.$element.trigger(e)
966 983
@@ -1050,7 +1067,9 @@ if (typeof jQuery === 'undefined') {
1050 $(document) 1067 $(document)
1051 .off('focusin.bs.modal') // guard against infinite focus loop 1068 .off('focusin.bs.modal') // guard against infinite focus loop
1052 .on('focusin.bs.modal', $.proxy(function (e) { 1069 .on('focusin.bs.modal', $.proxy(function (e) {
1053 if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 1070 if (document !== e.target &&
1071 this.$element[0] !== e.target &&
1072 !this.$element.has(e.target).length) {
1054 this.$element.trigger('focus') 1073 this.$element.trigger('focus')
1055 } 1074 }
1056 }, this)) 1075 }, this))
@@ -1152,7 +1171,7 @@ if (typeof jQuery === 'undefined') {
1152 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight 1171 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
1153 1172
1154 this.$element.css({ 1173 this.$element.css({
1155 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', 1174 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
1156 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' 1175 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
1157 }) 1176 })
1158 } 1177 }
@@ -1177,11 +1196,26 @@ if (typeof jQuery === 'undefined') {
1177 Modal.prototype.setScrollbar = function () { 1196 Modal.prototype.setScrollbar = function () {
1178 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 1197 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1179 this.originalBodyPad = document.body.style.paddingRight || '' 1198 this.originalBodyPad = document.body.style.paddingRight || ''
1180 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 1199 var scrollbarWidth = this.scrollbarWidth
1200 if (this.bodyIsOverflowing) {
1201 this.$body.css('padding-right', bodyPad + scrollbarWidth)
1202 $(this.fixedContent).each(function (index, element) {
1203 var actualPadding = element.style.paddingRight
1204 var calculatedPadding = $(element).css('padding-right')
1205 $(element)
1206 .data('padding-right', actualPadding)
1207 .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
1208 })
1209 }
1181 } 1210 }
1182 1211
1183 Modal.prototype.resetScrollbar = function () { 1212 Modal.prototype.resetScrollbar = function () {
1184 this.$body.css('padding-right', this.originalBodyPad) 1213 this.$body.css('padding-right', this.originalBodyPad)
1214 $(this.fixedContent).each(function (index, element) {
1215 var padding = $(element).data('padding-right')
1216 $(element).removeData('padding-right')
1217 element.style.paddingRight = padding ? padding : ''
1218 })
1185 } 1219 }
1186 1220
1187 Modal.prototype.measureScrollbar = function () { // thx walsh 1221 Modal.prototype.measureScrollbar = function () { // thx walsh
@@ -1199,8 +1233,8 @@ if (typeof jQuery === 'undefined') {
1199 1233
1200 function Plugin(option, _relatedTarget) { 1234 function Plugin(option, _relatedTarget) {
1201 return this.each(function () { 1235 return this.each(function () {
1202 var $this = $(this) 1236 var $this = $(this)
1203 var data = $this.data('bs.modal') 1237 var data = $this.data('bs.modal')
1204 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 1238 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1205 1239
1206 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 1240 if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
@@ -1211,7 +1245,7 @@ if (typeof jQuery === 'undefined') {
1211 1245
1212 var old = $.fn.modal 1246 var old = $.fn.modal
1213 1247
1214 $.fn.modal = Plugin 1248 $.fn.modal = Plugin
1215 $.fn.modal.Constructor = Modal 1249 $.fn.modal.Constructor = Modal
1216 1250
1217 1251
@@ -1228,10 +1262,13 @@ if (typeof jQuery === 'undefined') {
1228 // ============== 1262 // ==============
1229 1263
1230 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 1264 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1231 var $this = $(this) 1265 var $this = $(this)
1232 var href = $this.attr('href') 1266 var href = $this.attr('href')
1233 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 1267 var target = $this.attr('data-target') ||
1234 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 1268 (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
1269
1270 var $target = $(document).find(target)
1271 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1235 1272
1236 if ($this.is('a')) e.preventDefault() 1273 if ($this.is('a')) e.preventDefault()
1237 1274
@@ -1247,18 +1284,148 @@ if (typeof jQuery === 'undefined') {
1247}(jQuery); 1284}(jQuery);
1248 1285
1249/* ======================================================================== 1286/* ========================================================================
1250 * Bootstrap: tooltip.js v3.3.6 1287 * Bootstrap: tooltip.js v3.4.1
1251 * http://getbootstrap.com/javascript/#tooltip 1288 * https://getbootstrap.com/docs/3.4/javascript/#tooltip
1252 * Inspired by the original jQuery.tipsy by Jason Frame 1289 * Inspired by the original jQuery.tipsy by Jason Frame
1253 * ======================================================================== 1290 * ========================================================================
1254 * Copyright 2011-2015 Twitter, Inc. 1291 * Copyright 2011-2019 Twitter, Inc.
1255 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1292 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1256 * ======================================================================== */ 1293 * ======================================================================== */
1257 1294
1258
1259+function ($) { 1295+function ($) {
1260 'use strict'; 1296 'use strict';
1261 1297
1298 var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
1299
1300 var uriAttrs = [
1301 'background',
1302 'cite',
1303 'href',
1304 'itemtype',
1305 'longdesc',
1306 'poster',
1307 'src',
1308 'xlink:href'
1309 ]
1310
1311 var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
1312
1313 var DefaultWhitelist = {
1314 // Global attributes allowed on any supplied element below.
1315 '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
1316 a: ['target', 'href', 'title', 'rel'],
1317 area: [],
1318 b: [],
1319 br: [],
1320 col: [],
1321 code: [],
1322 div: [],
1323 em: [],
1324 hr: [],
1325 h1: [],
1326 h2: [],
1327 h3: [],
1328 h4: [],
1329 h5: [],
1330 h6: [],
1331 i: [],
1332 img: ['src', 'alt', 'title', 'width', 'height'],
1333 li: [],
1334 ol: [],
1335 p: [],
1336 pre: [],
1337 s: [],
1338 small: [],
1339 span: [],
1340 sub: [],
1341 sup: [],
1342 strong: [],
1343 u: [],
1344 ul: []
1345 }
1346
1347 /**
1348 * A pattern that recognizes a commonly useful subset of URLs that are safe.
1349 *
1350 * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
1351 */
1352 var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
1353
1354 /**
1355 * A pattern that matches safe data URLs. Only matches image, video and audio types.
1356 *
1357 * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
1358 */
1359 var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
1360
1361 function allowedAttribute(attr, allowedAttributeList) {
1362 var attrName = attr.nodeName.toLowerCase()
1363
1364 if ($.inArray(attrName, allowedAttributeList) !== -1) {
1365 if ($.inArray(attrName, uriAttrs) !== -1) {
1366 return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
1367 }
1368
1369 return true
1370 }
1371
1372 var regExp = $(allowedAttributeList).filter(function (index, value) {
1373 return value instanceof RegExp
1374 })
1375
1376 // Check if a regular expression validates the attribute.
1377 for (var i = 0, l = regExp.length; i < l; i++) {
1378 if (attrName.match(regExp[i])) {
1379 return true
1380 }
1381 }
1382
1383 return false
1384 }
1385
1386 function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
1387 if (unsafeHtml.length === 0) {
1388 return unsafeHtml
1389 }
1390
1391 if (sanitizeFn && typeof sanitizeFn === 'function') {
1392 return sanitizeFn(unsafeHtml)
1393 }
1394
1395 // IE 8 and below don't support createHTMLDocument
1396 if (!document.implementation || !document.implementation.createHTMLDocument) {
1397 return unsafeHtml
1398 }
1399
1400 var createdDocument = document.implementation.createHTMLDocument('sanitization')
1401 createdDocument.body.innerHTML = unsafeHtml
1402
1403 var whitelistKeys = $.map(whiteList, function (el, i) { return i })
1404 var elements = $(createdDocument.body).find('*')
1405
1406 for (var i = 0, len = elements.length; i < len; i++) {
1407 var el = elements[i]
1408 var elName = el.nodeName.toLowerCase()
1409
1410 if ($.inArray(elName, whitelistKeys) === -1) {
1411 el.parentNode.removeChild(el)
1412
1413 continue
1414 }
1415
1416 var attributeList = $.map(el.attributes, function (el) { return el })
1417 var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
1418
1419 for (var j = 0, len2 = attributeList.length; j < len2; j++) {
1420 if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
1421 el.removeAttribute(attributeList[j].nodeName)
1422 }
1423 }
1424 }
1425
1426 return createdDocument.body.innerHTML
1427 }
1428
1262 // TOOLTIP PUBLIC CLASS DEFINITION 1429 // TOOLTIP PUBLIC CLASS DEFINITION
1263 // =============================== 1430 // ===============================
1264 1431
@@ -1274,7 +1441,7 @@ if (typeof jQuery === 'undefined') {
1274 this.init('tooltip', element, options) 1441 this.init('tooltip', element, options)
1275 } 1442 }
1276 1443
1277 Tooltip.VERSION = '3.3.6' 1444 Tooltip.VERSION = '3.4.1'
1278 1445
1279 Tooltip.TRANSITION_DURATION = 150 1446 Tooltip.TRANSITION_DURATION = 150
1280 1447
@@ -1291,7 +1458,10 @@ if (typeof jQuery === 'undefined') {
1291 viewport: { 1458 viewport: {
1292 selector: 'body', 1459 selector: 'body',
1293 padding: 0 1460 padding: 0
1294 } 1461 },
1462 sanitize : true,
1463 sanitizeFn : null,
1464 whiteList : DefaultWhitelist
1295 } 1465 }
1296 1466
1297 Tooltip.prototype.init = function (type, element, options) { 1467 Tooltip.prototype.init = function (type, element, options) {
@@ -1299,7 +1469,7 @@ if (typeof jQuery === 'undefined') {
1299 this.type = type 1469 this.type = type
1300 this.$element = $(element) 1470 this.$element = $(element)
1301 this.options = this.getOptions(options) 1471 this.options = this.getOptions(options)
1302 this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 1472 this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
1303 this.inState = { click: false, hover: false, focus: false } 1473 this.inState = { click: false, hover: false, focus: false }
1304 1474
1305 if (this.$element[0] instanceof document.constructor && !this.options.selector) { 1475 if (this.$element[0] instanceof document.constructor && !this.options.selector) {
@@ -1332,7 +1502,15 @@ if (typeof jQuery === 'undefined') {
1332 } 1502 }
1333 1503
1334 Tooltip.prototype.getOptions = function (options) { 1504 Tooltip.prototype.getOptions = function (options) {
1335 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 1505 var dataAttributes = this.$element.data()
1506
1507 for (var dataAttr in dataAttributes) {
1508 if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
1509 delete dataAttributes[dataAttr]
1510 }
1511 }
1512
1513 options = $.extend({}, this.getDefaults(), dataAttributes, options)
1336 1514
1337 if (options.delay && typeof options.delay == 'number') { 1515 if (options.delay && typeof options.delay == 'number') {
1338 options.delay = { 1516 options.delay = {
@@ -1341,6 +1519,10 @@ if (typeof jQuery === 'undefined') {
1341 } 1519 }
1342 } 1520 }
1343 1521
1522 if (options.sanitize) {
1523 options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
1524 }
1525
1344 return options 1526 return options
1345 } 1527 }
1346 1528
@@ -1452,7 +1634,7 @@ if (typeof jQuery === 'undefined') {
1452 .addClass(placement) 1634 .addClass(placement)
1453 .data('bs.' + this.type, this) 1635 .data('bs.' + this.type, this)
1454 1636
1455 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 1637 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
1456 this.$element.trigger('inserted.bs.' + this.type) 1638 this.$element.trigger('inserted.bs.' + this.type)
1457 1639
1458 var pos = this.getPosition() 1640 var pos = this.getPosition()
@@ -1554,7 +1736,16 @@ if (typeof jQuery === 'undefined') {
1554 var $tip = this.tip() 1736 var $tip = this.tip()
1555 var title = this.getTitle() 1737 var title = this.getTitle()
1556 1738
1557 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 1739 if (this.options.html) {
1740 if (this.options.sanitize) {
1741 title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
1742 }
1743
1744 $tip.find('.tooltip-inner').html(title)
1745 } else {
1746 $tip.find('.tooltip-inner').text(title)
1747 }
1748
1558 $tip.removeClass('fade in top bottom left right') 1749 $tip.removeClass('fade in top bottom left right')
1559 } 1750 }
1560 1751
@@ -1565,9 +1756,11 @@ if (typeof jQuery === 'undefined') {
1565 1756
1566 function complete() { 1757 function complete() {
1567 if (that.hoverState != 'in') $tip.detach() 1758 if (that.hoverState != 'in') $tip.detach()
1568 that.$element 1759 if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
1569 .removeAttr('aria-describedby') 1760 that.$element
1570 .trigger('hidden.bs.' + that.type) 1761 .removeAttr('aria-describedby')
1762 .trigger('hidden.bs.' + that.type)
1763 }
1571 callback && callback() 1764 callback && callback()
1572 } 1765 }
1573 1766
@@ -1610,7 +1803,10 @@ if (typeof jQuery === 'undefined') {
1610 // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 1803 // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
1611 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 1804 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
1612 } 1805 }
1613 var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() 1806 var isSvg = window.SVGElement && el instanceof window.SVGElement
1807 // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
1808 // See https://github.com/twbs/bootstrap/issues/20280
1809 var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
1614 var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 1810 var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
1615 var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 1811 var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
1616 1812
@@ -1726,9 +1922,13 @@ if (typeof jQuery === 'undefined') {
1726 that.$tip = null 1922 that.$tip = null
1727 that.$arrow = null 1923 that.$arrow = null
1728 that.$viewport = null 1924 that.$viewport = null
1925 that.$element = null
1729 }) 1926 })
1730 } 1927 }
1731 1928
1929 Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
1930 return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
1931 }
1732 1932
1733 // TOOLTIP PLUGIN DEFINITION 1933 // TOOLTIP PLUGIN DEFINITION
1734 // ========================= 1934 // =========================
@@ -1762,10 +1962,10 @@ if (typeof jQuery === 'undefined') {
1762}(jQuery); 1962}(jQuery);
1763 1963
1764/* ======================================================================== 1964/* ========================================================================
1765 * Bootstrap: popover.js v3.3.6 1965 * Bootstrap: popover.js v3.4.1
1766 * http://getbootstrap.com/javascript/#popovers 1966 * https://getbootstrap.com/docs/3.4/javascript/#popovers
1767 * ======================================================================== 1967 * ========================================================================
1768 * Copyright 2011-2015 Twitter, Inc. 1968 * Copyright 2011-2019 Twitter, Inc.
1769 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1969 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1770 * ======================================================================== */ 1970 * ======================================================================== */
1771 1971
@@ -1782,7 +1982,7 @@ if (typeof jQuery === 'undefined') {
1782 1982
1783 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 1983 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1784 1984
1785 Popover.VERSION = '3.3.6' 1985 Popover.VERSION = '3.4.1'
1786 1986
1787 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 1987 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1788 placement: 'right', 1988 placement: 'right',
@@ -1808,10 +2008,25 @@ if (typeof jQuery === 'undefined') {
1808 var title = this.getTitle() 2008 var title = this.getTitle()
1809 var content = this.getContent() 2009 var content = this.getContent()
1810 2010
1811 $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 2011 if (this.options.html) {
1812 $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events 2012 var typeContent = typeof content
1813 this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 2013
1814 ](content) 2014 if (this.options.sanitize) {
2015 title = this.sanitizeHtml(title)
2016
2017 if (typeContent === 'string') {
2018 content = this.sanitizeHtml(content)
2019 }
2020 }
2021
2022 $tip.find('.popover-title').html(title)
2023 $tip.find('.popover-content').children().detach().end()[
2024 typeContent === 'string' ? 'html' : 'append'
2025 ](content)
2026 } else {
2027 $tip.find('.popover-title').text(title)
2028 $tip.find('.popover-content').children().detach().end().text(content)
2029 }
1815 2030
1816 $tip.removeClass('fade top bottom left right in') 2031 $tip.removeClass('fade top bottom left right in')
1817 2032
@@ -1830,8 +2045,8 @@ if (typeof jQuery === 'undefined') {
1830 2045
1831 return $e.attr('data-content') 2046 return $e.attr('data-content')
1832 || (typeof o.content == 'function' ? 2047 || (typeof o.content == 'function' ?
1833 o.content.call($e[0]) : 2048 o.content.call($e[0]) :
1834 o.content) 2049 o.content)
1835 } 2050 }
1836 2051
1837 Popover.prototype.arrow = function () { 2052 Popover.prototype.arrow = function () {
@@ -1871,10 +2086,10 @@ if (typeof jQuery === 'undefined') {
1871}(jQuery); 2086}(jQuery);
1872 2087
1873/* ======================================================================== 2088/* ========================================================================
1874 * Bootstrap: scrollspy.js v3.3.6 2089 * Bootstrap: scrollspy.js v3.4.1
1875 * http://getbootstrap.com/javascript/#scrollspy 2090 * https://getbootstrap.com/docs/3.4/javascript/#scrollspy
1876 * ======================================================================== 2091 * ========================================================================
1877 * Copyright 2011-2015 Twitter, Inc. 2092 * Copyright 2011-2019 Twitter, Inc.
1878 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2093 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1879 * ======================================================================== */ 2094 * ======================================================================== */
1880 2095
@@ -1900,7 +2115,7 @@ if (typeof jQuery === 'undefined') {
1900 this.process() 2115 this.process()
1901 } 2116 }
1902 2117
1903 ScrollSpy.VERSION = '3.3.6' 2118 ScrollSpy.VERSION = '3.4.1'
1904 2119
1905 ScrollSpy.DEFAULTS = { 2120 ScrollSpy.DEFAULTS = {
1906 offset: 10 2121 offset: 10
@@ -2044,10 +2259,10 @@ if (typeof jQuery === 'undefined') {
2044}(jQuery); 2259}(jQuery);
2045 2260
2046/* ======================================================================== 2261/* ========================================================================
2047 * Bootstrap: tab.js v3.3.6 2262 * Bootstrap: tab.js v3.4.1
2048 * http://getbootstrap.com/javascript/#tabs 2263 * https://getbootstrap.com/docs/3.4/javascript/#tabs
2049 * ======================================================================== 2264 * ========================================================================
2050 * Copyright 2011-2015 Twitter, Inc. 2265 * Copyright 2011-2019 Twitter, Inc.
2051 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2266 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2052 * ======================================================================== */ 2267 * ======================================================================== */
2053 2268
@@ -2064,7 +2279,7 @@ if (typeof jQuery === 'undefined') {
2064 // jscs:enable requireDollarBeforejQueryAssignment 2279 // jscs:enable requireDollarBeforejQueryAssignment
2065 } 2280 }
2066 2281
2067 Tab.VERSION = '3.3.6' 2282 Tab.VERSION = '3.4.1'
2068 2283
2069 Tab.TRANSITION_DURATION = 150 2284 Tab.TRANSITION_DURATION = 150
2070 2285
@@ -2093,7 +2308,7 @@ if (typeof jQuery === 'undefined') {
2093 2308
2094 if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return 2309 if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
2095 2310
2096 var $target = $(selector) 2311 var $target = $(document).find(selector)
2097 2312
2098 this.activate($this.closest('li'), $ul) 2313 this.activate($this.closest('li'), $ul)
2099 this.activate($target, $target.parent(), function () { 2314 this.activate($target, $target.parent(), function () {
@@ -2118,15 +2333,15 @@ if (typeof jQuery === 'undefined') {
2118 $active 2333 $active
2119 .removeClass('active') 2334 .removeClass('active')
2120 .find('> .dropdown-menu > .active') 2335 .find('> .dropdown-menu > .active')
2121 .removeClass('active') 2336 .removeClass('active')
2122 .end() 2337 .end()
2123 .find('[data-toggle="tab"]') 2338 .find('[data-toggle="tab"]')
2124 .attr('aria-expanded', false) 2339 .attr('aria-expanded', false)
2125 2340
2126 element 2341 element
2127 .addClass('active') 2342 .addClass('active')
2128 .find('[data-toggle="tab"]') 2343 .find('[data-toggle="tab"]')
2129 .attr('aria-expanded', true) 2344 .attr('aria-expanded', true)
2130 2345
2131 if (transition) { 2346 if (transition) {
2132 element[0].offsetWidth // reflow for transition 2347 element[0].offsetWidth // reflow for transition
@@ -2138,10 +2353,10 @@ if (typeof jQuery === 'undefined') {
2138 if (element.parent('.dropdown-menu').length) { 2353 if (element.parent('.dropdown-menu').length) {
2139 element 2354 element
2140 .closest('li.dropdown') 2355 .closest('li.dropdown')
2141 .addClass('active') 2356 .addClass('active')
2142 .end() 2357 .end()
2143 .find('[data-toggle="tab"]') 2358 .find('[data-toggle="tab"]')
2144 .attr('aria-expanded', true) 2359 .attr('aria-expanded', true)
2145 } 2360 }
2146 2361
2147 callback && callback() 2362 callback && callback()
@@ -2200,10 +2415,10 @@ if (typeof jQuery === 'undefined') {
2200}(jQuery); 2415}(jQuery);
2201 2416
2202/* ======================================================================== 2417/* ========================================================================
2203 * Bootstrap: affix.js v3.3.6 2418 * Bootstrap: affix.js v3.4.1
2204 * http://getbootstrap.com/javascript/#affix 2419 * https://getbootstrap.com/docs/3.4/javascript/#affix
2205 * ======================================================================== 2420 * ========================================================================
2206 * Copyright 2011-2015 Twitter, Inc. 2421 * Copyright 2011-2019 Twitter, Inc.
2207 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2422 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2208 * ======================================================================== */ 2423 * ======================================================================== */
2209 2424
@@ -2217,7 +2432,9 @@ if (typeof jQuery === 'undefined') {
2217 var Affix = function (element, options) { 2432 var Affix = function (element, options) {
2218 this.options = $.extend({}, Affix.DEFAULTS, options) 2433 this.options = $.extend({}, Affix.DEFAULTS, options)
2219 2434
2220 this.$target = $(this.options.target) 2435 var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
2436
2437 this.$target = target
2221 .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 2438 .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
2222 .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 2439 .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
2223 2440
@@ -2229,7 +2446,7 @@ if (typeof jQuery === 'undefined') {
2229 this.checkPosition() 2446 this.checkPosition()
2230 } 2447 }
2231 2448
2232 Affix.VERSION = '3.3.6' 2449 Affix.VERSION = '3.4.1'
2233 2450
2234 Affix.RESET = 'affix affix-top affix-bottom' 2451 Affix.RESET = 'affix affix-top affix-bottom'
2235 2452
diff --git a/bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.min.js b/bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.min.js
new file mode 100644
index 0000000000..eb0a8b410f
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/js/bootstrap-3.4.1.min.js
@@ -0,0 +1,6 @@
1/*!
2 * Bootstrap v3.4.1 (https://getbootstrap.com/)
3 * Copyright 2011-2019 Twitter, Inc.
4 * Licensed under the MIT license
5 */
6if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");!function(t){"use strict";var e=jQuery.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||3<e[0])throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(),function(n){"use strict";n.fn.emulateTransitionEnd=function(t){var e=!1,i=this;n(this).one("bsTransitionEnd",function(){e=!0});return setTimeout(function(){e||n(i).trigger(n.support.transition.end)},t),this},n(function(){n.support.transition=function o(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(t.style[i]!==undefined)return{end:e[i]};return!1}(),n.support.transition&&(n.event.special.bsTransitionEnd={bindType:n.support.transition.end,delegateType:n.support.transition.end,handle:function(t){if(n(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(s){"use strict";var e='[data-dismiss="alert"]',a=function(t){s(t).on("click",e,this.close)};a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.close=function(t){var e=s(this),i=e.attr("data-target");i||(i=(i=e.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),i="#"===i?[]:i;var o=s(document).find(i);function n(){o.detach().trigger("closed.bs.alert").remove()}t&&t.preventDefault(),o.length||(o=e.closest(".alert")),o.trigger(t=s.Event("close.bs.alert")),t.isDefaultPrevented()||(o.removeClass("in"),s.support.transition&&o.hasClass("fade")?o.one("bsTransitionEnd",n).emulateTransitionEnd(a.TRANSITION_DURATION):n())};var t=s.fn.alert;s.fn.alert=function o(i){return this.each(function(){var t=s(this),e=t.data("bs.alert");e||t.data("bs.alert",e=new a(this)),"string"==typeof i&&e[i].call(t)})},s.fn.alert.Constructor=a,s.fn.alert.noConflict=function(){return s.fn.alert=t,this},s(document).on("click.bs.alert.data-api",e,a.prototype.close)}(jQuery),function(s){"use strict";var n=function(t,e){this.$element=s(t),this.options=s.extend({},n.DEFAULTS,e),this.isLoading=!1};function i(o){return this.each(function(){var t=s(this),e=t.data("bs.button"),i="object"==typeof o&&o;e||t.data("bs.button",e=new n(this,i)),"toggle"==o?e.toggle():o&&e.setState(o)})}n.VERSION="3.4.1",n.DEFAULTS={loadingText:"loading..."},n.prototype.setState=function(t){var e="disabled",i=this.$element,o=i.is("input")?"val":"html",n=i.data();t+="Text",null==n.resetText&&i.data("resetText",i[o]()),setTimeout(s.proxy(function(){i[o](null==n[t]?this.options[t]:n[t]),"loadingText"==t?(this.isLoading=!0,i.addClass(e).attr(e,e).prop(e,!0)):this.isLoading&&(this.isLoading=!1,i.removeClass(e).removeAttr(e).prop(e,!1))},this),0)},n.prototype.toggle=function(){var t=!0,e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var i=this.$element.find("input");"radio"==i.prop("type")?(i.prop("checked")&&(t=!1),e.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==i.prop("type")&&(i.prop("checked")!==this.$element.hasClass("active")&&(t=!1),this.$element.toggleClass("active")),i.prop("checked",this.$element.hasClass("active")),t&&i.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var t=s.fn.button;s.fn.button=i,s.fn.button.Constructor=n,s.fn.button.noConflict=function(){return s.fn.button=t,this},s(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=s(t.target).closest(".btn");i.call(e,"toggle"),s(t.target).is('input[type="radio"], input[type="checkbox"]')||(t.preventDefault(),e.is("input,button")?e.trigger("focus"):e.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(t){s(t.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(t.type))})}(jQuery),function(p){"use strict";var c=function(t,e){this.$element=p(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=e,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",p.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",p.proxy(this.pause,this)).on("mouseleave.bs.carousel",p.proxy(this.cycle,this))};function r(n){return this.each(function(){var t=p(this),e=t.data("bs.carousel"),i=p.extend({},c.DEFAULTS,t.data(),"object"==typeof n&&n),o="string"==typeof n?n:i.slide;e||t.data("bs.carousel",e=new c(this,i)),"number"==typeof n?e.to(n):o?e[o]():i.interval&&e.pause().cycle()})}c.VERSION="3.4.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},c.prototype.cycle=function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(p.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},c.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e);if(("prev"==t&&0===i||"next"==t&&i==this.$items.length-1)&&!this.options.wrap)return e;var o=(i+("prev"==t?-1:1))%this.$items.length;return this.$items.eq(o)},c.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(t>this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(i<t?"next":"prev",this.$items.eq(t))},c.prototype.pause=function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&p.support.transition&&(this.$element.trigger(p.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(t,e){var i=this.$element.find(".item.active"),o=e||this.getItemForDirection(t,i),n=this.interval,s="next"==t?"left":"right",a=this;if(o.hasClass("active"))return this.sliding=!1;var r=o[0],l=p.Event("slide.bs.carousel",{relatedTarget:r,direction:s});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,n&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var h=p(this.$indicators.children()[this.getItemIndex(o)]);h&&h.addClass("active")}var d=p.Event("slid.bs.carousel",{relatedTarget:r,direction:s});return p.support.transition&&this.$element.hasClass("slide")?(o.addClass(t),"object"==typeof o&&o.length&&o[0].offsetWidth,i.addClass(s),o.addClass(s),i.one("bsTransitionEnd",function(){o.removeClass([t,s].join(" ")).addClass("active"),i.removeClass(["active",s].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger(d)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(i.removeClass("active"),o.addClass("active"),this.sliding=!1,this.$element.trigger(d)),n&&this.cycle(),this}};var t=p.fn.carousel;p.fn.carousel=r,p.fn.carousel.Constructor=c,p.fn.carousel.noConflict=function(){return p.fn.carousel=t,this};var e=function(t){var e=p(this),i=e.attr("href");i&&(i=i.replace(/.*(?=#[^\s]+$)/,""));var o=e.attr("data-target")||i,n=p(document).find(o);if(n.hasClass("carousel")){var s=p.extend({},n.data(),e.data()),a=e.attr("data-slide-to");a&&(s.interval=!1),r.call(n,s),a&&n.data("bs.carousel").to(a),t.preventDefault()}};p(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),p(window).on("load",function(){p('[data-ride="carousel"]').each(function(){var t=p(this);r.call(t,t.data())})})}(jQuery),function(a){"use strict";var r=function(t,e){this.$element=a(t),this.options=a.extend({},r.DEFAULTS,e),this.$trigger=a('[data-toggle="collapse"][href="#'+t.id+'"],[data-toggle="collapse"][data-target="#'+t.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function n(t){var e,i=t.attr("data-target")||(e=t.attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(i)}function l(o){return this.each(function(){var t=a(this),e=t.data("bs.collapse"),i=a.extend({},r.DEFAULTS,t.data(),"object"==typeof o&&o);!e&&i.toggle&&/show|hide/.test(o)&&(i.toggle=!1),e||t.data("bs.collapse",e=new r(this,i)),"string"==typeof o&&e[o]()})}r.VERSION="3.4.1",r.TRANSITION_DURATION=350,r.DEFAULTS={toggle:!0},r.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},r.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var t,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(t=e.data("bs.collapse"))&&t.transitioning)){var i=a.Event("show.bs.collapse");if(this.$element.trigger(i),!i.isDefaultPrevented()){e&&e.length&&(l.call(e,"hide"),t||e.data("bs.collapse",null));var o=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[o](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var n=function(){this.$element.removeClass("collapsing").addClass("collapse in")[o](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return n.call(this);var s=a.camelCase(["scroll",o].join("-"));this.$element.one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(r.TRANSITION_DURATION)[o](this.$element[0][s])}}}},r.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var t=a.Event("hide.bs.collapse");if(this.$element.trigger(t),!t.isDefaultPrevented()){var e=this.dimension();this.$element[e](this.$element[e]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var i=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return i.call(this);this.$element[e](0).one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(r.TRANSITION_DURATION)}}},r.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},r.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(t,e){var i=a(e);this.addAriaAndCollapsedClass(n(i),i)},this)).end()},r.prototype.addAriaAndCollapsedClass=function(t,e){var i=t.hasClass("in");t.attr("aria-expanded",i),e.toggleClass("collapsed",!i).attr("aria-expanded",i)};var t=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=r,a.fn.collapse.noConflict=function(){return a.fn.collapse=t,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(t){var e=a(this);e.attr("data-target")||t.preventDefault();var i=n(e),o=i.data("bs.collapse")?"toggle":e.data();l.call(i,o)})}(jQuery),function(a){"use strict";var r='[data-toggle="dropdown"]',o=function(t){a(t).on("click.bs.dropdown",this.toggle)};function l(t){var e=t.attr("data-target");e||(e=(e=t.attr("href"))&&/#[A-Za-z]/.test(e)&&e.replace(/.*(?=#[^\s]*$)/,""));var i="#"!==e?a(document).find(e):null;return i&&i.length?i:t.parent()}function s(o){o&&3===o.which||(a(".dropdown-backdrop").remove(),a(r).each(function(){var t=a(this),e=l(t),i={relatedTarget:this};e.hasClass("open")&&(o&&"click"==o.type&&/input|textarea/i.test(o.target.tagName)&&a.contains(e[0],o.target)||(e.trigger(o=a.Event("hide.bs.dropdown",i)),o.isDefaultPrevented()||(t.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",i)))))}))}o.VERSION="3.4.1",o.prototype.toggle=function(t){var e=a(this);if(!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(s(),!o){"ontouchstart"in document.documentElement&&!i.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",s);var n={relatedTarget:this};if(i.trigger(t=a.Event("show.bs.dropdown",n)),t.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),i.toggleClass("open").trigger(a.Event("shown.bs.dropdown",n))}return!1}},o.prototype.keydown=function(t){if(/(38|40|27|32)/.test(t.which)&&!/input|textarea/i.test(t.target.tagName)){var e=a(this);if(t.preventDefault(),t.stopPropagation(),!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(!o&&27!=t.which||o&&27==t.which)return 27==t.which&&i.find(r).trigger("focus"),e.trigger("click");var n=i.find(".dropdown-menu li:not(.disabled):visible a");if(n.length){var s=n.index(t.target);38==t.which&&0<s&&s--,40==t.which&&s<n.length-1&&s++,~s||(s=0),n.eq(s).trigger("focus")}}}};var t=a.fn.dropdown;a.fn.dropdown=function e(i){return this.each(function(){var t=a(this),e=t.data("bs.dropdown");e||t.data("bs.dropdown",e=new o(this)),"string"==typeof i&&e[i].call(t)})},a.fn.dropdown.Constructor=o,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=t,this},a(document).on("click.bs.dropdown.data-api",s).on("click.bs.dropdown.data-api",".dropdown form",function(t){t.stopPropagation()}).on("click.bs.dropdown.data-api",r,o.prototype.toggle).on("keydown.bs.dropdown.data-api",r,o.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",o.prototype.keydown)}(jQuery),function(a){"use strict";var s=function(t,e){this.options=e,this.$body=a(document.body),this.$element=a(t),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.fixedContent=".navbar-fixed-top, .navbar-fixed-bottom",this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};function r(o,n){return this.each(function(){var t=a(this),e=t.data("bs.modal"),i=a.extend({},s.DEFAULTS,t.data(),"object"==typeof o&&o);e||t.data("bs.modal",e=new s(this,i)),"string"==typeof o?e[o](n):i.show&&e.show(n)})}s.VERSION="3.4.1",s.TRANSITION_DURATION=300,s.BACKDROP_TRANSITION_DURATION=150,s.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},s.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},s.prototype.show=function(i){var o=this,t=a.Event("show.bs.modal",{relatedTarget:i});this.$element.trigger(t),this.isShown||t.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(t){a(t.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var t=a.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),t&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:i});t?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(s.TRANSITION_DURATION):o.$element.trigger("focus").trigger(e)}))},s.prototype.hide=function(t){t&&t.preventDefault(),t=a.Event("hide.bs.modal"),this.$element.trigger(t),this.isShown&&!t.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(s.TRANSITION_DURATION):this.hideModal())},s.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(t){document===t.target||this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},s.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},s.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},s.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},s.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},s.prototype.backdrop=function(t){var e=this,i=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var o=a.support.transition&&i;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+i).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(t){this.ignoreBackdropClick?this.ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide())},this)),o&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!t)return;o?this.$backdrop.one("bsTransitionEnd",t).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):t()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var n=function(){e.removeBackdrop(),t&&t()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",n).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):n()}else t&&t()},s.prototype.handleUpdate=function(){this.adjustDialog()},s.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},s.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},s.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth<t,this.scrollbarWidth=this.measureScrollbar()},s.prototype.setScrollbar=function(){var t=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"";var n=this.scrollbarWidth;this.bodyIsOverflowing&&(this.$body.css("padding-right",t+n),a(this.fixedContent).each(function(t,e){var i=e.style.paddingRight,o=a(e).css("padding-right");a(e).data("padding-right",i).css("padding-right",parseFloat(o)+n+"px")}))},s.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad),a(this.fixedContent).each(function(t,e){var i=a(e).data("padding-right");a(e).removeData("padding-right"),e.style.paddingRight=i||""})},s.prototype.measureScrollbar=function(){var t=document.createElement("div");t.className="modal-scrollbar-measure",this.$body.append(t);var e=t.offsetWidth-t.clientWidth;return this.$body[0].removeChild(t),e};var t=a.fn.modal;a.fn.modal=r,a.fn.modal.Constructor=s,a.fn.modal.noConflict=function(){return a.fn.modal=t,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(t){var e=a(this),i=e.attr("href"),o=e.attr("data-target")||i&&i.replace(/.*(?=#[^\s]+$)/,""),n=a(document).find(o),s=n.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(i)&&i},n.data(),e.data());e.is("a")&&t.preventDefault(),n.one("show.bs.modal",function(t){t.isDefaultPrevented()||n.one("hidden.bs.modal",function(){e.is(":visible")&&e.trigger("focus")})}),r.call(n,s,this)})}(jQuery),function(g){"use strict";var o=["sanitize","whiteList","sanitizeFn"],a=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],t={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},r=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,l=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function u(t,e){var i=t.nodeName.toLowerCase();if(-1!==g.inArray(i,e))return-1===g.inArray(i,a)||Boolean(t.nodeValue.match(r)||t.nodeValue.match(l));for(var o=g(e).filter(function(t,e){return e instanceof RegExp}),n=0,s=o.length;n<s;n++)if(i.match(o[n]))return!0;return!1}function n(t,e,i){if(0===t.length)return t;if(i&&"function"==typeof i)return i(t);if(!document.implementation||!document.implementation.createHTMLDocument)return t;var o=document.implementation.createHTMLDocument("sanitization");o.body.innerHTML=t;for(var n=g.map(e,function(t,e){return e}),s=g(o.body).find("*"),a=0,r=s.length;a<r;a++){var l=s[a],h=l.nodeName.toLowerCase();if(-1!==g.inArray(h,n))for(var d=g.map(l.attributes,function(t){return t}),p=[].concat(e["*"]||[],e[h]||[]),c=0,f=d.length;c<f;c++)u(d[c],p)||l.removeAttribute(d[c].nodeName);else l.parentNode.removeChild(l)}return o.body.innerHTML}var m=function(t,e){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",t,e)};m.VERSION="3.4.1",m.TRANSITION_DURATION=150,m.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:t},m.prototype.init=function(t,e,i){if(this.enabled=!0,this.type=t,this.$element=g(e),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var o=this.options.trigger.split(" "),n=o.length;n--;){var s=o[n];if("click"==s)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=s){var a="hover"==s?"mouseenter":"focusin",r="hover"==s?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(r+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},m.prototype.getDefaults=function(){return m.DEFAULTS},m.prototype.getOptions=function(t){var e=this.$element.data();for(var i in e)e.hasOwnProperty(i)&&-1!==g.inArray(i,o)&&delete e[i];return(t=g.extend({},this.getDefaults(),e,t)).delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.sanitize&&(t.template=n(t.template,t.whiteList,t.sanitizeFn)),t},m.prototype.getDelegateOptions=function(){var i={},o=this.getDefaults();return this._options&&g.each(this._options,function(t,e){o[t]!=e&&(i[t]=e)}),i},m.prototype.enter=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusin"==t.type?"focus":"hover"]=!0),e.tip().hasClass("in")||"in"==e.hoverState)e.hoverState="in";else{if(clearTimeout(e.timeout),e.hoverState="in",!e.options.delay||!e.options.delay.show)return e.show();e.timeout=setTimeout(function(){"in"==e.hoverState&&e.show()},e.options.delay.show)}},m.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},m.prototype.leave=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusout"==t.type?"focus":"hover"]=!1),!e.isInStateTrue()){if(clearTimeout(e.timeout),e.hoverState="out",!e.options.delay||!e.options.delay.hide)return e.hide();e.timeout=setTimeout(function(){"out"==e.hoverState&&e.hide()},e.options.delay.hide)}},m.prototype.show=function(){var t=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var e=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!e)return;var i=this,o=this.tip(),n=this.getUID(this.type);this.setContent(),o.attr("id",n),this.$element.attr("aria-describedby",n),this.options.animation&&o.addClass("fade");var s="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,r=a.test(s);r&&(s=s.replace(a,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(s).data("bs."+this.type,this),this.options.container?o.appendTo(g(document).find(this.options.container)):o.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),h=o[0].offsetWidth,d=o[0].offsetHeight;if(r){var p=s,c=this.getPosition(this.$viewport);s="bottom"==s&&l.bottom+d>c.bottom?"top":"top"==s&&l.top-d<c.top?"bottom":"right"==s&&l.right+h>c.width?"left":"left"==s&&l.left-h<c.left?"right":s,o.removeClass(p).addClass(s)}var f=this.getCalculatedOffset(s,l,h,d);this.applyPlacement(f,s);var u=function(){var t=i.hoverState;i.$element.trigger("shown.bs."+i.type),i.hoverState=null,"out"==t&&i.leave(i)};g.support.transition&&this.$tip.hasClass("fade")?o.one("bsTransitionEnd",u).emulateTransitionEnd(m.TRANSITION_DURATION):u()}},m.prototype.applyPlacement=function(t,e){var i=this.tip(),o=i[0].offsetWidth,n=i[0].offsetHeight,s=parseInt(i.css("margin-top"),10),a=parseInt(i.css("margin-left"),10);isNaN(s)&&(s=0),isNaN(a)&&(a=0),t.top+=s,t.left+=a,g.offset.setOffset(i[0],g.extend({using:function(t){i.css({top:Math.round(t.top),left:Math.round(t.left)})}},t),0),i.addClass("in");var r=i[0].offsetWidth,l=i[0].offsetHeight;"top"==e&&l!=n&&(t.top=t.top+n-l);var h=this.getViewportAdjustedDelta(e,t,r,l);h.left?t.left+=h.left:t.top+=h.top;var d=/top|bottom/.test(e),p=d?2*h.left-o+r:2*h.top-n+l,c=d?"offsetWidth":"offsetHeight";i.offset(t),this.replaceArrow(p,i[0][c],d)},m.prototype.replaceArrow=function(t,e,i){this.arrow().css(i?"left":"top",50*(1-t/e)+"%").css(i?"top":"left","")},m.prototype.setContent=function(){var t=this.tip(),e=this.getTitle();this.options.html?(this.options.sanitize&&(e=n(e,this.options.whiteList,this.options.sanitizeFn)),t.find(".tooltip-inner").html(e)):t.find(".tooltip-inner").text(e),t.removeClass("fade in top bottom left right")},m.prototype.hide=function(t){var e=this,i=g(this.$tip),o=g.Event("hide.bs."+this.type);function n(){"in"!=e.hoverState&&i.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),t&&t()}if(this.$element.trigger(o),!o.isDefaultPrevented())return i.removeClass("in"),g.support.transition&&i.hasClass("fade")?i.one("bsTransitionEnd",n).emulateTransitionEnd(m.TRANSITION_DURATION):n(),this.hoverState=null,this},m.prototype.fixTitle=function(){var t=this.$element;(t.attr("title")||"string"!=typeof t.attr("data-original-title"))&&t.attr("data-original-title",t.attr("title")||"").attr("title","")},m.prototype.hasContent=function(){return this.getTitle()},m.prototype.getPosition=function(t){var e=(t=t||this.$element)[0],i="BODY"==e.tagName,o=e.getBoundingClientRect();null==o.width&&(o=g.extend({},o,{width:o.right-o.left,height:o.bottom-o.top}));var n=window.SVGElement&&e instanceof window.SVGElement,s=i?{top:0,left:0}:n?null:t.offset(),a={scroll:i?document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop()},r=i?{width:g(window).width(),height:g(window).height()}:null;return g.extend({},o,a,r,s)},m.prototype.getCalculatedOffset=function(t,e,i,o){return"bottom"==t?{top:e.top+e.height,left:e.left+e.width/2-i/2}:"top"==t?{top:e.top-o,left:e.left+e.width/2-i/2}:"left"==t?{top:e.top+e.height/2-o/2,left:e.left-i}:{top:e.top+e.height/2-o/2,left:e.left+e.width}},m.prototype.getViewportAdjustedDelta=function(t,e,i,o){var n={top:0,left:0};if(!this.$viewport)return n;var s=this.options.viewport&&this.options.viewport.padding||0,a=this.getPosition(this.$viewport);if(/right|left/.test(t)){var r=e.top-s-a.scroll,l=e.top+s-a.scroll+o;r<a.top?n.top=a.top-r:l>a.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;h<a.left?n.left=a.left-h:d>a.right&&(n.left=a.left+a.width-d)}return n},m.prototype.getTitle=function(){var t=this.$element,e=this.options;return t.attr("data-original-title")||("function"==typeof e.title?e.title.call(t[0]):e.title)},m.prototype.getUID=function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},m.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},m.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},m.prototype.enable=function(){this.enabled=!0},m.prototype.disable=function(){this.enabled=!1},m.prototype.toggleEnabled=function(){this.enabled=!this.enabled},m.prototype.toggle=function(t){var e=this;t&&((e=g(t.currentTarget).data("bs."+this.type))||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e))),t?(e.inState.click=!e.inState.click,e.isInStateTrue()?e.enter(e):e.leave(e)):e.tip().hasClass("in")?e.leave(e):e.enter(e)},m.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})},m.prototype.sanitizeHtml=function(t){return n(t,this.options.whiteList,this.options.sanitizeFn)};var e=g.fn.tooltip;g.fn.tooltip=function i(o){return this.each(function(){var t=g(this),e=t.data("bs.tooltip"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.tooltip",e=new m(this,i)),"string"==typeof o&&e[o]())})},g.fn.tooltip.Constructor=m,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=e,this}}(jQuery),function(n){"use strict";var s=function(t,e){this.init("popover",t,e)};if(!n.fn.tooltip)throw new Error("Popover requires tooltip.js");s.VERSION="3.4.1",s.DEFAULTS=n.extend({},n.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),((s.prototype=n.extend({},n.fn.tooltip.Constructor.prototype)).constructor=s).prototype.getDefaults=function(){return s.DEFAULTS},s.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();if(this.options.html){var o=typeof i;this.options.sanitize&&(e=this.sanitizeHtml(e),"string"===o&&(i=this.sanitizeHtml(i))),t.find(".popover-title").html(e),t.find(".popover-content").children().detach().end()["string"===o?"html":"append"](i)}else t.find(".popover-title").text(e),t.find(".popover-content").children().detach().end().text(i);t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},s.prototype.hasContent=function(){return this.getTitle()||this.getContent()},s.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},s.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var t=n.fn.popover;n.fn.popover=function e(o){return this.each(function(){var t=n(this),e=t.data("bs.popover"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.popover",e=new s(this,i)),"string"==typeof o&&e[o]())})},n.fn.popover.Constructor=s,n.fn.popover.noConflict=function(){return n.fn.popover=t,this}}(jQuery),function(s){"use strict";function n(t,e){this.$body=s(document.body),this.$scrollElement=s(t).is(document.body)?s(window):s(t),this.options=s.extend({},n.DEFAULTS,e),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",s.proxy(this.process,this)),this.refresh(),this.process()}function e(o){return this.each(function(){var t=s(this),e=t.data("bs.scrollspy"),i="object"==typeof o&&o;e||t.data("bs.scrollspy",e=new n(this,i)),"string"==typeof o&&e[o]()})}n.VERSION="3.4.1",n.DEFAULTS={offset:10},n.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},n.prototype.refresh=function(){var t=this,o="offset",n=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),s.isWindow(this.$scrollElement[0])||(o="position",n=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var t=s(this),e=t.data("target")||t.attr("href"),i=/^#./.test(e)&&s(e);return i&&i.length&&i.is(":visible")&&[[i[o]().top+n,e]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},n.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),o<=e)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e<n[0])return this.activeTarget=null,this.clear();for(t=n.length;t--;)a!=s[t]&&e>=n[t]&&(n[t+1]===undefined||e<n[t+1])&&this.activate(s[t])},n.prototype.activate=function(t){this.activeTarget=t,this.clear();var e=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',i=s(e).parents("li").addClass("active");i.parent(".dropdown-menu").length&&(i=i.closest("li.dropdown").addClass("active")),i.trigger("activate.bs.scrollspy")},n.prototype.clear=function(){s(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var t=s.fn.scrollspy;s.fn.scrollspy=e,s.fn.scrollspy.Constructor=n,s.fn.scrollspy.noConflict=function(){return s.fn.scrollspy=t,this},s(window).on("load.bs.scrollspy.data-api",function(){s('[data-spy="scroll"]').each(function(){var t=s(this);e.call(t,t.data())})})}(jQuery),function(r){"use strict";var a=function(t){this.element=r(t)};function e(i){return this.each(function(){var t=r(this),e=t.data("bs.tab");e||t.data("bs.tab",e=new a(this)),"string"==typeof i&&e[i]()})}a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.show=function(){var t=this.element,e=t.closest("ul:not(.dropdown-menu)"),i=t.data("target");if(i||(i=(i=t.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),!t.parent("li").hasClass("active")){var o=e.find(".active:last a"),n=r.Event("hide.bs.tab",{relatedTarget:t[0]}),s=r.Event("show.bs.tab",{relatedTarget:o[0]});if(o.trigger(n),t.trigger(s),!s.isDefaultPrevented()&&!n.isDefaultPrevented()){var a=r(document).find(i);this.activate(t.closest("li"),e),this.activate(a,a.parent(),function(){o.trigger({type:"hidden.bs.tab",relatedTarget:t[0]}),t.trigger({type:"shown.bs.tab",relatedTarget:o[0]})})}}},a.prototype.activate=function(t,e,i){var o=e.find("> .active"),n=i&&r.support.transition&&(o.length&&o.hasClass("fade")||!!e.find("> .fade").length);function s(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),t.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),n?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu").length&&t.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),i&&i()}o.length&&n?o.one("bsTransitionEnd",s).emulateTransitionEnd(a.TRANSITION_DURATION):s(),o.removeClass("in")};var t=r.fn.tab;r.fn.tab=e,r.fn.tab.Constructor=a,r.fn.tab.noConflict=function(){return r.fn.tab=t,this};var i=function(t){t.preventDefault(),e.call(r(this),"show")};r(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery),function(l){"use strict";var h=function(t,e){this.options=l.extend({},h.DEFAULTS,e);var i=this.options.target===h.DEFAULTS.target?l(this.options.target):l(document).find(this.options.target);this.$target=i.on("scroll.bs.affix.data-api",l.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",l.proxy(this.checkPositionWithEventLoop,this)),this.$element=l(t),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};function i(o){return this.each(function(){var t=l(this),e=t.data("bs.affix"),i="object"==typeof o&&o;e||t.data("bs.affix",e=new h(this,i)),"string"==typeof o&&e[o]()})}h.VERSION="3.4.1",h.RESET="affix affix-top affix-bottom",h.DEFAULTS={offset:0,target:window},h.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return n<i&&"top";if("bottom"==this.affixed)return null!=i?!(n+this.unpin<=s.top)&&"bottom":!(n+a<=t-o)&&"bottom";var r=null==this.affixed,l=r?n:s.top;return null!=i&&n<=i?"top":null!=o&&t-o<=l+(r?a:e)&&"bottom"},h.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(h.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},h.prototype.checkPositionWithEventLoop=function(){setTimeout(l.proxy(this.checkPosition,this),1)},h.prototype.checkPosition=function(){if(this.$element.is(":visible")){var t=this.$element.height(),e=this.options.offset,i=e.top,o=e.bottom,n=Math.max(l(document).height(),l(document.body).height());"object"!=typeof e&&(o=i=e),"function"==typeof i&&(i=e.top(this.$element)),"function"==typeof o&&(o=e.bottom(this.$element));var s=this.getState(n,t,i,o);if(this.affixed!=s){null!=this.unpin&&this.$element.css("top","");var a="affix"+(s?"-"+s:""),r=l.Event(a+".bs.affix");if(this.$element.trigger(r),r.isDefaultPrevented())return;this.affixed=s,this.unpin="bottom"==s?this.getPinnedOffset():null,this.$element.removeClass(h.RESET).addClass(a).trigger(a.replace("affix","affixed")+".bs.affix")}"bottom"==s&&this.$element.offset({top:n-t-o})}};var t=l.fn.affix;l.fn.affix=i,l.fn.affix.Constructor=h,l.fn.affix.noConflict=function(){return l.fn.affix=t,this},l(window).on("load",function(){l('[data-spy="affix"]').each(function(){var t=l(this),e=t.data();e.offset=e.offset||{},null!=e.offsetBottom&&(e.offset.bottom=e.offsetBottom),null!=e.offsetTop&&(e.offset.top=e.offsetTop),i.call(t,e)})})}(jQuery); \ No newline at end of file
diff --git a/bitbake/lib/toaster/toastergui/static/js/bootstrap.min.js b/bitbake/lib/toaster/toastergui/static/js/bootstrap.min.js
deleted file mode 100644
index c4a924160d..0000000000
--- a/bitbake/lib/toaster/toastergui/static/js/bootstrap.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
1/*!
2 * Bootstrap v3.3.6 (http://getbootstrap.com)
3 * Copyright 2011-2016 Twitter, Inc.
4 * Licensed under the MIT license
5 */
6if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),
7d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file
diff --git a/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.js b/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.js
new file mode 100644
index 0000000000..7f37b5d991
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.js
@@ -0,0 +1,2 @@
1/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
2!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||v(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:"jQuery"+(t+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==i.call(e))&&(!(t=r(e))||"function"==typeof(n=ue.call(t,"constructor")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},text:function(e){var t,n="",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||"HTML")},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(c(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:le}),"function"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge="[\\x20\\t\\r\\n\\f]",ve=new RegExp("^"+ge+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ge+"+$","g");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function p(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e}ce.escapeSelector=function(e){return(e+"").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",t="(?:\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",p="\\["+ge+"*("+t+")(?:"+ge+"*([*^$|!~]?=)"+ge+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+t+"))|)"+ge+"*\\]",g=":("+t+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+p+")*)|.*)\\)|)",v=new RegExp(ge+"+","g"),y=new RegExp("^"+ge+"*,"+ge+"*"),m=new RegExp("^"+ge+"*([>+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="<a id='"+S+"' href='' disabled='disabled'></a><select id='"+S+"-\r\\' disabled='disabled'><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0<I(t,T,null,[e]).length},I.contains=function(e,t){return(e.ownerDocument||e)!=T&&V(e),ce.contains(e,t)},I.attr=function(e,t){(e.ownerDocument||e)!=T&&V(e);var n=b.attrHandle[t.toLowerCase()],r=n&&ue.call(b.attrHandle,t.toLowerCase())?n(e,t,!C):void 0;return void 0!==r?r:e.getAttribute(t)},I.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ce.uniqueSort=function(e){var t,n=[],r=0,i=0;if(a=!le.sortStable,o=!le.sortStable&&ae.call(e,0),de.call(e,l),a){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)he.call(e,n[r],1)}return o=null,e},ce.fn.uniqueSort=function(){return this.pushStack(ce.uniqueSort(ae.apply(this)))},(b=ce.expr={cacheLength:50,createPseudo:F,match:D,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(v," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(d,e,t,h,g){var v="nth"!==d.slice(0,3),y="last"!==d.slice(-4),m="of-type"===e;return 1===h&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u=v!==y?"nextSibling":"previousSibling",l=e.parentNode,c=m&&e.nodeName.toLowerCase(),f=!n&&!m,p=!1;if(l){if(v){while(u){o=e;while(o=o[u])if(m?fe(o,c):1===o.nodeType)return!1;s=u="only"===d&&!s&&"nextSibling"}return!0}if(s=[y?l.firstChild:l.lastChild],y&&f){p=(a=(r=(i=l[S]||(l[S]={}))[d]||[])[0]===E&&r[1])&&r[2],o=a&&l.childNodes[a];while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if(1===o.nodeType&&++p&&o===e){i[d]=[E,a,p];break}}else if(f&&(p=a=(r=(i=e[S]||(e[S]={}))[d]||[])[0]===E&&r[1]),!1===p)while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if((m?fe(o,c):1===o.nodeType)&&++p&&(f&&((i=o[S]||(o[S]={}))[d]=[E,p]),o===e))break;return(p-=g)===h||p%h==0&&0<=p/h}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||I.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?F(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=se.call(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:F(function(e){var r=[],i=[],s=ne(e.replace(ve,"$1"));return s[S]?F(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:F(function(t){return function(e){return 0<I(t,e).length}}),contains:F(function(t){return t=t.replace(O,P),function(e){return-1<(e.textContent||ce.text(e)).indexOf(t)}}),lang:F(function(n){return A.test(n||"")||I.error("unsupported lang: "+n),n=n.replace(O,P).toLowerCase(),function(e){var t;do{if(t=C?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=ie.location&&ie.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===r},focus:function(e){return e===function(){try{return T.activeElement}catch(e){}}()&&T.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:z(!1),disabled:z(!0),checked:function(e){return fe(e,"input")&&!!e.checked||fe(e,"option")&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return q.test(e.nodeName)},input:function(e){return N.test(e.nodeName)},button:function(e){return fe(e,"input")&&"button"===e.type||fe(e,"button")},text:function(e){var t;return fe(e,"input")&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:X(function(){return[0]}),last:X(function(e,t){return[t-1]}),eq:X(function(e,t,n){return[n<0?n+t:n]}),even:X(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:X(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:X(function(e,t,n){var r;for(r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:X(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=B(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=_(e);function G(){}function Y(e,t){var n,r,i,o,a,s,u,l=c[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=y.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=m.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ve," ")}),a=a.slice(n.length)),b.filter)!(r=D[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?I.error(e):c(e,s).slice(0)}function Q(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function J(a,e,t){var s=e.dir,u=e.next,l=u||s,c=t&&"parentNode"===l,f=n++;return e.first?function(e,t,n){while(e=e[s])if(1===e.nodeType||c)return a(e,t,n);return!1}:function(e,t,n){var r,i,o=[E,f];if(n){while(e=e[s])if((1===e.nodeType||c)&&a(e,t,n))return!0}else while(e=e[s])if(1===e.nodeType||c)if(i=e[S]||(e[S]={}),u&&fe(e,u))e=e[s]||e;else{if((r=i[l])&&r[0]===E&&r[1]===f)return o[2]=r[2];if((i[l]=o)[2]=a(e,t,n))return!0}return!1}}function K(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Z(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function ee(d,h,g,v,y,e){return v&&!v[S]&&(v=ee(v)),y&&!y[S]&&(y=ee(y,e)),F(function(e,t,n,r){var i,o,a,s,u=[],l=[],c=t.length,f=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)I(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),p=!d||!e&&h?f:Z(f,u,d,n,r);if(g?g(p,s=y||(e?d:c||v)?[]:t,n,r):s=p,v){i=Z(s,l),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(s[l[o]]=!(p[l[o]]=a))}if(e){if(y||d){if(y){i=[],o=s.length;while(o--)(a=s[o])&&i.push(p[o]=a);y(null,s=[],i,r)}o=s.length;while(o--)(a=s[o])&&-1<(i=y?se.call(e,a):u[o])&&(e[i]=!(t[i]=a))}}else s=Z(s===t?s.splice(c,s.length):s),y?y(null,t,s,r):k.apply(t,s)})}function te(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=J(function(e){return e===i},a,!0),l=J(function(e){return-1<se.call(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!=w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[J(K(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return ee(1<s&&K(c),1<s&&Q(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(ve,"$1"),t,s<n&&te(e.slice(s,n)),n<r&&te(e=e.slice(n)),n<r&&Q(e))}c.push(t)}return K(c)}function ne(e,t){var n,v,y,m,x,r,i=[],o=[],a=u[e+" "];if(!a){t||(t=Y(e)),n=t.length;while(n--)(a=te(t[n]))[S]?i.push(a):o.push(a);(a=u(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=E+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==T||(V(o),n=!C);while(s=v[a++])if(s(o,t||T,n)){k.call(r,o);break}i&&(E=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=pe.call(r));f=Z(f)}k.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&ce.uniqueSort(r)}return i&&(E=h,w=p),c},m?F(r):r))).selector=e}return a}function re(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&Y(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&C&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(O,P),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=D.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(O,P),H.test(o[0].type)&&U(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&Q(o)))return k.apply(n,r),n;break}}}return(l||ne(e,c))(r,t,!C,n,!t||H.test(e)&&U(t.parentNode)||t),n}G.prototype=b.filters=b.pseudos,b.setFilters=new G,le.sortStable=S.split("").sort(l).join("")===S,V(),le.sortDetached=$(function(e){return 1&e.compareDocumentPosition(T.createElement("fieldset"))}),ce.find=I,ce.expr[":"]=ce.expr.pseudos,ce.unique=ce.uniqueSort,I.compile=ne,I.select=re,I.setDocument=V,I.tokenize=Y,I.escape=ce.escapeSelector,I.getText=ce.text,I.isXML=ce.isXMLDoc,I.selectors=ce.expr,I.support=ce.support,I.uniqueSort=ce.uniqueSort}();var d=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&ce(e).is(n))break;r.push(e)}return r},h=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},b=ce.expr.match.needsContext,w=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1<se.call(n,e)!==r}):ce.filter(n,e,r)}ce.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?ce.find.matchesSelector(r,e)?[r]:[]:ce.find.matches(e,ce.grep(t,function(e){return 1===e.nodeType}))},ce.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(ce(e).filter(function(){for(t=0;t<r;t++)if(ce.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)ce.find(e,i[t],n);return 1<r?ce.uniqueSort(n):n},filter:function(e){return this.pushStack(T(this,e||[],!1))},not:function(e){return this.pushStack(T(this,e||[],!0))},is:function(e){return!!T(this,"string"==typeof e&&b.test(e)?ce(e):e||[],!1).length}});var k,S=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(ce.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&ce(e);if(!b.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&ce.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?ce.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?se.call(ce(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ce.uniqueSort(ce.merge(this.get(),ce(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ce.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return d(e,"parentNode")},parentsUntil:function(e,t,n){return d(e,"parentNode",n)},next:function(e){return A(e,"nextSibling")},prev:function(e){return A(e,"previousSibling")},nextAll:function(e){return d(e,"nextSibling")},prevAll:function(e){return d(e,"previousSibling")},nextUntil:function(e,t,n){return d(e,"nextSibling",n)},prevUntil:function(e,t,n){return d(e,"previousSibling",n)},siblings:function(e){return h((e.parentNode||{}).firstChild,e)},children:function(e){return h(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(fe(e,"template")&&(e=e.content||e),ce.merge([],e.childNodes))}},function(r,i){ce.fn[r]=function(e,t){var n=ce.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=ce.filter(t,n)),1<this.length&&(j[r]||ce.uniqueSort(n),E.test(r)&&n.reverse()),this.pushStack(n)}});var D=/[^\x20\t\r\n\f]+/g;function N(e){return e}function q(e){throw e}function L(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}ce.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},ce.each(e.match(D)||[],function(e,t){n[t]=!0}),n):ce.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){ce.each(e,function(e,t){v(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==x(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return ce.each(arguments,function(e,t){var n;while(-1<(n=ce.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<ce.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},ce.extend({Deferred:function(e){var o=[["notify","progress",ce.Callbacks("memory"),ce.Callbacks("memory"),2],["resolve","done",ce.Callbacks("once memory"),ce.Callbacks("once memory"),0,"resolved"],["reject","fail",ce.Callbacks("once memory"),ce.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return ce.Deferred(function(r){ce.each(o,function(e,t){var n=v(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&v(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,v(t)?s?t.call(e,l(u,o,N,s),l(u,o,q,s)):(u++,t.call(e,l(u,o,N,s),l(u,o,q,s),l(u,o,N,o.notifyWith))):(a!==N&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){ce.Deferred.exceptionHook&&ce.Deferred.exceptionHook(e,t.error),u<=i+1&&(a!==q&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(ce.Deferred.getErrorHook?t.error=ce.Deferred.getErrorHook():ce.Deferred.getStackHook&&(t.error=ce.Deferred.getStackHook()),ie.setTimeout(t))}}return ce.Deferred(function(e){o[0][3].add(l(0,e,v(r)?r:N,e.notifyWith)),o[1][3].add(l(0,e,v(t)?t:N)),o[2][3].add(l(0,e,v(n)?n:q))}).promise()},promise:function(e){return null!=e?ce.extend(e,a):a}},s={};return ce.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=ae.call(arguments),o=ce.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?ae.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(L(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||v(i[t]&&i[t].then)))return o.then();while(t--)L(i[t],a(t),o.reject);return o.promise()}});var H=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ce.Deferred.exceptionHook=function(e,t){ie.console&&ie.console.warn&&e&&H.test(e.name)&&ie.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},ce.readyException=function(e){ie.setTimeout(function(){throw e})};var O=ce.Deferred();function P(){C.removeEventListener("DOMContentLoaded",P),ie.removeEventListener("load",P),ce.ready()}ce.fn.ready=function(e){return O.then(e)["catch"](function(e){ce.readyException(e)}),this},ce.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ce.readyWait:ce.isReady)||(ce.isReady=!0)!==e&&0<--ce.readyWait||O.resolveWith(C,[ce])}}),ce.ready.then=O.then,"complete"===C.readyState||"loading"!==C.readyState&&!C.documentElement.doScroll?ie.setTimeout(ce.ready):(C.addEventListener("DOMContentLoaded",P),ie.addEventListener("load",P));var M=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n))for(s in i=!0,n)M(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(ce(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},R=/^-ms-/,I=/-([a-z])/g;function W(e,t){return t.toUpperCase()}function F(e){return e.replace(R,"ms-").replace(I,W)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function B(){this.expando=ce.expando+B.uid++}B.uid=1,B.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[F(t)]=n;else for(r in t)i[F(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][F(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(F):(t=F(t))in r?[t]:t.match(D)||[]).length;while(n--)delete r[t[n]]}(void 0===t||ce.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!ce.isEmptyObject(t)}};var _=new B,z=new B,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,U=/[A-Z]/g;function V(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(U,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:X.test(i)?JSON.parse(i):i)}catch(e){}z.set(e,t,n)}else n=void 0;return n}ce.extend({hasData:function(e){return z.hasData(e)||_.hasData(e)},data:function(e,t,n){return z.access(e,t,n)},removeData:function(e,t){z.remove(e,t)},_data:function(e,t,n){return _.access(e,t,n)},_removeData:function(e,t){_.remove(e,t)}}),ce.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=z.get(o),1===o.nodeType&&!_.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=F(r.slice(5)),V(o,r,i[r]));_.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){z.set(this,n)}):M(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=z.get(o,n))?t:void 0!==(t=V(o,n))?t:void 0;this.each(function(){z.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){z.remove(this,e)})}}),ce.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=_.get(e,t),n&&(!r||Array.isArray(n)?r=_.access(e,t,ce.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=ce.queue(e,t),r=n.length,i=n.shift(),o=ce._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){ce.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return _.get(e,n)||_.access(e,n,{empty:ce.Callbacks("once memory").add(function(){_.remove(e,[t+"queue",n])})})}}),ce.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?ce.queue(this[0],t):void 0===n?this:this.each(function(){var e=ce.queue(this,t,n);ce._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&ce.dequeue(this,t)})},dequeue:function(e){return this.each(function(){ce.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=ce.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=_.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var G=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,Y=new RegExp("^(?:([+-])=|)("+G+")([a-z%]*)$","i"),Q=["Top","Right","Bottom","Left"],J=C.documentElement,K=function(e){return ce.contains(e.ownerDocument,e)},Z={composed:!0};J.getRootNode&&(K=function(e){return ce.contains(e.ownerDocument,e)||e.getRootNode(Z)===e.ownerDocument});var ee=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&K(e)&&"none"===ce.css(e,"display")};function te(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return ce.css(e,t,"")},u=s(),l=n&&n[3]||(ce.cssNumber[t]?"":"px"),c=e.nodeType&&(ce.cssNumber[t]||"px"!==l&&+u)&&Y.exec(ce.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)ce.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,ce.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ne={};function re(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=_.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ee(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ne[s])||(o=a.body.appendChild(a.createElement(s)),u=ce.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ne[s]=u)))):"none"!==n&&(l[c]="none",_.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}ce.fn.extend({show:function(){return re(this,!0)},hide:function(){return re(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ee(this)?ce(this).show():ce(this).hide()})}});var xe,be,we=/^(?:checkbox|radio)$/i,Te=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="<textarea>x</textarea>",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="<option></option>",le.option=!!xe.lastChild;var ke={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n<r;n++)_.set(e[n],"globalEval",!t||_.get(t[n],"globalEval"))}ke.tbody=ke.tfoot=ke.colgroup=ke.caption=ke.thead,ke.th=ke.td,le.option||(ke.optgroup=ke.option=[1,"<select multiple='multiple'>","</select>"]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===x(o))ce.merge(p,o.nodeType?[o]:o);else if(je.test(o)){a=a||f.appendChild(t.createElement("div")),s=(Te.exec(o)||["",""])[1].toLowerCase(),u=ke[s]||ke._default,a.innerHTML=u[1]+ce.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;ce.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<ce.inArray(o,r))i&&i.push(o);else if(l=K(o),a=Se(f.appendChild(o),"script"),l&&Ee(a),n){c=0;while(o=a[c++])Ce.test(o.type||"")&&n.push(o)}return f}var De=/^([^.]*)(?:\.(.+)|)/;function Ne(){return!0}function qe(){return!1}function Le(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Le(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=qe;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return ce().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=ce.guid++)),e.each(function(){ce.event.add(this,t,i,r,n)})}function He(e,r,t){t?(_.set(e,r,!1),ce.event.add(e,r,{namespace:!1,handler:function(e){var t,n=_.get(this,r);if(1&e.isTrigger&&this[r]){if(n)(ce.event.special[r]||{}).delegateType&&e.stopPropagation();else if(n=ae.call(arguments),_.set(this,r,n),this[r](),t=_.get(this,r),_.set(this,r,!1),n!==t)return e.stopImmediatePropagation(),e.preventDefault(),t}else n&&(_.set(this,r,ce.event.trigger(n[0],n.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ne)}})):void 0===_.get(e,r)&&ce.event.add(e,r,Ne)}ce.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.get(t);if($(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&ce.find.matchesSelector(J,i),n.guid||(n.guid=ce.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof ce&&ce.event.triggered!==e.type?ce.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(D)||[""]).length;while(l--)d=g=(s=De.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=ce.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ce.event.special[d]||{},c=ce.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ce.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),ce.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.hasData(e)&&_.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(D)||[""]).length;while(l--)if(d=g=(s=De.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=ce.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||ce.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ce.event.remove(e,d+t[l],n,r,!0);ce.isEmptyObject(u)&&_.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=ce.event.fix(e),l=(_.get(this,"events")||Object.create(null))[u.type]||[],c=ce.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=ce.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((ce.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<ce(i,this).index(l):ce.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(ce.Event.prototype,t,{enumerable:!0,configurable:!0,get:v(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[ce.expando]?e:new ce.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click",!0),!1},trigger:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click"),!0},_default:function(e){var t=e.target;return we.test(t.type)&&t.click&&fe(t,"input")&&_.get(t,"click")||fe(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},ce.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},ce.Event=function(e,t){if(!(this instanceof ce.Event))return new ce.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ne:qe,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&ce.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[ce.expando]=!0},ce.Event.prototype={constructor:ce.Event,isDefaultPrevented:qe,isPropagationStopped:qe,isImmediatePropagationStopped:qe,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ne,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ne,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ne,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},ce.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},ce.event.addProp),ce.each({focus:"focusin",blur:"focusout"},function(r,i){function o(e){if(C.documentMode){var t=_.get(this,"handle"),n=ce.event.fix(e);n.type="focusin"===e.type?"focus":"blur",n.isSimulated=!0,t(e),n.target===n.currentTarget&&t(n)}else ce.event.simulate(i,e.target,ce.event.fix(e))}ce.event.special[r]={setup:function(){var e;if(He(this,r,!0),!C.documentMode)return!1;(e=_.get(this,i))||this.addEventListener(i,o),_.set(this,i,(e||0)+1)},trigger:function(){return He(this,r),!0},teardown:function(){var e;if(!C.documentMode)return!1;(e=_.get(this,i)-1)?_.set(this,i,e):(this.removeEventListener(i,o),_.remove(this,i))},_default:function(e){return _.get(e.target,r)},delegateType:i},ce.event.special[i]={setup:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i);n||(C.documentMode?this.addEventListener(i,o):e.addEventListener(r,o,!0)),_.set(t,i,(n||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i)-1;n?_.set(t,i,n):(C.documentMode?this.removeEventListener(i,o):e.removeEventListener(r,o,!0),_.remove(t,i))}}}),ce.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){ce.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||ce.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),ce.fn.extend({on:function(e,t,n,r){return Le(this,e,t,n,r)},one:function(e,t,n,r){return Le(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,ce(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=qe),this.each(function(){ce.event.remove(this,e,n,t)})}});var Oe=/<script|<style|<link/i,Pe=/checked\s*(?:[^=]|=\s*.checked.)/i,Me=/^\s*<!\[CDATA\[|\]\]>\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)ce.event.add(t,i,s[i][n]);z.hasData(e)&&(o=z.access(e),a=ce.extend({},o),z.set(t,a))}}function $e(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=v(d);if(h||1<f&&"string"==typeof d&&!le.checkClone&&Pe.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),$e(t,r,i,o)});if(f&&(t=(e=Ae(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=ce.map(Se(e,"script"),Ie)).length;c<f;c++)u=e,c!==p&&(u=ce.clone(u,!0,!0),s&&ce.merge(a,Se(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,ce.map(a,We),c=0;c<s;c++)u=a[c],Ce.test(u.type||"")&&!_.access(u,"globalEval")&&ce.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?ce._evalUrl&&!u.noModule&&ce._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):m(u.textContent.replace(Me,""),u,l))}return n}function Be(e,t,n){for(var r,i=t?ce.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||ce.cleanData(Se(r)),r.parentNode&&(n&&K(r)&&Ee(Se(r,"script")),r.parentNode.removeChild(r));return e}ce.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=K(e);if(!(le.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ce.isXMLDoc(e)))for(a=Se(c),r=0,i=(o=Se(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&we.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||Se(e),a=a||Se(c),r=0,i=o.length;r<i;r++)Fe(o[r],a[r]);else Fe(e,c);return 0<(a=Se(c,"script")).length&&Ee(a,!f&&Se(e,"script")),c},cleanData:function(e){for(var t,n,r,i=ce.event.special,o=0;void 0!==(n=e[o]);o++)if($(n)){if(t=n[_.expando]){if(t.events)for(r in t.events)i[r]?ce.event.remove(n,r):ce.removeEvent(n,r,t.handle);n[_.expando]=void 0}n[z.expando]&&(n[z.expando]=void 0)}}}),ce.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return M(this,function(e){return void 0===e?ce.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return $e(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Re(this,e).appendChild(e)})},prepend:function(){return $e(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Re(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(ce.cleanData(Se(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ce.clone(this,e,t)})},html:function(e){return M(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Oe.test(e)&&!ke[(Te.exec(e)||["",""])[1].toLowerCase()]){e=ce.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(ce.cleanData(Se(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return $e(this,arguments,function(e){var t=this.parentNode;ce.inArray(this,n)<0&&(ce.cleanData(Se(this)),t&&t.replaceChild(e,this))},n)}}),ce.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){ce.fn[e]=function(e){for(var t,n=[],r=ce(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),ce(r[o])[a](t),s.apply(n,t.get());return this.pushStack(n)}});var _e=new RegExp("^("+G+")(?!px)[a-z%]+$","i"),ze=/^--/,Xe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=ie),t.getComputedStyle(e)},Ue=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ve=new RegExp(Q.join("|"),"i");function Ge(e,t,n){var r,i,o,a,s=ze.test(t),u=e.style;return(n=n||Xe(e))&&(a=n.getPropertyValue(t)||n[t],s&&a&&(a=a.replace(ve,"$1")||void 0),""!==a||K(e)||(a=ce.style(e,t)),!le.pixelBoxStyles()&&_e.test(a)&&Ve.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+"":a}function Ye(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",J.appendChild(u).appendChild(l);var e=ie.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),J.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=C.createElement("div"),l=C.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",le.clearCloneStyle="content-box"===l.style.backgroundClip,ce.extend(le,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=C.createElement("table"),t=C.createElement("tr"),n=C.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="box-sizing:content-box;border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",J.appendChild(e).appendChild(t).appendChild(n),r=ie.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,J.removeChild(e)),a}}))}();var Qe=["Webkit","Moz","ms"],Je=C.createElement("div").style,Ke={};function Ze(e){var t=ce.cssProps[e]||Ke[e];return t||(e in Je?e:Ke[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Qe.length;while(n--)if((e=Qe[n]+t)in Je)return e}(e)||e)}var et=/^(none|table(?!-c[ea]).+)/,tt={position:"absolute",visibility:"hidden",display:"block"},nt={letterSpacing:"0",fontWeight:"400"};function rt(e,t,n){var r=Y.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function it(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0,l=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(l+=ce.css(e,n+Q[a],!0,i)),r?("content"===n&&(u-=ce.css(e,"padding"+Q[a],!0,i)),"margin"!==n&&(u-=ce.css(e,"border"+Q[a]+"Width",!0,i))):(u+=ce.css(e,"padding"+Q[a],!0,i),"padding"!==n?u+=ce.css(e,"border"+Q[a]+"Width",!0,i):s+=ce.css(e,"border"+Q[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u+l}function ot(e,t,n){var r=Xe(e),i=(!le.boxSizingReliable()||n)&&"border-box"===ce.css(e,"boxSizing",!1,r),o=i,a=Ge(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(_e.test(a)){if(!n)return a;a="auto"}return(!le.boxSizingReliable()&&i||!le.reliableTrDimensions()&&fe(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===ce.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===ce.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+it(e,t,n||(i?"border":"content"),o,r,a)+"px"}function at(e,t,n,r,i){return new at.prototype.init(e,t,n,r,i)}ce.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=F(t),u=ze.test(t),l=e.style;if(u||(t=Ze(s)),a=ce.cssHooks[t]||ce.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=Y.exec(n))&&i[1]&&(n=te(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(ce.cssNumber[s]?"":"px")),le.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=F(t);return ze.test(t)||(t=Ze(s)),(a=ce.cssHooks[t]||ce.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ge(e,t,r)),"normal"===i&&t in nt&&(i=nt[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),ce.each(["height","width"],function(e,u){ce.cssHooks[u]={get:function(e,t,n){if(t)return!et.test(ce.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?ot(e,u,n):Ue(e,tt,function(){return ot(e,u,n)})},set:function(e,t,n){var r,i=Xe(e),o=!le.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===ce.css(e,"boxSizing",!1,i),s=n?it(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-it(e,u,"border",!1,i)-.5)),s&&(r=Y.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=ce.css(e,u)),rt(0,t,s)}}}),ce.cssHooks.marginLeft=Ye(le.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,"marginLeft"))||e.getBoundingClientRect().left-Ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),ce.each({margin:"",padding:"",border:"Width"},function(i,o){ce.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+Q[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(ce.cssHooks[i+o].set=rt)}),ce.fn.extend({css:function(e,t){return M(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Xe(e),i=t.length;a<i;a++)o[t[a]]=ce.css(e,t[a],!1,r);return o}return void 0!==n?ce.style(e,t,n):ce.css(e,t)},e,t,1<arguments.length)}}),((ce.Tween=at).prototype={constructor:at,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ce.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ce.cssNumber[n]?"":"px")},cur:function(){var e=at.propHooks[this.prop];return e&&e.get?e.get(this):at.propHooks._default.get(this)},run:function(e){var t,n=at.propHooks[this.prop];return this.options.duration?this.pos=t=ce.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):at.propHooks._default.set(this),this}}).init.prototype=at.prototype,(at.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=ce.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){ce.fx.step[e.prop]?ce.fx.step[e.prop](e):1!==e.elem.nodeType||!ce.cssHooks[e.prop]&&null==e.elem.style[Ze(e.prop)]?e.elem[e.prop]=e.now:ce.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=at.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ce.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ce.fx=at.prototype.init,ce.fx.step={};var st,ut,lt,ct,ft=/^(?:toggle|show|hide)$/,pt=/queueHooks$/;function dt(){ut&&(!1===C.hidden&&ie.requestAnimationFrame?ie.requestAnimationFrame(dt):ie.setTimeout(dt,ce.fx.interval),ce.fx.tick())}function ht(){return ie.setTimeout(function(){st=void 0}),st=Date.now()}function gt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=Q[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function vt(e,t,n){for(var r,i=(yt.tweeners[t]||[]).concat(yt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function yt(o,e,t){var n,a,r=0,i=yt.prefilters.length,s=ce.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=st||ht(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:ce.extend({},e),opts:ce.extend(!0,{specialEasing:{},easing:ce.easing._default},t),originalProperties:e,originalOptions:t,startTime:st||ht(),duration:t.duration,tweens:[],createTween:function(e,t){var n=ce.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=F(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=ce.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=yt.prefilters[r].call(l,o,c,l.opts))return v(n.stop)&&(ce._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return ce.map(c,vt,l),v(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),ce.fx.timer(ce.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}ce.Animation=ce.extend(yt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return te(n.elem,e,Y.exec(t),n),n}]},tweener:function(e,t){v(e)?(t=e,e=["*"]):e=e.match(D);for(var n,r=0,i=e.length;r<i;r++)n=e[r],yt.tweeners[n]=yt.tweeners[n]||[],yt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ee(e),v=_.get(e,"fxshow");for(r in n.queue||(null==(a=ce._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,ce.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ft.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||ce.style(e,r)}if((u=!ce.isEmptyObject(t))||!ce.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=_.get(e,"display")),"none"===(c=ce.css(e,"display"))&&(l?c=l:(re([e],!0),l=e.style.display||l,c=ce.css(e,"display"),re([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===ce.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=_.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&re([e],!0),p.done(function(){for(r in g||re([e]),_.remove(e,"fxshow"),d)ce.style(e,r,d[r])})),u=vt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?yt.prefilters.unshift(e):yt.prefilters.push(e)}}),ce.speed=function(e,t,n){var r=e&&"object"==typeof e?ce.extend({},e):{complete:n||!n&&t||v(e)&&e,duration:e,easing:n&&t||t&&!v(t)&&t};return ce.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in ce.fx.speeds?r.duration=ce.fx.speeds[r.duration]:r.duration=ce.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){v(r.old)&&r.old.call(this),r.queue&&ce.dequeue(this,r.queue)},r},ce.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ee).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=ce.isEmptyObject(t),o=ce.speed(e,n,r),a=function(){var e=yt(this,ce.extend({},t),o);(i||_.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=ce.timers,r=_.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&pt.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||ce.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=_.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=ce.timers,o=n?n.length:0;for(t.finish=!0,ce.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),ce.each(["toggle","show","hide"],function(e,r){var i=ce.fn[r];ce.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(gt(r,!0),e,t,n)}}),ce.each({slideDown:gt("show"),slideUp:gt("hide"),slideToggle:gt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){ce.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),ce.timers=[],ce.fx.tick=function(){var e,t=0,n=ce.timers;for(st=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||ce.fx.stop(),st=void 0},ce.fx.timer=function(e){ce.timers.push(e),ce.fx.start()},ce.fx.interval=13,ce.fx.start=function(){ut||(ut=!0,dt())},ce.fx.stop=function(){ut=null},ce.fx.speeds={slow:600,fast:200,_default:400},ce.fn.delay=function(r,e){return r=ce.fx&&ce.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=ie.setTimeout(e,r);t.stop=function(){ie.clearTimeout(n)}})},lt=C.createElement("input"),ct=C.createElement("select").appendChild(C.createElement("option")),lt.type="checkbox",le.checkOn=""!==lt.value,le.optSelected=ct.selected,(lt=C.createElement("input")).value="t",lt.type="radio",le.radioValue="t"===lt.value;var mt,xt=ce.expr.attrHandle;ce.fn.extend({attr:function(e,t){return M(this,ce.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){ce.removeAttr(this,e)})}}),ce.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?ce.prop(e,t,n):(1===o&&ce.isXMLDoc(e)||(i=ce.attrHooks[t.toLowerCase()]||(ce.expr.match.bool.test(t)?mt:void 0)),void 0!==n?null===n?void ce.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=ce.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!le.radioValue&&"radio"===t&&fe(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(D);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),mt={set:function(e,t,n){return!1===t?ce.removeAttr(e,n):e.setAttribute(n,n),n}},ce.each(ce.expr.match.bool.source.match(/\w+/g),function(e,t){var a=xt[t]||ce.find.attr;xt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=xt[o],xt[o]=r,r=null!=a(e,t,n)?o:null,xt[o]=i),r}});var bt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;function Tt(e){return(e.match(D)||[]).join(" ")}function Ct(e){return e.getAttribute&&e.getAttribute("class")||""}function kt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(D)||[]}ce.fn.extend({prop:function(e,t){return M(this,ce.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[ce.propFix[e]||e]})}}),ce.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ce.isXMLDoc(e)||(t=ce.propFix[t]||t,i=ce.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=ce.find.attr(e,"tabindex");return t?parseInt(t,10):bt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),le.optSelected||(ce.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),ce.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ce.propFix[this.toLowerCase()]=this}),ce.fn.extend({addClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).addClass(t.call(this,e,Ct(this)))}):(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++)i=e[o],n.indexOf(" "+i+" ")<0&&(n+=i+" ");a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).removeClass(t.call(this,e,Ct(this)))}):arguments.length?(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(" "+i+" "))n=n.replace(" "+i+" "," ")}a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this:this.attr("class","")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s="string"===a||Array.isArray(t);return v(t)?this.each(function(e){ce(this).toggleClass(t.call(this,e,Ct(this),n),n)}):"boolean"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=kt(t),this.each(function(){if(s)for(o=ce(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&"boolean"!==a||((r=Ct(this))&&_.set(this,"__className__",r),this.setAttribute&&this.setAttribute("class",r||!1===t?"":_.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+Tt(Ct(n))+" ").indexOf(t))return!0;return!1}});var St=/\r/g;ce.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=v(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,ce(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=ce.map(t,function(e){return null==e?"":e+""})),(r=ce.valHooks[this.type]||ce.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=ce.valHooks[t.type]||ce.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(St,""):null==e?"":e:void 0}}),ce.extend({valHooks:{option:{get:function(e){var t=ce.find.attr(e,"value");return null!=t?t:Tt(ce.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!fe(n.parentNode,"optgroup"))){if(t=ce(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=ce.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<ce.inArray(ce.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ce.each(["radio","checkbox"],function(){ce.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<ce.inArray(ce(e).val(),t)}},le.checkOn||(ce.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Et=ie.location,jt={guid:Date.now()},At=/\?/;ce.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new ie.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||ce.error("Invalid XML: "+(n?ce.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Dt=/^(?:focusinfocus|focusoutblur)$/,Nt=function(e){e.stopPropagation()};ce.extend(ce.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||C],d=ue.call(e,"type")?e.type:e,h=ue.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||C,3!==n.nodeType&&8!==n.nodeType&&!Dt.test(d+ce.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[ce.expando]?e:new ce.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:ce.makeArray(t,[e]),c=ce.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!y(n)){for(s=c.delegateType||d,Dt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||C)&&p.push(a.defaultView||a.parentWindow||ie)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(_.get(o,"events")||Object.create(null))[e.type]&&_.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&$(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!$(n)||u&&v(n[d])&&!y(n)&&((a=n[u])&&(n[u]=null),ce.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Nt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Nt),ce.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=ce.extend(new ce.Event,n,{type:e,isSimulated:!0});ce.event.trigger(r,null,t)}}),ce.fn.extend({trigger:function(e,t){return this.each(function(){ce.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ce.event.trigger(e,t,n,!0)}});var qt=/\[\]$/,Lt=/\r?\n/g,Ht=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Pt(n,e,r,i){var t;if(Array.isArray(e))ce.each(e,function(e,t){r||qt.test(n)?i(n,t):Pt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==x(e))i(n,e);else for(t in e)Pt(n+"["+t+"]",e[t],r,i)}ce.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!ce.isPlainObject(e))ce.each(e,function(){i(this.name,this.value)});else for(n in e)Pt(n,e[n],t,i);return r.join("&")},ce.fn.extend({serialize:function(){return ce.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ce.prop(this,"elements");return e?ce.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ce(this).is(":disabled")&&Ot.test(this.nodeName)&&!Ht.test(e)&&(this.checked||!we.test(e))}).map(function(e,t){var n=ce(this).val();return null==n?null:Array.isArray(n)?ce.map(n,function(e){return{name:t.name,value:e.replace(Lt,"\r\n")}}):{name:t.name,value:n.replace(Lt,"\r\n")}}).get()}});var Mt=/%20/g,Rt=/#.*$/,It=/([?&])_=[^&]*/,Wt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ft=/^(?:GET|HEAD)$/,$t=/^\/\//,Bt={},_t={},zt="*/".concat("*"),Xt=C.createElement("a");function Ut(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(D)||[];if(v(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Vt(t,i,o,a){var s={},u=t===_t;function l(e){var r;return s[e]=!0,ce.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Gt(e,t){var n,r,i=ce.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&ce.extend(!0,e,r),e}Xt.href=Et.href,ce.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":zt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":ce.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Gt(Gt(e,ce.ajaxSettings),t):Gt(ce.ajaxSettings,e)},ajaxPrefilter:Ut(Bt),ajaxTransport:Ut(_t),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=ce.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?ce(y):ce.event,x=ce.Deferred(),b=ce.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Wt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace($t,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(D)||[""],null==v.crossDomain){r=C.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Xt.protocol+"//"+Xt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=ce.param(v.data,v.traditional)),Vt(Bt,v,t,T),h)return T;for(i in(g=ce.event&&v.global)&&0==ce.active++&&ce.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ft.test(v.type),f=v.url.replace(Rt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Mt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(At.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(It,"$1"),o=(At.test(f)?"&":"?")+"_="+jt.guid+++o),v.url=f+o),v.ifModified&&(ce.lastModified[f]&&T.setRequestHeader("If-Modified-Since",ce.lastModified[f]),ce.etag[f]&&T.setRequestHeader("If-None-Match",ce.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+zt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Vt(_t,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=ie.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&ie.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<ce.inArray("script",v.dataTypes)&&ce.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(ce.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(ce.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--ce.active||ce.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return ce.get(e,t,n,"json")},getScript:function(e,t){return ce.get(e,void 0,t,"script")}}),ce.each(["get","post"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})},ce.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=ce(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return v(n)?this.each(function(e){ce(this).wrapInner(n.call(this,e))}):this.each(function(){var e=ce(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=v(t);return this.each(function(e){ce(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){ce(this).replaceWith(this.childNodes)}),this}}),ce.expr.pseudos.hidden=function(e){return!ce.expr.pseudos.visible(e)},ce.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ce.ajaxSettings.xhr=function(){try{return new ie.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Qt=ce.ajaxSettings.xhr();le.cors=!!Qt&&"withCredentials"in Qt,le.ajax=Qt=!!Qt,ce.ajaxTransport(function(i){var o,a;if(le.cors||Qt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Yt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&ie.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),ce.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ce.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return ce.globalEval(e),e}}}),ce.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ce.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=ce("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=Tt(e.slice(s)),e=e.slice(0,s)),v(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&ce.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?ce("<div>").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var en=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;ce.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),v(e))return r=ae.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(ae.call(arguments)))}).guid=e.guid=e.guid||ce.guid++,i},ce.holdReady=function(e){e?ce.readyWait++:ce.ready(!0)},ce.isArray=Array.isArray,ce.parseJSON=JSON.parse,ce.nodeName=fe,ce.isFunction=v,ce.isWindow=y,ce.camelCase=F,ce.type=x,ce.now=Date.now,ce.isNumeric=function(e){var t=ce.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},ce.trim=function(e){return null==e?"":(e+"").replace(en,"$1")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return ce});var tn=ie.jQuery,nn=ie.$;return ce.noConflict=function(e){return ie.$===ce&&(ie.$=nn),e&&ie.jQuery===ce&&(ie.jQuery=tn),ce},"undefined"==typeof e&&(ie.jQuery=ie.$=ce),ce});
diff --git a/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.map b/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.map
new file mode 100644
index 0000000000..db38af5893
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/js/jquery-3.7.1.min.map
@@ -0,0 +1 @@
{"version":3,"sources":["jquery-3.7.1.js"],"names":["global","factory","module","exports","document","w","Error","window","this","noGlobal","arr","getProto","Object","getPrototypeOf","slice","flat","array","call","concat","apply","push","indexOf","class2type","toString","hasOwn","hasOwnProperty","fnToString","ObjectFunctionString","support","isFunction","obj","nodeType","item","isWindow","preservedScriptAttributes","type","src","nonce","noModule","DOMEval","code","node","doc","i","val","script","createElement","text","getAttribute","setAttribute","head","appendChild","parentNode","removeChild","toType","version","rhtmlSuffix","jQuery","selector","context","fn","init","isArrayLike","length","nodeName","elem","name","toLowerCase","prototype","jquery","constructor","toArray","get","num","pushStack","elems","ret","merge","prevObject","each","callback","map","arguments","first","eq","last","even","grep","_elem","odd","len","j","end","sort","splice","extend","options","copy","copyIsArray","clone","target","deep","isPlainObject","Array","isArray","undefined","expando","Math","random","replace","isReady","error","msg","noop","proto","Ctor","isEmptyObject","globalEval","textContent","documentElement","nodeValue","makeArray","results","inArray","isXMLDoc","namespace","namespaceURI","docElem","ownerDocument","test","second","invert","matches","callbackExpect","arg","value","guid","Symbol","iterator","split","_i","pop","whitespace","rtrimCSS","RegExp","contains","a","b","bup","compareDocumentPosition","rcssescape","fcssescape","ch","asCodePoint","charCodeAt","escapeSelector","sel","preferredDoc","pushNative","Expr","outermostContext","sortInput","hasDuplicate","documentIsHTML","rbuggyQSA","dirruns","done","classCache","createCache","tokenCache","compilerCache","nonnativeSelectorCache","sortOrder","booleans","identifier","attributes","pseudos","rwhitespace","rcomma","rleadingCombinator","rdescend","rpseudo","ridentifier","matchExpr","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","rinputs","rheader","rquickExpr","rsibling","runescape","funescape","escape","nonHex","high","String","fromCharCode","unloadHandler","setDocument","inDisabledFieldset","addCombinator","disabled","dir","next","childNodes","e","els","find","seed","m","nid","match","groups","newSelector","newContext","exec","getElementById","id","getElementsByTagName","getElementsByClassName","testContext","scope","tokenize","toSelector","join","querySelectorAll","qsaError","removeAttribute","select","keys","cache","key","cacheLength","shift","markFunction","assert","el","createInputPseudo","createButtonPseudo","createDisabledPseudo","isDisabled","createPositionalPseudo","argument","matchIndexes","subWindow","webkitMatchesSelector","msMatchesSelector","defaultView","top","addEventListener","getById","getElementsByName","disconnectedMatch","cssHas","querySelector","filter","attrId","getAttributeNode","tag","className","input","innerHTML","compare","sortDetached","expr","elements","matchesSelector","attr","attrHandle","uniqueSort","duplicates","sortStable","createPseudo","relative",">"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","expectedNodeName","pattern","operator","check","result","what","_argument","simple","forward","ofType","_context","xml","outerCache","nodeIndex","start","parent","useCache","diff","firstChild","lastChild","pseudo","args","setFilters","idx","matched","not","matcher","compile","unmatched","has","lang","elemLang","hash","location","root","focus","activeElement","err","safeActiveElement","hasFocus","href","tabIndex","enabled","checked","selected","selectedIndex","empty","nextSibling","header","button","_matchIndexes","lt","gt","nth","radio","checkbox","file","password","image","submit","reset","parseOnly","tokens","soFar","preFilters","cached","combinator","base","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","matcherOut","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","filters","unique","getText","isXML","selectors","until","truncate","is","siblings","n","rneedsContext","rsingleTag","winnow","qualifier","self","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","cur","targets","l","closest","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","content","reverse","rnothtmlwhite","Identity","v","Thrower","ex","adoptValue","resolve","reject","noValue","method","promise","fail","then","Callbacks","object","_","flag","firing","memory","fired","locked","list","queue","firingIndex","fire","once","stopOnFalse","remove","disable","lock","fireWith","Deferred","func","tuples","state","always","deferred","catch","pipe","fns","newDefer","tuple","returned","progress","notify","onFulfilled","onRejected","onProgress","maxDepth","depth","handler","special","that","mightThrow","TypeError","notifyWith","resolveWith","process","exceptionHook","rejectWith","getErrorHook","getStackHook","setTimeout","stateString","when","singleValue","remaining","resolveContexts","resolveValues","primary","updateFunc","rerrorNames","asyncError","console","warn","message","stack","readyException","readyList","completed","removeEventListener","readyWait","wait","readyState","doScroll","access","chainable","emptyGet","raw","bulk","_key","rmsPrefix","rdashAlpha","fcamelCase","_all","letter","toUpperCase","camelCase","string","acceptData","owner","Data","uid","defineProperty","configurable","set","data","prop","hasData","dataPriv","dataUser","rbrace","rmultiDash","dataAttr","JSON","parse","removeData","_data","_removeData","attrs","dequeue","startLength","hooks","_queueHooks","unshift","stop","setter","clearQueue","tmp","count","defer","pnum","source","rcssNum","cssExpand","isAttached","composed","getRootNode","isHiddenWithinTree","style","display","css","adjustCSS","valueParts","tween","adjusted","scale","maxIterations","currentValue","initial","unit","cssNumber","initialInUnit","defaultDisplayMap","showHide","show","values","body","hide","toggle","div","rcheckableType","rtagName","rscriptType","createDocumentFragment","checkClone","cloneNode","noCloneChecked","defaultValue","option","wrapMap","thead","col","tr","td","_default","getAll","setGlobalEval","refElements","tbody","tfoot","colgroup","caption","th","optgroup","rhtml","buildFragment","scripts","selection","ignored","wrap","attached","fragment","nodes","htmlPrefilter","createTextNode","rtypenamespace","returnTrue","returnFalse","on","types","one","origFn","event","off","leverageNative","isSetup","saved","isTrigger","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","isImmediatePropagationStopped","handleObjIn","eventHandle","events","t","handleObj","handlers","namespaces","origType","elemData","create","handle","triggered","dispatch","bindType","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","nativeEvent","handlerQueue","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","rnamespace","postDispatch","matchedHandlers","matchedSelectors","addProp","hook","Event","enumerable","originalEvent","writable","load","noBubble","click","beforeunload","returnValue","props","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","Date","now","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","char","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","focusMappedHandler","documentMode","simulate","attaches","dataHolder","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","rnoInnerhtml","rchecked","rcleanScript","manipulationTarget","disableScript","restoreScript","cloneCopyEvent","dest","udataOld","udataCur","domManip","collection","hasScripts","iNoClone","valueIsFunction","html","_evalUrl","keepData","cleanData","dataAndEvents","deepDataAndEvents","srcElements","destElements","inPage","detach","append","prepend","insertBefore","before","after","replaceWith","replaceChild","appendTo","prependTo","insertAfter","replaceAll","original","insert","rnumnonpx","rcustomProp","getStyles","opener","getComputedStyle","swap","old","rboxStyle","curCSS","computed","width","minWidth","maxWidth","isCustomProp","getPropertyValue","pixelBoxStyles","addGetHookIf","conditionFn","hookFn","computeStyleTests","container","cssText","divStyle","pixelPositionVal","reliableMarginLeftVal","roundPixelMeasures","marginLeft","right","pixelBoxStylesVal","boxSizingReliableVal","position","scrollboxSizeVal","offsetWidth","measure","round","parseFloat","reliableTrDimensionsVal","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","table","trChild","trStyle","height","parseInt","borderTopWidth","borderBottomWidth","offsetHeight","cssPrefixes","emptyStyle","vendorProps","finalPropName","final","cssProps","capName","vendorPropName","rdisplayswap","cssShow","visibility","cssNormalTransform","letterSpacing","fontWeight","setPositiveNumber","subtract","max","boxModelAdjustment","dimension","box","isBorderBox","styles","computedVal","extra","delta","marginDelta","ceil","getWidthOrHeight","valueIsBorderBox","offsetProp","getClientRects","Tween","easing","cssHooks","opacity","animationIterationCount","aspectRatio","borderImageSlice","columnCount","flexGrow","flexShrink","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","order","orphans","widows","zIndex","zoom","fillOpacity","floodOpacity","stopOpacity","strokeMiterlimit","strokeOpacity","origName","setProperty","isFinite","getBoundingClientRect","scrollboxSizeBuggy","left","margin","padding","border","prefix","suffix","expand","expanded","parts","propHooks","run","percent","eased","duration","pos","step","fx","scrollTop","scrollLeft","linear","p","swing","cos","PI","fxNow","inProgress","opt","rfxtypes","rrun","schedule","hidden","requestAnimationFrame","interval","tick","createFxNow","genFx","includeWidth","createTween","animation","Animation","tweeners","properties","stopped","prefilters","currentTime","startTime","tweens","opts","specialEasing","originalProperties","originalOptions","gotoEnd","propFilter","bind","complete","timer","anim","*","tweener","oldfire","propTween","restoreDisplay","isBox","dataShow","unqueued","overflow","overflowX","overflowY","prefilter","speed","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","slow","fast","delay","time","timeout","clearTimeout","checkOn","optSelected","radioValue","boolHook","removeAttr","nType","attrHooks","attrNames","getter","lowercaseName","rfocusable","rclickable","stripAndCollapse","getClass","classesToArray","removeProp","propFix","tabindex","for","class","addClass","classNames","curValue","finalValue","removeClass","toggleClass","stateVal","isValidValue","hasClass","rreturn","valHooks","optionSet","rquery","parseXML","parserErrorElem","DOMParser","parseFromString","rfocusMorph","stopPropagationCallback","onlyHandlers","bubbleType","ontype","lastElement","eventPath","parentWindow","triggerHandler","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","traditional","param","s","valueOrFunction","encodeURIComponent","serialize","serializeArray","r20","rhash","rantiCache","rheaders","rnoContent","rprotocol","transports","allTypes","originAnchor","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","active","lastModified","etag","url","isLocal","protocol","processData","async","contentType","accepts","json","responseFields","converters","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","transport","cacheURL","responseHeadersString","responseHeaders","timeoutTimer","urlAnchor","fireGlobals","uncached","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getResponseHeader","getAllResponseHeaders","setRequestHeader","overrideMimeType","mimeType","status","abort","statusText","finalText","crossDomain","host","hasContent","ifModified","headers","beforeSend","success","send","nativeStatusText","responses","isSuccess","response","modified","ct","finalDataType","firstDataType","ajaxHandleResponses","conv2","current","conv","dataFilter","throws","ajaxConvert","getJSON","getScript","text script","wrapAll","firstElementChild","wrapInner","htmlIsFunction","unwrap","visible","xhr","XMLHttpRequest","xhrSuccessStatus","0","1223","xhrSupported","cors","errorCallback","open","username","xhrFields","onload","onerror","onabort","ontimeout","onreadystatechange","responseType","responseText","binary","scriptAttrs","charset","scriptCharset","evt","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","createHTMLDocument","implementation","keepScripts","parsed","params","animated","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","curElem","using","rect","win","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","","defaultExtra","funcName","unbind","delegate","undelegate","hover","fnOver","fnOut","rtrim","proxy","holdReady","hold","parseJSON","isNumeric","isNaN","trim","define","amd","_jQuery","_$","$","noConflict"],"mappings":"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","file":"jquery-3.7.1.min.js"} \ No newline at end of file
diff --git a/bitbake/lib/toaster/toastergui/static/js/jquery.dataTables-1.13.8.min.js b/bitbake/lib/toaster/toastergui/static/js/jquery.dataTables-1.13.8.min.js
new file mode 100644
index 0000000000..b6d9aa8c79
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/js/jquery.dataTables-1.13.8.min.js
@@ -0,0 +1,4 @@
1/*! DataTables 1.13.8
2 * ©2008-2023 SpryMedia Ltd - datatables.net/license
3 */
4!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:module.exports=n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/<script/i,""),e,n)||null}function m(t,e,n,a){var r=[],o=0,i=e.length;if(a!==H)for(;o<i;o++)t[e[o]][n]&&r.push(t[e[o]][n][a]);else for(;o<i;o++)r.push(t[e[o]][n]);return r}function f(t,e){var n,a=[];e===H?(e=0,n=t):(n=e,e=t);for(var r=e;r<n;r++)a.push(r);return a}function _(t){for(var e=[],n=0,a=t.length;n<a;n++)t[n]&&e.push(t[n]);return e}function s(t,e){return-1!==this.indexOf(t,e=e===H?0:e)}var p,e,t,w=function(t,v){if(w.factory(t,v))return w;if(this instanceof w)return P(t).DataTable(v);v=t,this.$=function(t,e){return this.api(!0).$(t,e)},this._=function(t,e){return this.api(!0).rows(t,e).data()},this.api=function(t){return new B(t?ge(this[p.iApiIndex]):this)},this.fnAddData=function(t,e){var n=this.api(!0),t=(Array.isArray(t)&&(Array.isArray(t[0])||P.isPlainObject(t[0]))?n.rows:n.row).add(t);return e!==H&&!e||n.draw(),t.flatten().toArray()},this.fnAdjustColumnSizing=function(t){var e=this.api(!0).columns.adjust(),n=e.settings()[0],a=n.oScroll;t===H||t?e.draw(!1):""===a.sX&&""===a.sY||Qt(n)},this.fnClearTable=function(t){var e=this.api(!0).clear();t!==H&&!t||e.draw()},this.fnClose=function(t){this.api(!0).row(t).child.hide()},this.fnDeleteRow=function(t,e,n){var a=this.api(!0),t=a.rows(t),r=t.settings()[0],o=r.aoData[t[0][0]];return t.remove(),e&&e.call(this,r,o),n!==H&&!n||a.draw(),o},this.fnDestroy=function(t){this.api(!0).destroy(t)},this.fnDraw=function(t){this.api(!0).draw(t)},this.fnFilter=function(t,e,n,a,r,o){var i=this.api(!0);(null===e||e===H?i:i.column(e)).search(t,n,a,o),i.draw()},this.fnGetData=function(t,e){var n,a=this.api(!0);return t!==H?(n=t.nodeName?t.nodeName.toLowerCase():"",e!==H||"td"==n||"th"==n?a.cell(t,e).data():a.row(t).data()||null):a.data().toArray()},this.fnGetNodes=function(t){var e=this.api(!0);return t!==H?e.row(t).node():e.rows().nodes().flatten().toArray()},this.fnGetPosition=function(t){var e=this.api(!0),n=t.nodeName.toUpperCase();return"TR"==n?e.row(t).index():"TD"==n||"TH"==n?[(n=e.cell(t).index()).row,n.columnVisible,n.column]:null},this.fnIsOpen=function(t){return this.api(!0).row(t).child.isShown()},this.fnOpen=function(t,e,n){return this.api(!0).row(t).child(e,n).show().child()[0]},this.fnPageChange=function(t,e){t=this.api(!0).page(t);e!==H&&!e||t.draw(!1)},this.fnSetColumnVis=function(t,e,n){t=this.api(!0).column(t).visible(e);n!==H&&!n||t.columns.adjust().draw()},this.fnSettings=function(){return ge(this[p.iApiIndex])},this.fnSort=function(t){this.api(!0).order(t).draw()},this.fnSortListener=function(t,e,n){this.api(!0).order.listener(t,e,n)},this.fnUpdate=function(t,e,n,a,r){var o=this.api(!0);return(n===H||null===n?o.row(e):o.cell(e,n)).data(t),r!==H&&!r||o.columns.adjust(),a!==H&&!a||o.draw(),0},this.fnVersionCheck=p.fnVersionCheck;var e,y=this,D=v===H,_=this.length;for(e in D&&(v={}),this.oApi=this.internal=p.internal,w.ext.internal)e&&(this[e]=$e(e));return this.each(function(){var r=1<_?be({},v,!0):v,o=0,t=this.getAttribute("id"),i=!1,e=w.defaults,l=P(this);if("table"!=this.nodeName.toLowerCase())W(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{K(e),Q(e.column),C(e,e,!0),C(e.column,e.column,!0),C(e,P.extend(r,l.data()),!0);for(var n=w.settings,o=0,s=n.length;o<s;o++){var a=n[o];if(a.nTable==this||a.nTHead&&a.nTHead.parentNode==this||a.nTFoot&&a.nTFoot.parentNode==this){var u=(r.bRetrieve!==H?r:e).bRetrieve,c=(r.bDestroy!==H?r:e).bDestroy;if(D||u)return a.oInstance;if(c){a.oInstance.fnDestroy();break}return void W(a,0,"Cannot reinitialise DataTable",3)}if(a.sTableId==this.id){n.splice(o,1);break}}null!==t&&""!==t||(t="DataTables_Table_"+w.ext._unique++,this.id=t);var f,d,h=P.extend(!0,{},w.models.oSettings,{sDestroyWidth:l[0].style.width,sInstance:t,sTableId:t}),p=(h.nTable=this,h.oApi=y.internal,h.oInit=r,n.push(h),h.oInstance=1===y.length?y:l.dataTable(),K(r),Z(r.oLanguage),r.aLengthMenu&&!r.iDisplayLength&&(r.iDisplayLength=(Array.isArray(r.aLengthMenu[0])?r.aLengthMenu[0]:r.aLengthMenu)[0]),r=be(P.extend(!0,{},e),r),F(h.oFeatures,r,["bPaginate","bLengthChange","bFilter","bSort","bSortMulti","bInfo","bProcessing","bAutoWidth","bSortClasses","bServerSide","bDeferRender"]),F(h,r,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer","searchDelay","rowId",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"]]),F(h.oScroll,r,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]),F(h.oLanguage,r,"fnInfoCallback"),L(h,"aoDrawCallback",r.fnDrawCallback,"user"),L(h,"aoServerParams",r.fnServerParams,"user"),L(h,"aoStateSaveParams",r.fnStateSaveParams,"user"),L(h,"aoStateLoadParams",r.fnStateLoadParams,"user"),L(h,"aoStateLoaded",r.fnStateLoaded,"user"),L(h,"aoRowCallback",r.fnRowCallback,"user"),L(h,"aoRowCreatedCallback",r.fnCreatedRow,"user"),L(h,"aoHeaderCallback",r.fnHeaderCallback,"user"),L(h,"aoFooterCallback",r.fnFooterCallback,"user"),L(h,"aoInitComplete",r.fnInitComplete,"user"),L(h,"aoPreDrawCallback",r.fnPreDrawCallback,"user"),h.rowIdFn=A(r.rowId),tt(h),h.oClasses),g=(P.extend(p,w.ext.classes,r.oClasses),l.addClass(p.sTable),h.iInitDisplayStart===H&&(h.iInitDisplayStart=r.iDisplayStart,h._iDisplayStart=r.iDisplayStart),null!==r.iDeferLoading&&(h.bDeferLoading=!0,t=Array.isArray(r.iDeferLoading),h._iRecordsDisplay=t?r.iDeferLoading[0]:r.iDeferLoading,h._iRecordsTotal=t?r.iDeferLoading[1]:r.iDeferLoading),h.oLanguage),t=(P.extend(!0,g,r.oLanguage),g.sUrl?(P.ajax({dataType:"json",url:g.sUrl,success:function(t){C(e.oLanguage,t),Z(t),P.extend(!0,g,t,h.oInit.oLanguage),R(h,null,"i18n",[h]),Jt(h)},error:function(){Jt(h)}}),i=!0):R(h,null,"i18n",[h]),null===r.asStripeClasses&&(h.asStripeClasses=[p.sStripeOdd,p.sStripeEven]),h.asStripeClasses),b=l.children("tbody").find("tr").eq(0),m=(-1!==P.inArray(!0,P.map(t,function(t,e){return b.hasClass(t)}))&&(P("tbody tr",this).removeClass(t.join(" ")),h.asDestroyStripes=t.slice()),[]),t=this.getElementsByTagName("thead");if(0!==t.length&&(wt(h.aoHeader,t[0]),m=Ct(h)),null===r.aoColumns)for(f=[],o=0,s=m.length;o<s;o++)f.push(null);else f=r.aoColumns;for(o=0,s=f.length;o<s;o++)nt(h,m?m[o]:null);st(h,r.aoColumnDefs,f,function(t,e){at(h,t,e)}),b.length&&(d=function(t,e){return null!==t.getAttribute("data-"+e)?e:null},P(b[0]).children("th, td").each(function(t,e){var n,a=h.aoColumns[t];a||W(h,0,"Incorrect column count",18),a.mData===t&&(n=d(e,"sort")||d(e,"order"),e=d(e,"filter")||d(e,"search"),null===n&&null===e||(a.mData={_:t+".display",sort:null!==n?t+".@data-"+n:H,type:null!==n?t+".@data-"+n:H,filter:null!==e?t+".@data-"+e:H},a._isArrayHost=!0,at(h,t)))}));var S=h.oFeatures,t=function(){if(r.aaSorting===H){var t=h.aaSorting;for(o=0,s=t.length;o<s;o++)t[o][1]=h.aoColumns[o].asSorting[0]}ce(h),S.bSort&&L(h,"aoDrawCallback",function(){var t,n;h.bSorted&&(t=I(h),n={},P.each(t,function(t,e){n[e.src]=e.dir}),R(h,null,"order",[h,t,n]),le(h))}),L(h,"aoDrawCallback",function(){(h.bSorted||"ssp"===E(h)||S.bDeferRender)&&ce(h)},"sc");var e=l.children("caption").each(function(){this._captionSide=P(this).css("caption-side")}),n=l.children("thead"),a=(0===n.length&&(n=P("<thead/>").appendTo(l)),h.nTHead=n[0],l.children("tbody")),n=(0===a.length&&(a=P("<tbody/>").insertAfter(n)),h.nTBody=a[0],l.children("tfoot"));if(0===(n=0===n.length&&0<e.length&&(""!==h.oScroll.sX||""!==h.oScroll.sY)?P("<tfoot/>").appendTo(l):n).length||0===n.children().length?l.addClass(p.sNoFooter):0<n.length&&(h.nTFoot=n[0],wt(h.aoFooter,h.nTFoot)),r.aaData)for(o=0;o<r.aaData.length;o++)x(h,r.aaData[o]);else!h.bDeferLoading&&"dom"!=E(h)||ut(h,P(h.nTBody).children("tr"));h.aiDisplay=h.aiDisplayMaster.slice(),!(h.bInitialised=!0)===i&&Jt(h)};L(h,"aoDrawCallback",de,"state_save"),r.bStateSave?(S.bStateSave=!0,he(h,0,t)):t()}}),y=null,this},c={},U=/[\r\n\u2028]/g,V=/<.*?>/g,X=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,J=new RegExp("(\\"+["/",".","*","+","?","|","(",")","[","]","{","}","\\","$","^","-"].join("|\\")+")","g"),q=/['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,h=function(t){return!t||!0===t||"-"===t},$=function(t,e){return c[e]||(c[e]=new RegExp(Ot(e),"g")),"string"==typeof t&&"."!==e?t.replace(/\./g,"").replace(c[e],"."):t},N=function(t,e,n){var a=[],r=0,o=t.length;if(n!==H)for(;r<o;r++)t[r]&&t[r][e]&&a.push(t[r][e][n]);else for(;r<o;r++)t[r]&&a.push(t[r][e]);return a},G=function(t){if(!(t.length<2))for(var e=t.slice().sort(),n=e[0],a=1,r=e.length;a<r;a++){if(e[a]===n)return!1;n=e[a]}return!0},z=function(t){if(G(t))return t.slice();var e,n,a,r=[],o=t.length,i=0;t:for(n=0;n<o;n++){for(e=t[n],a=0;a<i;a++)if(r[a]===e)continue t;r.push(e),i++}return r},Y=function(t,e){if(Array.isArray(e))for(var n=0;n<e.length;n++)Y(t,e[n]);else t.push(e);return t};function i(n){var a,r,o={};P.each(n,function(t,e){(a=t.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(a[1]+" ")&&(r=t.replace(a[0],a[2].toLowerCase()),o[r]=t,"o"===a[1])&&i(n[t])}),n._hungarianMap=o}function C(n,a,r){var o;n._hungarianMap||i(n),P.each(a,function(t,e){(o=n._hungarianMap[t])===H||!r&&a[o]!==H||("o"===o.charAt(0)?(a[o]||(a[o]={}),P.extend(!0,a[o],a[t]),C(n[o],a[o],r)):a[o]=a[t])})}function Z(t){var e,n=w.defaults.oLanguage,a=n.sDecimal;a&&Me(a),t&&(e=t.sZeroRecords,!t.sEmptyTable&&e&&"No data available in table"===n.sEmptyTable&&F(t,t,"sZeroRecords","sEmptyTable"),!t.sLoadingRecords&&e&&"Loading..."===n.sLoadingRecords&&F(t,t,"sZeroRecords","sLoadingRecords"),t.sInfoThousands&&(t.sThousands=t.sInfoThousands),e=t.sDecimal)&&a!==e&&Me(e)}Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Array.prototype.includes||(Array.prototype.includes=s),String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}),String.prototype.includes||(String.prototype.includes=s),w.util={throttle:function(a,t){var r,o,i=t!==H?t:200;return function(){var t=this,e=+new Date,n=arguments;r&&e<r+i?(clearTimeout(o),o=setTimeout(function(){r=H,a.apply(t,n)},i)):(r=e,a.apply(t,n))}},escapeRegex:function(t){return t.replace(J,"\\$1")},set:function(a){var d;return P.isPlainObject(a)?w.util.set(a._):null===a?function(){}:"function"==typeof a?function(t,e,n){a(t,"set",e,n)}:"string"!=typeof a||-1===a.indexOf(".")&&-1===a.indexOf("[")&&-1===a.indexOf("(")?function(t,e){t[a]=e}:(d=function(t,e,n){for(var a,r,o,i,l=dt(n),n=l[l.length-1],s=0,u=l.length-1;s<u;s++){if("__proto__"===l[s]||"constructor"===l[s])throw new Error("Cannot set prototype values");if(a=l[s].match(ft),r=l[s].match(g),a){if(l[s]=l[s].replace(ft,""),t[l[s]]=[],(a=l.slice()).splice(0,s+1),i=a.join("."),Array.isArray(e))for(var c=0,f=e.length;c<f;c++)d(o={},e[c],i),t[l[s]].push(o);else t[l[s]]=e;return}r&&(l[s]=l[s].replace(g,""),t=t[l[s]](e)),null!==t[l[s]]&&t[l[s]]!==H||(t[l[s]]={}),t=t[l[s]]}n.match(g)?t[n.replace(g,"")](e):t[n.replace(ft,"")]=e},function(t,e){return d(t,e,a)})},get:function(r){var o,d;return P.isPlainObject(r)?(o={},P.each(r,function(t,e){e&&(o[t]=w.util.get(e))}),function(t,e,n,a){var r=o[e]||o._;return r!==H?r(t,e,n,a):t}):null===r?function(t){return t}:"function"==typeof r?function(t,e,n,a){return r(t,e,n,a)}:"string"!=typeof r||-1===r.indexOf(".")&&-1===r.indexOf("[")&&-1===r.indexOf("(")?function(t,e){return t[r]}:(d=function(t,e,n){var a,r,o;if(""!==n)for(var i=dt(n),l=0,s=i.length;l<s;l++){if(f=i[l].match(ft),a=i[l].match(g),f){if(i[l]=i[l].replace(ft,""),""!==i[l]&&(t=t[i[l]]),r=[],i.splice(0,l+1),o=i.join("."),Array.isArray(t))for(var u=0,c=t.length;u<c;u++)r.push(d(t[u],e,o));var f=f[0].substring(1,f[0].length-1);t=""===f?r:r.join(f);break}if(a)i[l]=i[l].replace(g,""),t=t[i[l]]();else{if(null===t||null===t[i[l]])return null;if(t===H||t[i[l]]===H)return H;t=t[i[l]]}}return t},function(t,e){return d(t,e,r)})}};var r=function(t,e,n){t[e]!==H&&(t[n]=t[e])};function K(t){r(t,"ordering","bSort"),r(t,"orderMulti","bSortMulti"),r(t,"orderClasses","bSortClasses"),r(t,"orderCellsTop","bSortCellsTop"),r(t,"order","aaSorting"),r(t,"orderFixed","aaSortingFixed"),r(t,"paging","bPaginate"),r(t,"pagingType","sPaginationType"),r(t,"pageLength","iDisplayLength"),r(t,"searching","bFilter"),"boolean"==typeof t.sScrollX&&(t.sScrollX=t.sScrollX?"100%":""),"boolean"==typeof t.scrollX&&(t.scrollX=t.scrollX?"100%":"");var e=t.aoSearchCols;if(e)for(var n=0,a=e.length;n<a;n++)e[n]&&C(w.models.oSearch,e[n])}function Q(t){r(t,"orderable","bSortable"),r(t,"orderData","aDataSort"),r(t,"orderSequence","asSorting"),r(t,"orderDataType","sortDataType");var e=t.aDataSort;"number"!=typeof e||Array.isArray(e)||(t.aDataSort=[e])}function tt(t){var e,n,a,r;w.__browser||(w.__browser=e={},r=(a=(n=P("<div/>").css({position:"fixed",top:0,left:-1*P(j).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(P("<div/>").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(P("<div/>").css({width:"100%",height:10}))).appendTo("body")).children()).children(),e.barWidth=a[0].offsetWidth-a[0].clientWidth,e.bScrollOversize=100===r[0].offsetWidth&&100!==a[0].clientWidth,e.bScrollbarLeft=1!==Math.round(r.offset().left),e.bBounding=!!n[0].getBoundingClientRect().width,n.remove()),P.extend(t.oBrowser,w.__browser),t.oScroll.iBarWidth=w.__browser.barWidth}function et(t,e,n,a,r,o){var i,l=a,s=!1;for(n!==H&&(i=n,s=!0);l!==r;)t.hasOwnProperty(l)&&(i=s?e(i,t[l],l,t):t[l],s=!0,l+=o);return i}function nt(t,e){var n=w.defaults.column,a=t.aoColumns.length,n=P.extend({},w.models.oColumn,n,{nTh:e||v.createElement("th"),sTitle:n.sTitle||(e?e.innerHTML:""),aDataSort:n.aDataSort||[a],mData:n.mData||a,idx:a}),n=(t.aoColumns.push(n),t.aoPreSearchCols);n[a]=P.extend({},w.models.oSearch,n[a]),at(t,a,P(e).data())}function at(t,e,n){function a(t){return"string"==typeof t&&-1!==t.indexOf("@")}var e=t.aoColumns[e],r=t.oClasses,o=P(e.nTh),i=(!e.sWidthOrig&&(e.sWidthOrig=o.attr("width")||null,u=(o.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/))&&(e.sWidthOrig=u[1]),n!==H&&null!==n&&(Q(n),C(w.defaults.column,n,!0),n.mDataProp===H||n.mData||(n.mData=n.mDataProp),n.sType&&(e._sManualType=n.sType),n.className&&!n.sClass&&(n.sClass=n.className),n.sClass&&o.addClass(n.sClass),u=e.sClass,P.extend(e,n),F(e,n,"sWidth","sWidthOrig"),u!==e.sClass&&(e.sClass=u+" "+e.sClass),n.iDataSort!==H&&(e.aDataSort=[n.iDataSort]),F(e,n,"aDataSort"),e.ariaTitle||(e.ariaTitle=o.attr("aria-label"))),e.mData),l=A(i),s=e.mRender?A(e.mRender):null,u=(e._bAttrSrc=P.isPlainObject(i)&&(a(i.sort)||a(i.type)||a(i.filter)),e._setter=null,e.fnGetData=function(t,e,n){var a=l(t,e,H,n);return s&&e?s(a,e,t,n):a},e.fnSetData=function(t,e,n){return b(i)(t,e,n)},"number"==typeof i||e._isArrayHost||(t._rowReadObject=!0),t.oFeatures.bSort||(e.bSortable=!1,o.addClass(r.sSortableNone)),-1!==P.inArray("asc",e.asSorting)),n=-1!==P.inArray("desc",e.asSorting);e.bSortable&&(u||n)?u&&!n?(e.sSortingClass=r.sSortableAsc,e.sSortingClassJUI=r.sSortJUIAscAllowed):!u&&n?(e.sSortingClass=r.sSortableDesc,e.sSortingClassJUI=r.sSortJUIDescAllowed):(e.sSortingClass=r.sSortable,e.sSortingClassJUI=r.sSortJUI):(e.sSortingClass=r.sSortableNone,e.sSortingClassJUI="")}function O(t){if(!1!==t.oFeatures.bAutoWidth){var e=t.aoColumns;ee(t);for(var n=0,a=e.length;n<a;n++)e[n].nTh.style.width=e[n].sWidth}var r=t.oScroll;""===r.sY&&""===r.sX||Qt(t),R(t,null,"column-sizing",[t])}function rt(t,e){t=it(t,"bVisible");return"number"==typeof t[e]?t[e]:null}function ot(t,e){t=it(t,"bVisible"),e=P.inArray(e,t);return-1!==e?e:null}function T(t){var n=0;return P.each(t.aoColumns,function(t,e){e.bVisible&&"none"!==P(e.nTh).css("display")&&n++}),n}function it(t,n){var a=[];return P.map(t.aoColumns,function(t,e){t[n]&&a.push(e)}),a}function lt(t){for(var e,n,a,r,o,i,l,s=t.aoColumns,u=t.aoData,c=w.ext.type.detect,f=0,d=s.length;f<d;f++)if(l=[],!(o=s[f]).sType&&o._sManualType)o.sType=o._sManualType;else if(!o.sType){for(e=0,n=c.length;e<n;e++){for(a=0,r=u.length;a<r&&(l[a]===H&&(l[a]=S(t,a,f,"type")),(i=c[e](l[a],t))||e===c.length-1)&&("html"!==i||h(l[a]));a++);if(i){o.sType=i;break}}o.sType||(o.sType="string")}}function st(t,e,n,a){var r,o,i,l,s=t.aoColumns;if(e)for(r=e.length-1;0<=r;r--)for(var u,c=(u=e[r]).target!==H?u.target:u.targets!==H?u.targets:u.aTargets,f=0,d=(c=Array.isArray(c)?c:[c]).length;f<d;f++)if("number"==typeof c[f]&&0<=c[f]){for(;s.length<=c[f];)nt(t);a(c[f],u)}else if("number"==typeof c[f]&&c[f]<0)a(s.length+c[f],u);else if("string"==typeof c[f])for(i=0,l=s.length;i<l;i++)"_all"!=c[f]&&!P(s[i].nTh).hasClass(c[f])||a(i,u);if(n)for(r=0,o=n.length;r<o;r++)a(r,n[r])}function x(t,e,n,a){for(var r=t.aoData.length,o=P.extend(!0,{},w.models.oRow,{src:n?"dom":"data",idx:r}),i=(o._aData=e,t.aoData.push(o),t.aoColumns),l=0,s=i.length;l<s;l++)i[l].sType=null;t.aiDisplayMaster.push(r);e=t.rowIdFn(e);return e!==H&&(t.aIds[e]=o),!n&&t.oFeatures.bDeferRender||St(t,r,n,a),r}function ut(n,t){var a;return(t=t instanceof P?t:P(t)).map(function(t,e){return a=mt(n,e),x(n,a.data,e,a.cells)})}function S(t,e,n,a){"search"===a?a="filter":"order"===a&&(a="sort");var r=t.iDraw,o=t.aoColumns[n],i=t.aoData[e]._aData,l=o.sDefaultContent,s=o.fnGetData(i,a,{settings:t,row:e,col:n});if(s===H)return t.iDrawError!=r&&null===l&&(W(t,0,"Requested unknown parameter "+("function"==typeof o.mData?"{function}":"'"+o.mData+"'")+" for row "+e+", column "+n,4),t.iDrawError=r),l;if(s!==i&&null!==s||null===l||a===H){if("function"==typeof s)return s.call(i)}else s=l;return null===s&&"display"===a?"":"filter"===a&&(e=w.ext.type.search)[o.sType]?e[o.sType](s):s}function ct(t,e,n,a){var r=t.aoColumns[n],o=t.aoData[e]._aData;r.fnSetData(o,a,{settings:t,row:e,col:n})}var ft=/\[.*?\]$/,g=/\(\)$/;function dt(t){return P.map(t.match(/(\\.|[^\.])+/g)||[""],function(t){return t.replace(/\\\./g,".")})}var A=w.util.get,b=w.util.set;function ht(t){return N(t.aoData,"_aData")}function pt(t){t.aoData.length=0,t.aiDisplayMaster.length=0,t.aiDisplay.length=0,t.aIds={}}function gt(t,e,n){for(var a=-1,r=0,o=t.length;r<o;r++)t[r]==e?a=r:t[r]>e&&t[r]--;-1!=a&&n===H&&t.splice(a,1)}function bt(n,a,t,e){function r(t,e){for(;t.childNodes.length;)t.removeChild(t.firstChild);t.innerHTML=S(n,a,e,"display")}var o,i,l=n.aoData[a];if("dom"!==t&&(t&&"auto"!==t||"dom"!==l.src)){var s=l.anCells;if(s)if(e!==H)r(s[e],e);else for(o=0,i=s.length;o<i;o++)r(s[o],o)}else l._aData=mt(n,l,e,e===H?H:l._aData).data;l._aSortData=null,l._aFilterData=null;var u=n.aoColumns;if(e!==H)u[e].sType=null;else{for(o=0,i=u.length;o<i;o++)u[o].sType=null;vt(n,l)}}function mt(t,e,n,a){function r(t,e){var n;"string"==typeof t&&-1!==(n=t.indexOf("@"))&&(n=t.substring(n+1),b(t)(a,e.getAttribute(n)))}function o(t){n!==H&&n!==f||(l=d[f],s=t.innerHTML.trim(),l&&l._bAttrSrc?(b(l.mData._)(a,s),r(l.mData.sort,t),r(l.mData.type,t),r(l.mData.filter,t)):h?(l._setter||(l._setter=b(l.mData)),l._setter(a,s)):a[f]=s),f++}var i,l,s,u=[],c=e.firstChild,f=0,d=t.aoColumns,h=t._rowReadObject;a=a!==H?a:h?{}:[];if(c)for(;c;)"TD"!=(i=c.nodeName.toUpperCase())&&"TH"!=i||(o(c),u.push(c)),c=c.nextSibling;else for(var p=0,g=(u=e.anCells).length;p<g;p++)o(u[p]);var e=e.firstChild?e:e.nTr;return e&&(e=e.getAttribute("id"))&&b(t.rowId)(a,e),{data:a,cells:u}}function St(t,e,n,a){var r,o,i,l,s,u,c=t.aoData[e],f=c._aData,d=[];if(null===c.nTr){for(r=n||v.createElement("tr"),c.nTr=r,c.anCells=d,r._DT_RowIndex=e,vt(t,c),l=0,s=t.aoColumns.length;l<s;l++)i=t.aoColumns[l],(o=(u=!n)?v.createElement(i.sCellType):a[l])||W(t,0,"Incorrect column count",18),o._DT_CellIndex={row:e,column:l},d.push(o),!u&&(!i.mRender&&i.mData===l||P.isPlainObject(i.mData)&&i.mData._===l+".display")||(o.innerHTML=S(t,e,l,"display")),i.sClass&&(o.className+=" "+i.sClass),i.bVisible&&!n?r.appendChild(o):!i.bVisible&&n&&o.parentNode.removeChild(o),i.fnCreatedCell&&i.fnCreatedCell.call(t.oInstance,o,S(t,e,l),f,e,l);R(t,"aoRowCreatedCallback",null,[r,f,e,d])}}function vt(t,e){var n=e.nTr,a=e._aData;n&&((t=t.rowIdFn(a))&&(n.id=t),a.DT_RowClass&&(t=a.DT_RowClass.split(" "),e.__rowc=e.__rowc?z(e.__rowc.concat(t)):t,P(n).removeClass(e.__rowc.join(" ")).addClass(a.DT_RowClass)),a.DT_RowAttr&&P(n).attr(a.DT_RowAttr),a.DT_RowData)&&P(n).data(a.DT_RowData)}function yt(t){var e,n,a,r=t.nTHead,o=t.nTFoot,i=0===P("th, td",r).length,l=t.oClasses,s=t.aoColumns;for(i&&(n=P("<tr/>").appendTo(r)),c=0,f=s.length;c<f;c++)a=s[c],e=P(a.nTh).addClass(a.sClass),i&&e.appendTo(n),t.oFeatures.bSort&&(e.addClass(a.sSortingClass),!1!==a.bSortable)&&(e.attr("tabindex",t.iTabIndex).attr("aria-controls",t.sTableId),ue(t,a.nTh,c)),a.sTitle!=e[0].innerHTML&&e.html(a.sTitle),ve(t,"header")(t,e,a,l);if(i&&wt(t.aoHeader,r),P(r).children("tr").children("th, td").addClass(l.sHeaderTH),P(o).children("tr").children("th, td").addClass(l.sFooterTH),null!==o)for(var u=t.aoFooter[0],c=0,f=u.length;c<f;c++)(a=s[c])?(a.nTf=u[c].cell,a.sClass&&P(a.nTf).addClass(a.sClass)):W(t,0,"Incorrect column count",18)}function Dt(t,e,n){var a,r,o,i,l,s,u,c,f,d=[],h=[],p=t.aoColumns.length;if(e){for(n===H&&(n=!1),a=0,r=e.length;a<r;a++){for(d[a]=e[a].slice(),d[a].nTr=e[a].nTr,o=p-1;0<=o;o--)t.aoColumns[o].bVisible||n||d[a].splice(o,1);h.push([])}for(a=0,r=d.length;a<r;a++){if(u=d[a].nTr)for(;s=u.firstChild;)u.removeChild(s);for(o=0,i=d[a].length;o<i;o++)if(f=c=1,h[a][o]===H){for(u.appendChild(d[a][o].cell),h[a][o]=1;d[a+c]!==H&&d[a][o].cell==d[a+c][o].cell;)h[a+c][o]=1,c++;for(;d[a][o+f]!==H&&d[a][o].cell==d[a][o+f].cell;){for(l=0;l<c;l++)h[a+l][o+f]=1;f++}P(d[a][o].cell).attr("rowspan",c).attr("colspan",f)}}}}function y(t,e){n="ssp"==E(s=t),(l=s.iInitDisplayStart)!==H&&-1!==l&&(s._iDisplayStart=!n&&l>=s.fnRecordsDisplay()?0:l,s.iInitDisplayStart=-1);var n=R(t,"aoPreDrawCallback","preDraw",[t]);if(-1!==P.inArray(!1,n))D(t,!1);else{var a=[],r=0,o=t.asStripeClasses,i=o.length,l=t.oLanguage,s="ssp"==E(t),u=t.aiDisplay,n=t._iDisplayStart,c=t.fnDisplayEnd();if(t.bDrawing=!0,t.bDeferLoading)t.bDeferLoading=!1,t.iDraw++,D(t,!1);else if(s){if(!t.bDestroying&&!e)return void xt(t)}else t.iDraw++;if(0!==u.length)for(var f=s?t.aoData.length:c,d=s?0:n;d<f;d++){var h,p=u[d],g=t.aoData[p],b=(null===g.nTr&&St(t,p),g.nTr);0!==i&&(h=o[r%i],g._sRowStripe!=h)&&(P(b).removeClass(g._sRowStripe).addClass(h),g._sRowStripe=h),R(t,"aoRowCallback",null,[b,g._aData,r,d,p]),a.push(b),r++}else{e=l.sZeroRecords;1==t.iDraw&&"ajax"==E(t)?e=l.sLoadingRecords:l.sEmptyTable&&0===t.fnRecordsTotal()&&(e=l.sEmptyTable),a[0]=P("<tr/>",{class:i?o[0]:""}).append(P("<td />",{valign:"top",colSpan:T(t),class:t.oClasses.sRowEmpty}).html(e))[0]}R(t,"aoHeaderCallback","header",[P(t.nTHead).children("tr")[0],ht(t),n,c,u]),R(t,"aoFooterCallback","footer",[P(t.nTFoot).children("tr")[0],ht(t),n,c,u]);s=P(t.nTBody);s.children().detach(),s.append(P(a)),R(t,"aoDrawCallback","draw",[t]),t.bSorted=!1,t.bFiltered=!1,t.bDrawing=!1}}function u(t,e){var n=t.oFeatures,a=n.bSort,n=n.bFilter;a&&ie(t),n?Rt(t,t.oPreviousSearch):t.aiDisplay=t.aiDisplayMaster.slice(),!0!==e&&(t._iDisplayStart=0),t._drawHold=e,y(t),t._drawHold=!1}function _t(t){for(var e,n,a,r,o,i,l,s=t.oClasses,u=P(t.nTable),u=P("<div/>").insertBefore(u),c=t.oFeatures,f=P("<div/>",{id:t.sTableId+"_wrapper",class:s.sWrapper+(t.nTFoot?"":" "+s.sNoFooter)}),d=(t.nHolding=u[0],t.nTableWrapper=f[0],t.nTableReinsertBefore=t.nTable.nextSibling,t.sDom.split("")),h=0;h<d.length;h++){if(e=null,"<"==(n=d[h])){if(a=P("<div/>")[0],"'"==(r=d[h+1])||'"'==r){for(o="",i=2;d[h+i]!=r;)o+=d[h+i],i++;"H"==o?o=s.sJUIHeader:"F"==o&&(o=s.sJUIFooter),-1!=o.indexOf(".")?(l=o.split("."),a.id=l[0].substr(1,l[0].length-1),a.className=l[1]):"#"==o.charAt(0)?a.id=o.substr(1,o.length-1):a.className=o,h+=i}f.append(a),f=P(a)}else if(">"==n)f=f.parent();else if("l"==n&&c.bPaginate&&c.bLengthChange)e=Gt(t);else if("f"==n&&c.bFilter)e=Lt(t);else if("r"==n&&c.bProcessing)e=Zt(t);else if("t"==n)e=Kt(t);else if("i"==n&&c.bInfo)e=Ut(t);else if("p"==n&&c.bPaginate)e=zt(t);else if(0!==w.ext.feature.length)for(var p=w.ext.feature,g=0,b=p.length;g<b;g++)if(n==p[g].cFeature){e=p[g].fnInit(t);break}e&&((l=t.aanFeatures)[n]||(l[n]=[]),l[n].push(e),f.append(e))}u.replaceWith(f),t.nHolding=null}function wt(t,e){var n,a,r,o,i,l,s,u,c,f,d=P(e).children("tr");for(t.splice(0,t.length),r=0,l=d.length;r<l;r++)t.push([]);for(r=0,l=d.length;r<l;r++)for(a=(n=d[r]).firstChild;a;){if("TD"==a.nodeName.toUpperCase()||"TH"==a.nodeName.toUpperCase())for(u=(u=+a.getAttribute("colspan"))&&0!=u&&1!=u?u:1,c=(c=+a.getAttribute("rowspan"))&&0!=c&&1!=c?c:1,s=function(t,e,n){for(var a=t[e];a[n];)n++;return n}(t,r,0),f=1==u,i=0;i<u;i++)for(o=0;o<c;o++)t[r+o][s+i]={cell:a,unique:f},t[r+o].nTr=n;a=a.nextSibling}}function Ct(t,e,n){var a=[];n||(n=t.aoHeader,e&&wt(n=[],e));for(var r=0,o=n.length;r<o;r++)for(var i=0,l=n[r].length;i<l;i++)!n[r][i].unique||a[i]&&t.bSortCellsTop||(a[i]=n[r][i].cell);return a}function Tt(r,t,n){function e(t){var e=r.jqXHR?r.jqXHR.status:null;(null===t||"number"==typeof e&&204==e)&&Ft(r,t={},[]),(e=t.error||t.sError)&&W(r,0,e),r.json=t,R(r,null,"xhr",[r,t,r.jqXHR]),n(t)}R(r,"aoServerParams","serverParams",[t]),t&&Array.isArray(t)&&(a={},o=/(.*?)\[\]$/,P.each(t,function(t,e){var n=e.name.match(o);n?(n=n[0],a[n]||(a[n]=[]),a[n].push(e.value)):a[e.name]=e.value}),t=a);var a,o,i,l=r.ajax,s=r.oInstance,u=(P.isPlainObject(l)&&l.data&&(u="function"==typeof(i=l.data)?i(t,r):i,t="function"==typeof i&&u?u:P.extend(!0,t,u),delete l.data),{data:t,success:e,dataType:"json",cache:!1,type:r.sServerMethod,error:function(t,e,n){var a=R(r,null,"xhr",[r,null,r.jqXHR]);-1===P.inArray(!0,a)&&("parsererror"==e?W(r,0,"Invalid JSON response",1):4===t.readyState&&W(r,0,"Ajax error",7)),D(r,!1)}});r.oAjaxData=t,R(r,null,"preXhr",[r,t]),r.fnServerData?r.fnServerData.call(s,r.sAjaxSource,P.map(t,function(t,e){return{name:e,value:t}}),e,r):r.sAjaxSource||"string"==typeof l?r.jqXHR=P.ajax(P.extend(u,{url:l||r.sAjaxSource})):"function"==typeof l?r.jqXHR=l.call(s,t,e,r):(r.jqXHR=P.ajax(P.extend(u,l)),l.data=i)}function xt(e){e.iDraw++,D(e,!0);var n=e._drawHold;Tt(e,At(e),function(t){e._drawHold=n,It(e,t),e._drawHold=!1})}function At(t){for(var e,n,a,r=t.aoColumns,o=r.length,i=t.oFeatures,l=t.oPreviousSearch,s=t.aoPreSearchCols,u=[],c=I(t),f=t._iDisplayStart,d=!1!==i.bPaginate?t._iDisplayLength:-1,h=function(t,e){u.push({name:t,value:e})},p=(h("sEcho",t.iDraw),h("iColumns",o),h("sColumns",N(r,"sName").join(",")),h("iDisplayStart",f),h("iDisplayLength",d),{draw:t.iDraw,columns:[],order:[],start:f,length:d,search:{value:l.sSearch,regex:l.bRegex}}),g=0;g<o;g++)n=r[g],a=s[g],e="function"==typeof n.mData?"function":n.mData,p.columns.push({data:e,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:a.sSearch,regex:a.bRegex}}),h("mDataProp_"+g,e),i.bFilter&&(h("sSearch_"+g,a.sSearch),h("bRegex_"+g,a.bRegex),h("bSearchable_"+g,n.bSearchable)),i.bSort&&h("bSortable_"+g,n.bSortable);i.bFilter&&(h("sSearch",l.sSearch),h("bRegex",l.bRegex)),i.bSort&&(P.each(c,function(t,e){p.order.push({column:e.col,dir:e.dir}),h("iSortCol_"+t,e.col),h("sSortDir_"+t,e.dir)}),h("iSortingCols",c.length));f=w.ext.legacy.ajax;return null===f?t.sAjaxSource?u:p:f?u:p}function It(t,n){function e(t,e){return n[t]!==H?n[t]:n[e]}var a=Ft(t,n),r=e("sEcho","draw"),o=e("iTotalRecords","recordsTotal"),i=e("iTotalDisplayRecords","recordsFiltered");if(r!==H){if(+r<t.iDraw)return;t.iDraw=+r}a=a||[],pt(t),t._iRecordsTotal=parseInt(o,10),t._iRecordsDisplay=parseInt(i,10);for(var l=0,s=a.length;l<s;l++)x(t,a[l]);t.aiDisplay=t.aiDisplayMaster.slice(),y(t,!0),t._bInitComplete||qt(t,n),D(t,!1)}function Ft(t,e,n){t=P.isPlainObject(t.ajax)&&t.ajax.dataSrc!==H?t.ajax.dataSrc:t.sAjaxDataProp;if(!n)return"data"===t?e.aaData||e[t]:""!==t?A(t)(e):e;b(t)(e,n)}function Lt(n){function e(t){i.f;var e=this.value||"";o.return&&"Enter"!==t.key||e!=o.sSearch&&(Rt(n,{sSearch:e,bRegex:o.bRegex,bSmart:o.bSmart,bCaseInsensitive:o.bCaseInsensitive,return:o.return}),n._iDisplayStart=0,y(n))}var t=n.oClasses,a=n.sTableId,r=n.oLanguage,o=n.oPreviousSearch,i=n.aanFeatures,l='<input type="search" class="'+t.sFilterInput+'"/>',s=(s=r.sSearch).match(/_INPUT_/)?s.replace("_INPUT_",l):s+l,l=P("<div/>",{id:i.f?null:a+"_filter",class:t.sFilter}).append(P("<label/>").append(s)),t=null!==n.searchDelay?n.searchDelay:"ssp"===E(n)?400:0,u=P("input",l).val(o.sSearch).attr("placeholder",r.sSearchPlaceholder).on("keyup.DT search.DT input.DT paste.DT cut.DT",t?ne(e,t):e).on("mouseup.DT",function(t){setTimeout(function(){e.call(u[0],t)},10)}).on("keypress.DT",function(t){if(13==t.keyCode)return!1}).attr("aria-controls",a);return P(n.nTable).on("search.dt.DT",function(t,e){if(n===e)try{u[0]!==v.activeElement&&u.val(o.sSearch)}catch(t){}}),l[0]}function Rt(t,e,n){function a(t){o.sSearch=t.sSearch,o.bRegex=t.bRegex,o.bSmart=t.bSmart,o.bCaseInsensitive=t.bCaseInsensitive,o.return=t.return}function r(t){return t.bEscapeRegex!==H?!t.bEscapeRegex:t.bRegex}var o=t.oPreviousSearch,i=t.aoPreSearchCols;if(lt(t),"ssp"!=E(t)){Ht(t,e.sSearch,n,r(e),e.bSmart,e.bCaseInsensitive),a(e);for(var l=0;l<i.length;l++)jt(t,i[l].sSearch,l,r(i[l]),i[l].bSmart,i[l].bCaseInsensitive);Pt(t)}else a(e);t.bFiltered=!0,R(t,null,"search",[t])}function Pt(t){for(var e,n,a=w.ext.search,r=t.aiDisplay,o=0,i=a.length;o<i;o++){for(var l=[],s=0,u=r.length;s<u;s++)n=r[s],e=t.aoData[n],a[o](t,e._aFilterData,n,e._aData,s)&&l.push(n);r.length=0,P.merge(r,l)}}function jt(t,e,n,a,r,o){if(""!==e){for(var i,l=[],s=t.aiDisplay,u=Nt(e,a,r,o),c=0;c<s.length;c++)i=t.aoData[s[c]]._aFilterData[n],u.test(i)&&l.push(s[c]);t.aiDisplay=l}}function Ht(t,e,n,a,r,o){var i,l,s,u=Nt(e,a,r,o),r=t.oPreviousSearch.sSearch,o=t.aiDisplayMaster,c=[];if(0!==w.ext.search.length&&(n=!0),l=Wt(t),e.length<=0)t.aiDisplay=o.slice();else{for((l||n||a||r.length>e.length||0!==e.indexOf(r)||t.bSorted)&&(t.aiDisplay=o.slice()),i=t.aiDisplay,s=0;s<i.length;s++)u.test(t.aoData[i[s]]._sFilterRow)&&c.push(i[s]);t.aiDisplay=c}}function Nt(t,e,n,a){return t=e?t:Ot(t),n&&(t="^(?=.*?"+P.map(t.match(/["\u201C][^"\u201D]+["\u201D]|[^ ]+/g)||[""],function(t){var e;return'"'===t.charAt(0)?t=(e=t.match(/^"(.*)"$/))?e[1]:t:"“"===t.charAt(0)&&(t=(e=t.match(/^\u201C(.*)\u201D$/))?e[1]:t),t.replace('"',"")}).join(")(?=.*?")+").*$"),new RegExp(t,a?"i":"")}var Ot=w.util.escapeRegex,kt=P("<div>")[0],Mt=kt.textContent!==H;function Wt(t){for(var e,n,a,r,o,i=t.aoColumns,l=!1,s=0,u=t.aoData.length;s<u;s++)if(!(o=t.aoData[s])._aFilterData){for(a=[],e=0,n=i.length;e<n;e++)i[e].bSearchable?"string"!=typeof(r=null===(r=S(t,s,e,"filter"))?"":r)&&r.toString&&(r=r.toString()):r="",r.indexOf&&-1!==r.indexOf("&")&&(kt.innerHTML=r,r=Mt?kt.textContent:kt.innerText),r.replace&&(r=r.replace(/[\r\n\u2028]/g,"")),a.push(r);o._aFilterData=a,o._sFilterRow=a.join(" "),l=!0}return l}function Et(t){return{search:t.sSearch,smart:t.bSmart,regex:t.bRegex,caseInsensitive:t.bCaseInsensitive}}function Bt(t){return{sSearch:t.search,bSmart:t.smart,bRegex:t.regex,bCaseInsensitive:t.caseInsensitive}}function Ut(t){var e=t.sTableId,n=t.aanFeatures.i,a=P("<div/>",{class:t.oClasses.sInfo,id:n?null:e+"_info"});return n||(t.aoDrawCallback.push({fn:Vt,sName:"information"}),a.attr("role","status").attr("aria-live","polite"),P(t.nTable).attr("aria-describedby",e+"_info")),a[0]}function Vt(t){var e,n,a,r,o,i,l=t.aanFeatures.i;0!==l.length&&(i=t.oLanguage,e=t._iDisplayStart+1,n=t.fnDisplayEnd(),a=t.fnRecordsTotal(),o=(r=t.fnRecordsDisplay())?i.sInfo:i.sInfoEmpty,r!==a&&(o+=" "+i.sInfoFiltered),o=Xt(t,o+=i.sInfoPostFix),null!==(i=i.fnInfoCallback)&&(o=i.call(t.oInstance,t,e,n,a,r,o)),P(l).html(o))}function Xt(t,e){var n=t.fnFormatNumber,a=t._iDisplayStart+1,r=t._iDisplayLength,o=t.fnRecordsDisplay(),i=-1===r;return e.replace(/_START_/g,n.call(t,a)).replace(/_END_/g,n.call(t,t.fnDisplayEnd())).replace(/_MAX_/g,n.call(t,t.fnRecordsTotal())).replace(/_TOTAL_/g,n.call(t,o)).replace(/_PAGE_/g,n.call(t,i?1:Math.ceil(a/r))).replace(/_PAGES_/g,n.call(t,i?1:Math.ceil(o/r)))}function Jt(n){var a,t,e,r=n.iInitDisplayStart,o=n.aoColumns,i=n.oFeatures,l=n.bDeferLoading;if(n.bInitialised){for(_t(n),yt(n),Dt(n,n.aoHeader),Dt(n,n.aoFooter),D(n,!0),i.bAutoWidth&&ee(n),a=0,t=o.length;a<t;a++)(e=o[a]).sWidth&&(e.nTh.style.width=M(e.sWidth));R(n,null,"preInit",[n]),u(n);i=E(n);"ssp"==i&&!l||("ajax"==i?Tt(n,[],function(t){var e=Ft(n,t);for(a=0;a<e.length;a++)x(n,e[a]);n.iInitDisplayStart=r,u(n),D(n,!1),qt(n,t)}):(D(n,!1),qt(n)))}else setTimeout(function(){Jt(n)},200)}function qt(t,e){t._bInitComplete=!0,(e||t.oInit.aaData)&&O(t),R(t,null,"plugin-init",[t,e]),R(t,"aoInitComplete","init",[t,e])}function $t(t,e){e=parseInt(e,10);t._iDisplayLength=e,Se(t),R(t,null,"length",[t,e])}function Gt(a){for(var t=a.oClasses,e=a.sTableId,n=a.aLengthMenu,r=Array.isArray(n[0]),o=r?n[0]:n,i=r?n[1]:n,l=P("<select/>",{name:e+"_length","aria-controls":e,class:t.sLengthSelect}),s=0,u=o.length;s<u;s++)l[0][s]=new Option("number"==typeof i[s]?a.fnFormatNumber(i[s]):i[s],o[s]);var c=P("<div><label/></div>").addClass(t.sLength);return a.aanFeatures.l||(c[0].id=e+"_length"),c.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",l[0].outerHTML)),P("select",c).val(a._iDisplayLength).on("change.DT",function(t){$t(a,P(this).val()),y(a)}),P(a.nTable).on("length.dt.DT",function(t,e,n){a===e&&P("select",c).val(n)}),c[0]}function zt(t){function c(t){y(t)}var e=t.sPaginationType,f=w.ext.pager[e],d="function"==typeof f,e=P("<div/>").addClass(t.oClasses.sPaging+e)[0],h=t.aanFeatures;return d||f.fnInit(t,e,c),h.p||(e.id=t.sTableId+"_paginate",t.aoDrawCallback.push({fn:function(t){if(d)for(var e=t._iDisplayStart,n=t._iDisplayLength,a=t.fnRecordsDisplay(),r=-1===n,o=r?0:Math.ceil(e/n),i=r?1:Math.ceil(a/n),l=f(o,i),s=0,u=h.p.length;s<u;s++)ve(t,"pageButton")(t,h.p[s],s,l,o,i);else f.fnUpdate(t,c)},sName:"pagination"})),e}function Yt(t,e,n){var a=t._iDisplayStart,r=t._iDisplayLength,o=t.fnRecordsDisplay(),o=(0===o||-1===r?a=0:"number"==typeof e?o<(a=e*r)&&(a=0):"first"==e?a=0:"previous"==e?(a=0<=r?a-r:0)<0&&(a=0):"next"==e?a+r<o&&(a+=r):"last"==e?a=Math.floor((o-1)/r)*r:W(t,0,"Unknown paging action: "+e,5),t._iDisplayStart!==a);return t._iDisplayStart=a,o?(R(t,null,"page",[t]),n&&y(t)):R(t,null,"page-nc",[t]),o}function Zt(t){return P("<div/>",{id:t.aanFeatures.r?null:t.sTableId+"_processing",class:t.oClasses.sProcessing,role:"status"}).html(t.oLanguage.sProcessing).append("<div><div></div><div></div><div></div><div></div></div>").insertBefore(t.nTable)[0]}function D(t,e){t.oFeatures.bProcessing&&P(t.aanFeatures.r).css("display",e?"block":"none"),R(t,null,"processing",[t,e])}function Kt(t){var e,n,a,r,o,i,l,s,u,c,f,d,h=P(t.nTable),p=t.oScroll;return""===p.sX&&""===p.sY?t.nTable:(e=p.sX,n=p.sY,a=t.oClasses,o=(r=h.children("caption")).length?r[0]._captionSide:null,s=P(h[0].cloneNode(!1)),i=P(h[0].cloneNode(!1)),u=function(t){return t?M(t):null},(l=h.children("tfoot")).length||(l=null),s=P(f="<div/>",{class:a.sScrollWrapper}).append(P(f,{class:a.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:e?u(e):"100%"}).append(P(f,{class:a.sScrollHeadInner}).css({"box-sizing":"content-box",width:p.sXInner||"100%"}).append(s.removeAttr("id").css("margin-left",0).append("top"===o?r:null).append(h.children("thead"))))).append(P(f,{class:a.sScrollBody}).css({position:"relative",overflow:"auto",width:u(e)}).append(h)),l&&s.append(P(f,{class:a.sScrollFoot}).css({overflow:"hidden",border:0,width:e?u(e):"100%"}).append(P(f,{class:a.sScrollFootInner}).append(i.removeAttr("id").css("margin-left",0).append("bottom"===o?r:null).append(h.children("tfoot"))))),u=s.children(),c=u[0],f=u[1],d=l?u[2]:null,e&&P(f).on("scroll.DT",function(t){var e=this.scrollLeft;c.scrollLeft=e,l&&(d.scrollLeft=e)}),P(f).css("max-height",n),p.bCollapse||P(f).css("height",n),t.nScrollHead=c,t.nScrollBody=f,t.nScrollFoot=d,t.aoDrawCallback.push({fn:Qt,sName:"scrolling"}),s[0])}function Qt(n){function t(t){(t=t.style).paddingTop="0",t.paddingBottom="0",t.borderTopWidth="0",t.borderBottomWidth="0",t.height=0}var e,a,r,o,i,l=n.oScroll,s=l.sX,u=l.sXInner,c=l.sY,l=l.iBarWidth,f=P(n.nScrollHead),d=f[0].style,h=f.children("div"),p=h[0].style,h=h.children("table"),g=n.nScrollBody,b=P(g),m=g.style,S=P(n.nScrollFoot).children("div"),v=S.children("table"),y=P(n.nTHead),D=P(n.nTable),_=D[0],w=_.style,C=n.nTFoot?P(n.nTFoot):null,T=n.oBrowser,x=T.bScrollOversize,A=(N(n.aoColumns,"nTh"),[]),I=[],F=[],L=[],R=g.scrollHeight>g.clientHeight;n.scrollBarVis!==R&&n.scrollBarVis!==H?(n.scrollBarVis=R,O(n)):(n.scrollBarVis=R,D.children("thead, tfoot").remove(),C&&(R=C.clone().prependTo(D),i=C.find("tr"),a=R.find("tr"),R.find("[id]").removeAttr("id")),R=y.clone().prependTo(D),y=y.find("tr"),e=R.find("tr"),R.find("th, td").removeAttr("tabindex"),R.find("[id]").removeAttr("id"),s||(m.width="100%",f[0].style.width="100%"),P.each(Ct(n,R),function(t,e){r=rt(n,t),e.style.width=n.aoColumns[r].sWidth}),C&&k(function(t){t.style.width=""},a),f=D.outerWidth(),""===s?(w.width="100%",x&&(D.find("tbody").height()>g.offsetHeight||"scroll"==b.css("overflow-y"))&&(w.width=M(D.outerWidth()-l)),f=D.outerWidth()):""!==u&&(w.width=M(u),f=D.outerWidth()),k(t,e),k(function(t){var e=j.getComputedStyle?j.getComputedStyle(t).width:M(P(t).width());F.push(t.innerHTML),A.push(e)},e),k(function(t,e){t.style.width=A[e]},y),P(e).css("height",0),C&&(k(t,a),k(function(t){L.push(t.innerHTML),I.push(M(P(t).css("width")))},a),k(function(t,e){t.style.width=I[e]},i),P(a).height(0)),k(function(t,e){t.innerHTML='<div class="dataTables_sizing">'+F[e]+"</div>",t.childNodes[0].style.height="0",t.childNodes[0].style.overflow="hidden",t.style.width=A[e]},e),C&&k(function(t,e){t.innerHTML='<div class="dataTables_sizing">'+L[e]+"</div>",t.childNodes[0].style.height="0",t.childNodes[0].style.overflow="hidden",t.style.width=I[e]},a),Math.round(D.outerWidth())<Math.round(f)?(o=g.scrollHeight>g.offsetHeight||"scroll"==b.css("overflow-y")?f+l:f,x&&(g.scrollHeight>g.offsetHeight||"scroll"==b.css("overflow-y"))&&(w.width=M(o-l)),""!==s&&""===u||W(n,1,"Possible column misalignment",6)):o="100%",m.width=M(o),d.width=M(o),C&&(n.nScrollFoot.style.width=M(o)),c||x&&(m.height=M(_.offsetHeight+l)),R=D.outerWidth(),h[0].style.width=M(R),p.width=M(R),y=D.height()>g.clientHeight||"scroll"==b.css("overflow-y"),p[i="padding"+(T.bScrollbarLeft?"Left":"Right")]=y?l+"px":"0px",C&&(v[0].style.width=M(R),S[0].style.width=M(R),S[0].style[i]=y?l+"px":"0px"),D.children("colgroup").insertBefore(D.children("thead")),b.trigger("scroll"),!n.bSorted&&!n.bFiltered||n._drawHold||(g.scrollTop=0))}function k(t,e,n){for(var a,r,o=0,i=0,l=e.length;i<l;){for(a=e[i].firstChild,r=n?n[i].firstChild:null;a;)1===a.nodeType&&(n?t(a,r,o):t(a,o),o++),a=a.nextSibling,r=n?r.nextSibling:null;i++}}var te=/<.*?>/g;function ee(t){var e,n,a=t.nTable,r=t.aoColumns,o=t.oScroll,i=o.sY,l=o.sX,o=o.sXInner,s=r.length,u=it(t,"bVisible"),c=P("th",t.nTHead),f=a.getAttribute("width"),d=a.parentNode,h=!1,p=t.oBrowser,g=p.bScrollOversize,b=a.style.width,m=(b&&-1!==b.indexOf("%")&&(f=b),ae(N(r,"sWidthOrig"),d));for(_=0;_<u.length;_++)null!==(e=r[u[_]]).sWidth&&(e.sWidth=m[_],h=!0);if(g||!h&&!l&&!i&&s==T(t)&&s==c.length)for(_=0;_<s;_++){var S=rt(t,_);null!==S&&(r[S].sWidth=M(c.eq(_).width()))}else{var b=P(a).clone().css("visibility","hidden").removeAttr("id"),v=(b.find("tbody tr").remove(),P("<tr/>").appendTo(b.find("tbody")));for(b.find("thead, tfoot").remove(),b.append(P(t.nTHead).clone()).append(P(t.nTFoot).clone()),b.find("tfoot th, tfoot td").css("width",""),c=Ct(t,b.find("thead")[0]),_=0;_<u.length;_++)e=r[u[_]],c[_].style.width=null!==e.sWidthOrig&&""!==e.sWidthOrig?M(e.sWidthOrig):"",e.sWidthOrig&&l&&P(c[_]).append(P("<div/>").css({width:e.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(t.aoData.length)for(_=0;_<u.length;_++)e=r[n=u[_]],P(re(t,n)).clone(!1).append(e.sContentPadding).appendTo(v);P("[name]",b).removeAttr("name");for(var y=P("<div/>").css(l||i?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(b).appendTo(d),D=(l&&o?b.width(o):l?(b.css("width","auto"),b.removeAttr("width"),b.width()<d.clientWidth&&f&&b.width(d.clientWidth)):i?b.width(d.clientWidth):f&&b.width(f),0),_=0;_<u.length;_++){var w=P(c[_]),C=w.outerWidth()-w.width(),w=p.bBounding?Math.ceil(c[_].getBoundingClientRect().width):w.outerWidth();D+=w,r[u[_]].sWidth=M(w-C)}a.style.width=M(D),y.remove()}f&&(a.style.width=M(f)),!f&&!l||t._reszEvt||(o=function(){P(j).on("resize.DT-"+t.sInstance,ne(function(){O(t)}))},g?setTimeout(o,1e3):o(),t._reszEvt=!0)}var ne=w.util.throttle;function ae(t,e){for(var n=[],a=[],r=0;r<t.length;r++)t[r]?n.push(P("<div/>").css("width",M(t[r])).appendTo(e||v.body)):n.push(null);for(r=0;r<t.length;r++)a.push(n[r]?n[r][0].offsetWidth:null);return P(n).remove(),a}function re(t,e){var n,a=oe(t,e);return a<0?null:(n=t.aoData[a]).nTr?n.anCells[e]:P("<td/>").html(S(t,a,e,"display"))[0]}function oe(t,e){for(var n,a=-1,r=-1,o=0,i=t.aoData.length;o<i;o++)(n=(n=(n=S(t,o,e,"display")+"").replace(te,"")).replace(/&nbsp;/g," ")).length>a&&(a=n.length,r=o);return r}function M(t){return null===t?"0px":"number"==typeof t?t<0?"0px":t+"px":t.match(/\d$/)?t+"px":t}function I(t){function e(t){t.length&&!Array.isArray(t[0])?h.push(t):P.merge(h,t)}var n,a,r,o,i,l,s,u=[],c=t.aoColumns,f=t.aaSortingFixed,d=P.isPlainObject(f),h=[];for(Array.isArray(f)&&e(f),d&&f.pre&&e(f.pre),e(t.aaSorting),d&&f.post&&e(f.post),n=0;n<h.length;n++)for(r=(o=c[s=h[n][a=0]].aDataSort).length;a<r;a++)l=c[i=o[a]].sType||"string",h[n]._idx===H&&(h[n]._idx=P.inArray(h[n][1],c[i].asSorting)),u.push({src:s,col:i,dir:h[n][1],index:h[n]._idx,type:l,formatter:w.ext.type.order[l+"-pre"]});return u}function ie(t){var e,n,a,r,c,f=[],u=w.ext.type.order,d=t.aoData,o=(t.aoColumns,0),i=t.aiDisplayMaster;for(lt(t),e=0,n=(c=I(t)).length;e<n;e++)(r=c[e]).formatter&&o++,fe(t,r.col);if("ssp"!=E(t)&&0!==c.length){for(e=0,a=i.length;e<a;e++)f[i[e]]=e;o===c.length?i.sort(function(t,e){for(var n,a,r,o,i=c.length,l=d[t]._aSortData,s=d[e]._aSortData,u=0;u<i;u++)if(0!=(r=(n=l[(o=c[u]).col])<(a=s[o.col])?-1:a<n?1:0))return"asc"===o.dir?r:-r;return(n=f[t])<(a=f[e])?-1:a<n?1:0}):i.sort(function(t,e){for(var n,a,r,o=c.length,i=d[t]._aSortData,l=d[e]._aSortData,s=0;s<o;s++)if(n=i[(r=c[s]).col],a=l[r.col],0!==(r=(u[r.type+"-"+r.dir]||u["string-"+r.dir])(n,a)))return r;return(n=f[t])<(a=f[e])?-1:a<n?1:0})}t.bSorted=!0}function le(t){for(var e=t.aoColumns,n=I(t),a=t.oLanguage.oAria,r=0,o=e.length;r<o;r++){var i=e[r],l=i.asSorting,s=i.ariaTitle||i.sTitle.replace(/<.*?>/g,""),u=i.nTh;u.removeAttribute("aria-sort"),i=i.bSortable?s+("asc"===(0<n.length&&n[0].col==r&&(u.setAttribute("aria-sort","asc"==n[0].dir?"ascending":"descending"),l[n[0].index+1])||l[0])?a.sSortAscending:a.sSortDescending):s,u.setAttribute("aria-label",i)}}function se(t,e,n,a){function r(t,e){var n=t._idx;return(n=n===H?P.inArray(t[1],s):n)+1<s.length?n+1:e?null:0}var o,i=t.aoColumns[e],l=t.aaSorting,s=i.asSorting;"number"==typeof l[0]&&(l=t.aaSorting=[l]),n&&t.oFeatures.bSortMulti?-1!==(i=P.inArray(e,N(l,"0")))?null===(o=null===(o=r(l[i],!0))&&1===l.length?0:o)?l.splice(i,1):(l[i][1]=s[o],l[i]._idx=o):(l.push([e,s[0],0]),l[l.length-1]._idx=0):l.length&&l[0][0]==e?(o=r(l[0]),l.length=1,l[0][1]=s[o],l[0]._idx=o):(l.length=0,l.push([e,s[0]]),l[0]._idx=0),u(t),"function"==typeof a&&a(t)}function ue(e,t,n,a){var r=e.aoColumns[n];me(t,{},function(t){!1!==r.bSortable&&(e.oFeatures.bProcessing?(D(e,!0),setTimeout(function(){se(e,n,t.shiftKey,a),"ssp"!==E(e)&&D(e,!1)},0)):se(e,n,t.shiftKey,a))})}function ce(t){var e,n,a,r=t.aLastSort,o=t.oClasses.sSortColumn,i=I(t),l=t.oFeatures;if(l.bSort&&l.bSortClasses){for(e=0,n=r.length;e<n;e++)a=r[e].src,P(N(t.aoData,"anCells",a)).removeClass(o+(e<2?e+1:3));for(e=0,n=i.length;e<n;e++)a=i[e].src,P(N(t.aoData,"anCells",a)).addClass(o+(e<2?e+1:3))}t.aLastSort=i}function fe(t,e){for(var n,a,r,o=t.aoColumns[e],i=w.ext.order[o.sSortDataType],l=(i&&(n=i.call(t.oInstance,t,e,ot(t,e))),w.ext.type.order[o.sType+"-pre"]),s=0,u=t.aoData.length;s<u;s++)(a=t.aoData[s])._aSortData||(a._aSortData=[]),a._aSortData[e]&&!i||(r=i?n[s]:S(t,s,e,"sort"),a._aSortData[e]=l?l(r):r)}function de(n){var t;n._bLoadingState||(t={time:+new Date,start:n._iDisplayStart,length:n._iDisplayLength,order:P.extend(!0,[],n.aaSorting),search:Et(n.oPreviousSearch),columns:P.map(n.aoColumns,function(t,e){return{visible:t.bVisible,search:Et(n.aoPreSearchCols[e])}})},n.oSavedState=t,R(n,"aoStateSaveParams","stateSaveParams",[n,t]),n.oFeatures.bStateSave&&!n.bDestroying&&n.fnStateSaveCallback.call(n.oInstance,n,t))}function he(e,t,n){var a;if(e.oFeatures.bStateSave)return(a=e.fnStateLoadCallback.call(e.oInstance,e,function(t){pe(e,t,n)}))!==H&&pe(e,a,n),!0;n()}function pe(n,t,e){var a,r,o=n.aoColumns,i=(n._bLoadingState=!0,n._bInitComplete?new w.Api(n):null);if(t&&t.time){var l=R(n,"aoStateLoadParams","stateLoadParams",[n,t]);if(-1!==P.inArray(!1,l))n._bLoadingState=!1;else{l=n.iStateDuration;if(0<l&&t.time<+new Date-1e3*l)n._bLoadingState=!1;else if(t.columns&&o.length!==t.columns.length)n._bLoadingState=!1;else{if(n.oLoadedState=P.extend(!0,{},t),t.length!==H&&(i?i.page.len(t.length):n._iDisplayLength=t.length),t.start!==H&&(null===i?(n._iDisplayStart=t.start,n.iInitDisplayStart=t.start):Yt(n,t.start/n._iDisplayLength)),t.order!==H&&(n.aaSorting=[],P.each(t.order,function(t,e){n.aaSorting.push(e[0]>=o.length?[0,e[1]]:e)})),t.search!==H&&P.extend(n.oPreviousSearch,Bt(t.search)),t.columns){for(a=0,r=t.columns.length;a<r;a++){var s=t.columns[a];s.visible!==H&&(i?i.column(a).visible(s.visible,!1):o[a].bVisible=s.visible),s.search!==H&&P.extend(n.aoPreSearchCols[a],Bt(s.search))}i&&i.columns.adjust()}n._bLoadingState=!1,R(n,"aoStateLoaded","stateLoaded",[n,t])}}}else n._bLoadingState=!1;e()}function ge(t){var e=w.settings,t=P.inArray(t,N(e,"nTable"));return-1!==t?e[t]:null}function W(t,e,n,a){if(n="DataTables warning: "+(t?"table id="+t.sTableId+" - ":"")+n,a&&(n+=". For more information about this error, please see https://datatables.net/tn/"+a),e)j.console&&console.log&&console.log(n);else{e=w.ext,e=e.sErrMode||e.errMode;if(t&&R(t,null,"error",[t,a,n]),"alert"==e)alert(n);else{if("throw"==e)throw new Error(n);"function"==typeof e&&e(t,a,n)}}}function F(n,a,t,e){Array.isArray(t)?P.each(t,function(t,e){Array.isArray(e)?F(n,a,e[0],e[1]):F(n,a,e)}):(e===H&&(e=t),a[t]!==H&&(n[e]=a[t]))}function be(t,e,n){var a,r;for(r in e)e.hasOwnProperty(r)&&(a=e[r],P.isPlainObject(a)?(P.isPlainObject(t[r])||(t[r]={}),P.extend(!0,t[r],a)):n&&"data"!==r&&"aaData"!==r&&Array.isArray(a)?t[r]=a.slice():t[r]=a);return t}function me(e,t,n){P(e).on("click.DT",t,function(t){P(e).trigger("blur"),n(t)}).on("keypress.DT",t,function(t){13===t.which&&(t.preventDefault(),n(t))}).on("selectstart.DT",function(){return!1})}function L(t,e,n,a){n&&t[e].push({fn:n,sName:a})}function R(n,t,e,a){var r=[];return t&&(r=P.map(n[t].slice().reverse(),function(t,e){return t.fn.apply(n.oInstance,a)})),null!==e&&(t=P.Event(e+".dt"),(e=P(n.nTable)).trigger(t,a),0===e.parents("body").length&&P("body").trigger(t,a),r.push(t.result)),r}function Se(t){var e=t._iDisplayStart,n=t.fnDisplayEnd(),a=t._iDisplayLength;n<=e&&(e=n-a),e-=e%a,t._iDisplayStart=e=-1===a||e<0?0:e}function ve(t,e){var t=t.renderer,n=w.ext.renderer[e];return P.isPlainObject(t)&&t[e]?n[t[e]]||n._:"string"==typeof t&&n[t]||n._}function E(t){return t.oFeatures.bServerSide?"ssp":t.ajax||t.sAjaxSource?"ajax":"dom"}function ye(t,n){var a;return Array.isArray(t)?P.map(t,function(t){return ye(t,n)}):"number"==typeof t?[n[t]]:(a=P.map(n,function(t,e){return t.nTable}),P(a).filter(t).map(function(t){var e=P.inArray(this,a);return n[e]}).toArray())}function De(r,o,t){var e,n;t&&(e=new B(r)).one("draw",function(){t(e.ajax.json())}),"ssp"==E(r)?u(r,o):(D(r,!0),(n=r.jqXHR)&&4!==n.readyState&&n.abort(),Tt(r,[],function(t){pt(r);for(var e=Ft(r,t),n=0,a=e.length;n<a;n++)x(r,e[n]);u(r,o),D(r,!1)}))}function _e(t,e,n,a,r){for(var o,i,l,s,u=[],c=typeof e,f=0,d=(e=e&&"string"!=c&&"function"!=c&&e.length!==H?e:[e]).length;f<d;f++)for(l=0,s=(i=e[f]&&e[f].split&&!e[f].match(/[\[\(:]/)?e[f].split(","):[e[f]]).length;l<s;l++)(o=n("string"==typeof i[l]?i[l].trim():i[l]))&&o.length&&(u=u.concat(o));var h=p.selector[t];if(h.length)for(f=0,d=h.length;f<d;f++)u=h[f](a,r,u);return z(u)}function we(t){return(t=t||{}).filter&&t.search===H&&(t.search=t.filter),P.extend({search:"none",order:"current",page:"all"},t)}function Ce(t){for(var e=0,n=t.length;e<n;e++)if(0<t[e].length)return t[0]=t[e],t[0].length=1,t.length=1,t.context=[t.context[e]],t;return t.length=0,t}function Te(o,t,e,n){function i(t,e){var n;if(Array.isArray(t)||t instanceof P)for(var a=0,r=t.length;a<r;a++)i(t[a],e);else t.nodeName&&"tr"===t.nodeName.toLowerCase()?l.push(t):(n=P("<tr><td></td></tr>").addClass(e),P("td",n).addClass(e).html(t)[0].colSpan=T(o),l.push(n[0]))}var l=[];i(e,n),t._details&&t._details.detach(),t._details=P(l),t._detailsShow&&t._details.insertAfter(t.nTr)}function xe(t,e){var n=t.context;if(n.length&&t.length){var a=n[0].aoData[t[0]];if(a._details){(a._detailsShow=e)?(a._details.insertAfter(a.nTr),P(a.nTr).addClass("dt-hasChild")):(a._details.detach(),P(a.nTr).removeClass("dt-hasChild")),R(n[0],null,"childRow",[e,t.row(t[0])]);var s=n[0],r=new B(s),a=".dt.DT_details",e="draw"+a,t="column-sizing"+a,a="destroy"+a,u=s.aoData;if(r.off(e+" "+t+" "+a),N(u,"_details").length>0){r.on(e,function(t,e){if(s!==e)return;r.rows({page:"current"}).eq(0).each(function(t){var e=u[t];if(e._detailsShow)e._details.insertAfter(e.nTr)})});r.on(t,function(t,e,n,a){if(s!==e)return;var r,o=T(e);for(var i=0,l=u.length;i<l;i++){r=u[i];if(r._details)r._details.each(function(){var t=P(this).children("td");if(t.length==1)t.attr("colspan",o)})}});r.on(a,function(t,e){if(s!==e)return;for(var n=0,a=u.length;n<a;n++)if(u[n]._details)Re(r,n)})}Le(n)}}}function Ae(t,e,n,a,r){for(var o=[],i=0,l=r.length;i<l;i++)o.push(S(t,r[i],e));return o}var Ie=[],o=Array.prototype,B=function(t,e){if(!(this instanceof B))return new B(t,e);function n(t){var e,n,a,r;t=t,a=w.settings,r=P.map(a,function(t,e){return t.nTable}),(t=t?t.nTable&&t.oApi?[t]:t.nodeName&&"table"===t.nodeName.toLowerCase()?-1!==(e=P.inArray(t,r))?[a[e]]:null:t&&"function"==typeof t.settings?t.settings().toArray():("string"==typeof t?n=P(t):t instanceof P&&(n=t),n?n.map(function(t){return-1!==(e=P.inArray(this,r))?a[e]:null}).toArray():void 0):[])&&o.push.apply(o,t)}var o=[];if(Array.isArray(t))for(var a=0,r=t.length;a<r;a++)n(t[a]);else n(t);this.context=z(o),e&&P.merge(this,e),this.selector={rows:null,cols:null,opts:null},B.extend(this,this,Ie)},Fe=(w.Api=B,P.extend(B.prototype,{any:function(){return 0!==this.count()},concat:o.concat,context:[],count:function(){return this.flatten().length},each:function(t){for(var e=0,n=this.length;e<n;e++)t.call(this,this[e],e,this);return this},eq:function(t){var e=this.context;return e.length>t?new B(e[t],this[t]):null},filter:function(t){var e=[];if(o.filter)e=o.filter.call(this,t,this);else for(var n=0,a=this.length;n<a;n++)t.call(this,this[n],n,this)&&e.push(this[n]);return new B(this.context,e)},flatten:function(){var t=[];return new B(this.context,t.concat.apply(t,this.toArray()))},join:o.join,indexOf:o.indexOf||function(t,e){for(var n=e||0,a=this.length;n<a;n++)if(this[n]===t)return n;return-1},iterator:function(t,e,n,a){var r,o,i,l,s,u,c,f,d=[],h=this.context,p=this.selector;for("string"==typeof t&&(a=n,n=e,e=t,t=!1),o=0,i=h.length;o<i;o++){var g=new B(h[o]);if("table"===e)(r=n.call(g,h[o],o))!==H&&d.push(r);else if("columns"===e||"rows"===e)(r=n.call(g,h[o],this[o],o))!==H&&d.push(r);else if("column"===e||"column-rows"===e||"row"===e||"cell"===e)for(c=this[o],"column-rows"===e&&(u=Fe(h[o],p.opts)),l=0,s=c.length;l<s;l++)f=c[l],(r="cell"===e?n.call(g,h[o],f.row,f.column,o,l):n.call(g,h[o],f,o,l,u))!==H&&d.push(r)}return d.length||a?((t=(a=new B(h,t?d.concat.apply([],d):d)).selector).rows=p.rows,t.cols=p.cols,t.opts=p.opts,a):this},lastIndexOf:o.lastIndexOf||function(t,e){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(t){var e=[];if(o.map)e=o.map.call(this,t,this);else for(var n=0,a=this.length;n<a;n++)e.push(t.call(this,this[n],n));return new B(this.context,e)},pluck:function(t){var e=w.util.get(t);return this.map(function(t){return e(t)})},pop:o.pop,push:o.push,reduce:o.reduce||function(t,e){return et(this,t,e,0,this.length,1)},reduceRight:o.reduceRight||function(t,e){return et(this,t,e,this.length-1,-1,-1)},reverse:o.reverse,selector:null,shift:o.shift,slice:function(){return new B(this.context,this)},sort:o.sort,splice:o.splice,toArray:function(){return o.slice.call(this)},to$:function(){return P(this)},toJQuery:function(){return P(this)},unique:function(){return new B(this.context,z(this))},unshift:o.unshift}),B.extend=function(t,e,n){if(n.length&&e&&(e instanceof B||e.__dt_wrapper))for(var a,r=0,o=n.length;r<o;r++)e[(a=n[r]).name]="function"===a.type?function(e,n,a){return function(){var t=n.apply(e,arguments);return B.extend(t,t,a.methodExt),t}}(t,a.val,a):"object"===a.type?{}:a.val,e[a.name].__dt_wrapper=!0,B.extend(t,e[a.name],a.propExt)},B.register=e=function(t,e){if(Array.isArray(t))for(var n=0,a=t.length;n<a;n++)B.register(t[n],e);else for(var r=t.split("."),o=Ie,i=0,l=r.length;i<l;i++){var s,u,c=function(t,e){for(var n=0,a=t.length;n<a;n++)if(t[n].name===e)return t[n];return null}(o,u=(s=-1!==r[i].indexOf("()"))?r[i].replace("()",""):r[i]);c||o.push(c={name:u,val:{},methodExt:[],propExt:[],type:"object"}),i===l-1?(c.val=e,c.type="function"==typeof e?"function":P.isPlainObject(e)?"object":"other"):o=s?c.methodExt:c.propExt}},B.registerPlural=t=function(t,e,n){B.register(t,n),B.register(e,function(){var t=n.apply(this,arguments);return t===this?this:t instanceof B?t.length?Array.isArray(t[0])?new B(t.context,t[0]):t[0]:H:t})},e("tables()",function(t){return t!==H&&null!==t?new B(ye(t,this.context)):this}),e("table()",function(t){var t=this.tables(t),e=t.context;return e.length?new B(e[0]):t}),t("tables().nodes()","table().node()",function(){return this.iterator("table",function(t){return t.nTable},1)}),t("tables().body()","table().body()",function(){return this.iterator("table",function(t){return t.nTBody},1)}),t("tables().header()","table().header()",function(){return this.iterator("table",function(t){return t.nTHead},1)}),t("tables().footer()","table().footer()",function(){return this.iterator("table",function(t){return t.nTFoot},1)}),t("tables().containers()","table().container()",function(){return this.iterator("table",function(t){return t.nTableWrapper},1)}),e("draw()",function(e){return this.iterator("table",function(t){"page"===e?y(t):u(t,!1===(e="string"==typeof e?"full-hold"!==e:e))})}),e("page()",function(e){return e===H?this.page.info().page:this.iterator("table",function(t){Yt(t,e)})}),e("page.info()",function(t){var e,n,a,r,o;return 0===this.context.length?H:(n=(e=this.context[0])._iDisplayStart,a=e.oFeatures.bPaginate?e._iDisplayLength:-1,r=e.fnRecordsDisplay(),{page:(o=-1===a)?0:Math.floor(n/a),pages:o?1:Math.ceil(r/a),start:n,end:e.fnDisplayEnd(),length:a,recordsTotal:e.fnRecordsTotal(),recordsDisplay:r,serverSide:"ssp"===E(e)})}),e("page.len()",function(e){return e===H?0!==this.context.length?this.context[0]._iDisplayLength:H:this.iterator("table",function(t){$t(t,e)})}),e("ajax.json()",function(){var t=this.context;if(0<t.length)return t[0].json}),e("ajax.params()",function(){var t=this.context;if(0<t.length)return t[0].oAjaxData}),e("ajax.reload()",function(e,n){return this.iterator("table",function(t){De(t,!1===n,e)})}),e("ajax.url()",function(e){var t=this.context;return e===H?0===t.length?H:(t=t[0]).ajax?P.isPlainObject(t.ajax)?t.ajax.url:t.ajax:t.sAjaxSource:this.iterator("table",function(t){P.isPlainObject(t.ajax)?t.ajax.url=e:t.ajax=e})}),e("ajax.url().load()",function(e,n){return this.iterator("table",function(t){De(t,!1===n,e)})}),function(t,e){var n,a=[],r=t.aiDisplay,o=t.aiDisplayMaster,i=e.search,l=e.order,e=e.page;if("ssp"==E(t))return"removed"===i?[]:f(0,o.length);if("current"==e)for(u=t._iDisplayStart,c=t.fnDisplayEnd();u<c;u++)a.push(r[u]);else if("current"==l||"applied"==l){if("none"==i)a=o.slice();else if("applied"==i)a=r.slice();else if("removed"==i){for(var s={},u=0,c=r.length;u<c;u++)s[r[u]]=null;a=P.map(o,function(t){return s.hasOwnProperty(t)?null:t})}}else if("index"==l||"original"==l)for(u=0,c=t.aoData.length;u<c;u++)("none"==i||-1===(n=P.inArray(u,r))&&"removed"==i||0<=n&&"applied"==i)&&a.push(u);return a}),Le=(e("rows()",function(e,n){e===H?e="":P.isPlainObject(e)&&(n=e,e=""),n=we(n);var t=this.iterator("table",function(t){return _e("row",e,function(n){var t=d(n),a=r.aoData;if(null!==t&&!o)return[t];if(i=i||Fe(r,o),null!==t&&-1!==P.inArray(t,i))return[t];if(null===n||n===H||""===n)return i;if("function"==typeof n)return P.map(i,function(t){var e=a[t];return n(t,e._aData,e.nTr)?t:null});if(n.nodeName)return t=n._DT_RowIndex,e=n._DT_CellIndex,t!==H?a[t]&&a[t].nTr===n?[t]:[]:e?a[e.row]&&a[e.row].nTr===n.parentNode?[e.row]:[]:(t=P(n).closest("*[data-dt-row]")).length?[t.data("dt-row")]:[];if("string"==typeof n&&"#"===n.charAt(0)){var e=r.aIds[n.replace(/^#/,"")];if(e!==H)return[e.idx]}t=_(m(r.aoData,i,"nTr"));return P(t).filter(n).map(function(){return this._DT_RowIndex}).toArray()},r=t,o=n);var r,o,i},1);return t.selector.rows=e,t.selector.opts=n,t}),e("rows().nodes()",function(){return this.iterator("row",function(t,e){return t.aoData[e].nTr||H},1)}),e("rows().data()",function(){return this.iterator(!0,"rows",function(t,e){return m(t.aoData,e,"_aData")},1)}),t("rows().cache()","row().cache()",function(n){return this.iterator("row",function(t,e){t=t.aoData[e];return"search"===n?t._aFilterData:t._aSortData},1)}),t("rows().invalidate()","row().invalidate()",function(n){return this.iterator("row",function(t,e){bt(t,e,n)})}),t("rows().indexes()","row().index()",function(){return this.iterator("row",function(t,e){return e},1)}),t("rows().ids()","row().id()",function(t){for(var e=[],n=this.context,a=0,r=n.length;a<r;a++)for(var o=0,i=this[a].length;o<i;o++){var l=n[a].rowIdFn(n[a].aoData[this[a][o]]._aData);e.push((!0===t?"#":"")+l)}return new B(n,e)}),t("rows().remove()","row().remove()",function(){var f=this;return this.iterator("row",function(t,e,n){var a,r,o,i,l,s,u=t.aoData,c=u[e];for(u.splice(e,1),a=0,r=u.length;a<r;a++)if(s=(l=u[a]).anCells,null!==l.nTr&&(l.nTr._DT_RowIndex=a),null!==s)for(o=0,i=s.length;o<i;o++)s[o]._DT_CellIndex.row=a;gt(t.aiDisplayMaster,e),gt(t.aiDisplay,e),gt(f[n],e,!1),0<t._iRecordsDisplay&&t._iRecordsDisplay--,Se(t);n=t.rowIdFn(c._aData);n!==H&&delete t.aIds[n]}),this.iterator("table",function(t){for(var e=0,n=t.aoData.length;e<n;e++)t.aoData[e].idx=e}),this}),e("rows.add()",function(o){var t=this.iterator("table",function(t){for(var e,n=[],a=0,r=o.length;a<r;a++)(e=o[a]).nodeName&&"TR"===e.nodeName.toUpperCase()?n.push(ut(t,e)[0]):n.push(x(t,e));return n},1),e=this.rows(-1);return e.pop(),P.merge(e,t),e}),e("row()",function(t,e){return Ce(this.rows(t,e))}),e("row().data()",function(t){var e,n=this.context;return t===H?n.length&&this.length?n[0].aoData[this[0]]._aData:H:((e=n[0].aoData[this[0]])._aData=t,Array.isArray(t)&&e.nTr&&e.nTr.id&&b(n[0].rowId)(t,e.nTr.id),bt(n[0],this[0],"data"),this)}),e("row().node()",function(){var t=this.context;return t.length&&this.length&&t[0].aoData[this[0]].nTr||null}),e("row.add()",function(e){e instanceof P&&e.length&&(e=e[0]);var t=this.iterator("table",function(t){return e.nodeName&&"TR"===e.nodeName.toUpperCase()?ut(t,e)[0]:x(t,e)});return this.row(t[0])}),P(v).on("plugin-init.dt",function(t,e){var n=new B(e),a="on-plugin-init",r="stateSaveParams."+a,o="destroy. "+a,a=(n.on(r,function(t,e,n){for(var a=e.rowIdFn,r=e.aoData,o=[],i=0;i<r.length;i++)r[i]._detailsShow&&o.push("#"+a(r[i]._aData));n.childRows=o}),n.on(o,function(){n.off(r+" "+o)}),n.state.loaded());a&&a.childRows&&n.rows(P.map(a.childRows,function(t){return t.replace(/:/g,"\\:")})).every(function(){R(e,null,"requestChild",[this])})}),w.util.throttle(function(t){de(t[0])},500)),Re=function(t,e){var n=t.context;n.length&&(e=n[0].aoData[e!==H?e:t[0]])&&e._details&&(e._details.remove(),e._detailsShow=H,e._details=H,P(e.nTr).removeClass("dt-hasChild"),Le(n))},Pe="row().child",je=Pe+"()",He=(e(je,function(t,e){var n=this.context;return t===H?n.length&&this.length?n[0].aoData[this[0]]._details:H:(!0===t?this.child.show():!1===t?Re(this):n.length&&this.length&&Te(n[0],n[0].aoData[this[0]],t,e),this)}),e([Pe+".show()",je+".show()"],function(t){return xe(this,!0),this}),e([Pe+".hide()",je+".hide()"],function(){return xe(this,!1),this}),e([Pe+".remove()",je+".remove()"],function(){return Re(this),this}),e(Pe+".isShown()",function(){var t=this.context;return t.length&&this.length&&t[0].aoData[this[0]]._detailsShow||!1}),/^([^:]+):(name|visIdx|visible)$/),Ne=(e("columns()",function(n,a){n===H?n="":P.isPlainObject(n)&&(a=n,n=""),a=we(a);var t=this.iterator("table",function(t){return e=n,l=a,s=(i=t).aoColumns,u=N(s,"sName"),c=N(s,"nTh"),_e("column",e,function(n){var a,t=d(n);if(""===n)return f(s.length);if(null!==t)return[0<=t?t:s.length+t];if("function"==typeof n)return a=Fe(i,l),P.map(s,function(t,e){return n(e,Ae(i,e,0,0,a),c[e])?e:null});var r="string"==typeof n?n.match(He):"";if(r)switch(r[2]){case"visIdx":case"visible":var e,o=parseInt(r[1],10);return o<0?[(e=P.map(s,function(t,e){return t.bVisible?e:null}))[e.length+o]]:[rt(i,o)];case"name":return P.map(u,function(t,e){return t===r[1]?e:null});default:return[]}return n.nodeName&&n._DT_CellIndex?[n._DT_CellIndex.column]:(t=P(c).filter(n).map(function(){return P.inArray(this,c)}).toArray()).length||!n.nodeName?t:(t=P(n).closest("*[data-dt-column]")).length?[t.data("dt-column")]:[]},i,l);var i,e,l,s,u,c},1);return t.selector.cols=n,t.selector.opts=a,t}),t("columns().header()","column().header()",function(t,e){return this.iterator("column",function(t,e){return t.aoColumns[e].nTh},1)}),t("columns().footer()","column().footer()",function(t,e){return this.iterator("column",function(t,e){return t.aoColumns[e].nTf},1)}),t("columns().data()","column().data()",function(){return this.iterator("column-rows",Ae,1)}),t("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(t,e){return t.aoColumns[e].mData},1)}),t("columns().cache()","column().cache()",function(o){return this.iterator("column-rows",function(t,e,n,a,r){return m(t.aoData,r,"search"===o?"_aFilterData":"_aSortData",e)},1)}),t("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(t,e,n,a,r){return m(t.aoData,r,"anCells",e)},1)}),t("columns().visible()","column().visible()",function(f,n){var e=this,t=this.iterator("column",function(t,e){if(f===H)return t.aoColumns[e].bVisible;var n,a,r=e,e=f,o=t.aoColumns,i=o[r],l=t.aoData;if(e===H)i.bVisible;else if(i.bVisible!==e){if(e)for(var s=P.inArray(!0,N(o,"bVisible"),r+1),u=0,c=l.length;u<c;u++)a=l[u].nTr,n=l[u].anCells,a&&a.insertBefore(n[r],n[s]||null);else P(N(t.aoData,"anCells",r)).detach();i.bVisible=e}});return f!==H&&this.iterator("table",function(t){Dt(t,t.aoHeader),Dt(t,t.aoFooter),t.aiDisplay.length||P(t.nTBody).find("td[colspan]").attr("colspan",T(t)),de(t),e.iterator("column",function(t,e){R(t,null,"column-visibility",[t,e,f,n])}),n!==H&&!n||e.columns.adjust()}),t}),t("columns().indexes()","column().index()",function(n){return this.iterator("column",function(t,e){return"visible"===n?ot(t,e):e},1)}),e("columns.adjust()",function(){return this.iterator("table",function(t){O(t)},1)}),e("column.index()",function(t,e){var n;if(0!==this.context.length)return n=this.context[0],"fromVisible"===t||"toData"===t?rt(n,e):"fromData"===t||"toVisible"===t?ot(n,e):void 0}),e("column()",function(t,e){return Ce(this.columns(t,e))}),e("cells()",function(g,t,b){var a,r,o,i,l,s,e;return P.isPlainObject(g)&&(g.row===H?(b=g,g=null):(b=t,t=null)),P.isPlainObject(t)&&(b=t,t=null),null===t||t===H?this.iterator("table",function(t){return a=t,t=g,e=we(b),f=a.aoData,d=Fe(a,e),n=_(m(f,d,"anCells")),h=P(Y([],n)),p=a.aoColumns.length,_e("cell",t,function(t){var e,n="function"==typeof t;if(null===t||t===H||n){for(o=[],i=0,l=d.length;i<l;i++)for(r=d[i],s=0;s<p;s++)u={row:r,column:s},(!n||(c=f[r],t(u,S(a,r,s),c.anCells?c.anCells[s]:null)))&&o.push(u);return o}return P.isPlainObject(t)?t.column!==H&&t.row!==H&&-1!==P.inArray(t.row,d)?[t]:[]:(e=h.filter(t).map(function(t,e){return{row:e._DT_CellIndex.row,column:e._DT_CellIndex.column}}).toArray()).length||!t.nodeName?e:(c=P(t).closest("*[data-dt-row]")).length?[{row:c.data("dt-row"),column:c.data("dt-column")}]:[]},a,e);var a,e,r,o,i,l,s,u,c,f,d,n,h,p}):(e=b?{page:b.page,order:b.order,search:b.search}:{},a=this.columns(t,e),r=this.rows(g,e),e=this.iterator("table",function(t,e){var n=[];for(o=0,i=r[e].length;o<i;o++)for(l=0,s=a[e].length;l<s;l++)n.push({row:r[e][o],column:a[e][l]});return n},1),e=b&&b.selected?this.cells(e,b):e,P.extend(e.selector,{cols:t,rows:g,opts:b}),e)}),t("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(t,e,n){t=t.aoData[e];return t&&t.anCells?t.anCells[n]:H},1)}),e("cells().data()",function(){return this.iterator("cell",function(t,e,n){return S(t,e,n)},1)}),t("cells().cache()","cell().cache()",function(a){return a="search"===a?"_aFilterData":"_aSortData",this.iterator("cell",function(t,e,n){return t.aoData[e][a][n]},1)}),t("cells().render()","cell().render()",function(a){return this.iterator("cell",function(t,e,n){return S(t,e,n,a)},1)}),t("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(t,e,n){return{row:e,column:n,columnVisible:ot(t,n)}},1)}),t("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(t,e,n){bt(t,e,a,n)})}),e("cell()",function(t,e,n){return Ce(this.cells(t,e,n))}),e("cell().data()",function(t){var e=this.context,n=this[0];return t===H?e.length&&n.length?S(e[0],n[0].row,n[0].column):H:(ct(e[0],n[0].row,n[0].column,t),bt(e[0],n[0].row,"data",n[0].column),this)}),e("order()",function(e,t){var n=this.context;return e===H?0!==n.length?n[0].aaSorting:H:("number"==typeof e?e=[[e,t]]:e.length&&!Array.isArray(e[0])&&(e=Array.prototype.slice.call(arguments)),this.iterator("table",function(t){t.aaSorting=e.slice()}))}),e("order.listener()",function(e,n,a){return this.iterator("table",function(t){ue(t,e,n,a)})}),e("order.fixed()",function(e){var t;return e?this.iterator("table",function(t){t.aaSortingFixed=P.extend(!0,{},e)}):(t=(t=this.context).length?t[0].aaSortingFixed:H,Array.isArray(t)?{pre:t}:t)}),e(["columns().order()","column().order()"],function(a){var r=this;return this.iterator("table",function(t,e){var n=[];P.each(r[e],function(t,e){n.push([e,a])}),t.aaSorting=n})}),e("search()",function(e,n,a,r){var t=this.context;return e===H?0!==t.length?t[0].oPreviousSearch.sSearch:H:this.iterator("table",function(t){t.oFeatures.bFilter&&Rt(t,P.extend({},t.oPreviousSearch,{sSearch:e+"",bRegex:null!==n&&n,bSmart:null===a||a,bCaseInsensitive:null===r||r}),1)})}),t("columns().search()","column().search()",function(a,r,o,i){return this.iterator("column",function(t,e){var n=t.aoPreSearchCols;if(a===H)return n[e].sSearch;t.oFeatures.bFilter&&(P.extend(n[e],{sSearch:a+"",bRegex:null!==r&&r,bSmart:null===o||o,bCaseInsensitive:null===i||i}),Rt(t,t.oPreviousSearch,1))})}),e("state()",function(){return this.context.length?this.context[0].oSavedState:null}),e("state.clear()",function(){return this.iterator("table",function(t){t.fnStateSaveCallback.call(t.oInstance,t,{})})}),e("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null}),e("state.save()",function(){return this.iterator("table",function(t){de(t)})}),w.use=function(t,e){"lib"===e||t.fn?P=t:"win"==e||t.document?v=(j=t).document:"datetime"!==e&&"DateTime"!==t.type||(w.DateTime=t)},w.factory=function(t,e){var n=!1;return t&&t.document&&(v=(j=t).document),e&&e.fn&&e.fn.jquery&&(P=e,n=!0),n},w.versionCheck=w.fnVersionCheck=function(t){for(var e,n,a=w.version.split("."),r=t.split("."),o=0,i=r.length;o<i;o++)if((e=parseInt(a[o],10)||0)!==(n=parseInt(r[o],10)||0))return n<e;return!0},w.isDataTable=w.fnIsDataTable=function(t){var r=P(t).get(0),o=!1;return t instanceof w.Api||(P.each(w.settings,function(t,e){var n=e.nScrollHead?P("table",e.nScrollHead)[0]:null,a=e.nScrollFoot?P("table",e.nScrollFoot)[0]:null;e.nTable!==r&&n!==r&&a!==r||(o=!0)}),o)},w.tables=w.fnTables=function(e){var t=!1,n=(P.isPlainObject(e)&&(t=e.api,e=e.visible),P.map(w.settings,function(t){if(!e||P(t.nTable).is(":visible"))return t.nTable}));return t?new B(n):n},w.camelToHungarian=C,e("$()",function(t,e){e=this.rows(e).nodes(),e=P(e);return P([].concat(e.filter(t).toArray(),e.find(t).toArray()))}),P.each(["on","one","off"],function(t,n){e(n+"()",function(){var t=Array.prototype.slice.call(arguments),e=(t[0]=P.map(t[0].split(/\s/),function(t){return t.match(/\.dt\b/)?t:t+".dt"}).join(" "),P(this.tables().nodes()));return e[n].apply(e,t),this})}),e("clear()",function(){return this.iterator("table",function(t){pt(t)})}),e("settings()",function(){return new B(this.context,this.context)}),e("init()",function(){var t=this.context;return t.length?t[0].oInit:null}),e("data()",function(){return this.iterator("table",function(t){return N(t.aoData,"_aData")}).flatten()}),e("destroy()",function(c){return c=c||!1,this.iterator("table",function(e){var n,t=e.oClasses,a=e.nTable,r=e.nTBody,o=e.nTHead,i=e.nTFoot,l=P(a),r=P(r),s=P(e.nTableWrapper),u=P.map(e.aoData,function(t){return t.nTr}),i=(e.bDestroying=!0,R(e,"aoDestroyCallback","destroy",[e]),c||new B(e).columns().visible(!0),s.off(".DT").find(":not(tbody *)").off(".DT"),P(j).off(".DT-"+e.sInstance),a!=o.parentNode&&(l.children("thead").detach(),l.append(o)),i&&a!=i.parentNode&&(l.children("tfoot").detach(),l.append(i)),e.aaSorting=[],e.aaSortingFixed=[],ce(e),P(u).removeClass(e.asStripeClasses.join(" ")),P("th, td",o).removeClass(t.sSortable+" "+t.sSortableAsc+" "+t.sSortableDesc+" "+t.sSortableNone),r.children().detach(),r.append(u),e.nTableWrapper.parentNode),o=c?"remove":"detach",u=(l[o](),s[o](),!c&&i&&(i.insertBefore(a,e.nTableReinsertBefore),l.css("width",e.sDestroyWidth).removeClass(t.sTable),n=e.asDestroyStripes.length)&&r.children().each(function(t){P(this).addClass(e.asDestroyStripes[t%n])}),P.inArray(e,w.settings));-1!==u&&w.settings.splice(u,1)})}),P.each(["column","row","cell"],function(t,s){e(s+"s().every()",function(o){var i=this.selector.opts,l=this;return this.iterator(s,function(t,e,n,a,r){o.call(l[s](e,"cell"===s?n:i,"cell"===s?i:H),e,n,a,r)})})}),e("i18n()",function(t,e,n){var a=this.context[0],t=A(t)(a.oLanguage);return t===H&&(t=e),"string"==typeof(t=n!==H&&P.isPlainObject(t)?t[n]!==H?t[n]:t._:t)?t.replace("%d",n):t}),w.version="1.13.8",w.settings=[],w.models={},w.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0,return:!1},w.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1},w.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null},w.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(t){return t.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(t){try{return JSON.parse((-1===t.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+t.sInstance+"_"+location.pathname))}catch(t){return{}}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(t,e){try{(-1===t.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+t.sInstance+"_"+location.pathname,JSON.stringify(e))}catch(t){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:P.extend({},w.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"},i(w.defaults),w.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null},i(w.defaults.column),w.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,jqXHR:null,json:H,oAjaxData:H,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==E(this)?+this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==E(this)?+this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var t=this._iDisplayLength,e=this._iDisplayStart,n=e+t,a=this.aiDisplay.length,r=this.oFeatures,o=r.bPaginate;return r.bServerSide?!1===o||-1===t?e+a:Math.min(e+t,this._iRecordsDisplay):!o||a<n||-1===t?a:n},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null},w.ext=p={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:w.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:w.version},P.extend(p,{afnFiltering:p.search,aTypes:p.type.detect,ofnSearch:p.type.search,oSort:p.type.order,afnSortData:p.order,aoFeatures:p.feature,oApi:p.internal,oStdClasses:p.classes,oPagination:p.pager}),P.extend(w.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_desc_disabled",sSortableDesc:"sorting_asc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""}),w.ext.pager);function Oe(t,e){var n=[],a=Ne.numbers_length,r=Math.floor(a/2);return e<=a?n=f(0,e):t<=r?((n=f(0,a-2)).push("ellipsis"),n.push(e-1)):((e-1-r<=t?n=f(e-(a-2),e):((n=f(t-r+2,t+r-1)).push("ellipsis"),n.push(e-1),n)).splice(0,0,"ellipsis"),n.splice(0,0,0)),n.DT_el="span",n}P.extend(Ne,{simple:function(t,e){return["previous","next"]},full:function(t,e){return["first","previous","next","last"]},numbers:function(t,e){return[Oe(t,e)]},simple_numbers:function(t,e){return["previous",Oe(t,e),"next"]},full_numbers:function(t,e){return["first","previous",Oe(t,e),"next","last"]},first_last_numbers:function(t,e){return["first",Oe(t,e),"last"]},_numbers:Oe,numbers_length:7}),P.extend(!0,w.ext.renderer,{pageButton:{_:function(u,t,c,e,f,d){function h(t,e){for(var n,a=b.sPageButtonDisabled,r=function(t){Yt(u,t.data.action,!0)},o=0,i=e.length;o<i;o++)if(n=e[o],Array.isArray(n)){var l=P("<"+(n.DT_el||"div")+"/>").appendTo(t);h(l,n)}else{var s=!1;switch(p=null,g=n){case"ellipsis":t.append('<span class="ellipsis">&#x2026;</span>');break;case"first":p=m.sFirst,0===f&&(s=!0);break;case"previous":p=m.sPrevious,0===f&&(s=!0);break;case"next":p=m.sNext,0!==d&&f!==d-1||(s=!0);break;case"last":p=m.sLast,0!==d&&f!==d-1||(s=!0);break;default:p=u.fnFormatNumber(n+1),g=f===n?b.sPageButtonActive:""}null!==p&&(l=u.oInit.pagingTag||"a",s&&(g+=" "+a),me(P("<"+l+">",{class:b.sPageButton+" "+g,"aria-controls":u.sTableId,"aria-disabled":s?"true":null,"aria-label":S[n],role:"link","aria-current":g===b.sPageButtonActive?"page":null,"data-dt-idx":n,tabindex:s?-1:u.iTabIndex,id:0===c&&"string"==typeof n?u.sTableId+"_"+n:null}).html(p).appendTo(t),{action:n},r))}}var p,g,n,b=u.oClasses,m=u.oLanguage.oPaginate,S=u.oLanguage.oAria.paginate||{};try{n=P(t).find(v.activeElement).data("dt-idx")}catch(t){}h(P(t).empty(),e),n!==H&&P(t).find("[data-dt-idx="+n+"]").trigger("focus")}}}),P.extend(w.ext.type.detect,[function(t,e){e=e.oLanguage.sDecimal;return l(t,e)?"num"+e:null},function(t,e){var n;return(!t||t instanceof Date||X.test(t))&&(null!==(n=Date.parse(t))&&!isNaN(n)||h(t))?"date":null},function(t,e){e=e.oLanguage.sDecimal;return l(t,e,!0)?"num-fmt"+e:null},function(t,e){e=e.oLanguage.sDecimal;return a(t,e)?"html-num"+e:null},function(t,e){e=e.oLanguage.sDecimal;return a(t,e,!0)?"html-num-fmt"+e:null},function(t,e){return h(t)||"string"==typeof t&&-1!==t.indexOf("<")?"html":null}]),P.extend(w.ext.type.search,{html:function(t){return h(t)?t:"string"==typeof t?t.replace(U," ").replace(V,""):""},string:function(t){return!h(t)&&"string"==typeof t?t.replace(U," "):t}});function ke(t,e,n,a){var r;return 0===t||t&&"-"!==t?"number"==(r=typeof t)||"bigint"==r?t:+(t=(t=e?$(t,e):t).replace&&(n&&(t=t.replace(n,"")),a)?t.replace(a,""):t):-1/0}function Me(n){P.each({num:function(t){return ke(t,n)},"num-fmt":function(t){return ke(t,n,q)},"html-num":function(t){return ke(t,n,V)},"html-num-fmt":function(t){return ke(t,n,V,q)}},function(t,e){p.type.order[t+n+"-pre"]=e,t.match(/^html\-/)&&(p.type.search[t+n]=p.type.search.html)})}P.extend(p.type.order,{"date-pre":function(t){t=Date.parse(t);return isNaN(t)?-1/0:t},"html-pre":function(t){return h(t)?"":t.replace?t.replace(/<.*?>/g,"").toLowerCase():t+""},"string-pre":function(t){return h(t)?"":"string"==typeof t?t.toLowerCase():t.toString?t.toString():""},"string-asc":function(t,e){return t<e?-1:e<t?1:0},"string-desc":function(t,e){return t<e?1:e<t?-1:0}}),Me(""),P.extend(!0,w.ext.renderer,{header:{_:function(r,o,i,l){P(r.nTable).on("order.dt.DT",function(t,e,n,a){r===e&&(e=i.idx,o.removeClass(l.sSortAsc+" "+l.sSortDesc).addClass("asc"==a[e]?l.sSortAsc:"desc"==a[e]?l.sSortDesc:i.sSortingClass))})},jqueryui:function(r,o,i,l){P("<div/>").addClass(l.sSortJUIWrapper).append(o.contents()).append(P("<span/>").addClass(l.sSortIcon+" "+i.sSortingClassJUI)).appendTo(o),P(r.nTable).on("order.dt.DT",function(t,e,n,a){r===e&&(e=i.idx,o.removeClass(l.sSortAsc+" "+l.sSortDesc).addClass("asc"==a[e]?l.sSortAsc:"desc"==a[e]?l.sSortDesc:i.sSortingClass),o.find("span."+l.sSortIcon).removeClass(l.sSortJUIAsc+" "+l.sSortJUIDesc+" "+l.sSortJUI+" "+l.sSortJUIAscAllowed+" "+l.sSortJUIDescAllowed).addClass("asc"==a[e]?l.sSortJUIAsc:"desc"==a[e]?l.sSortJUIDesc:i.sSortingClassJUI))})}}});function We(t){return"string"==typeof(t=Array.isArray(t)?t.join(","):t)?t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):t}function Ee(t,e,n,a,r){return j.moment?t[e](r):j.luxon?t[n](r):a?t[a](r):t}var Be=!1;function Ue(t,e,n){var a;if(j.moment){if(!(a=j.moment.utc(t,e,n,!0)).isValid())return null}else if(j.luxon){if(!(a=e&&"string"==typeof t?j.luxon.DateTime.fromFormat(t,e):j.luxon.DateTime.fromISO(t)).isValid)return null;a.setLocale(n)}else e?(Be||alert("DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17"),Be=!0):a=new Date(t);return a}function Ve(s){return function(a,r,o,i){0===arguments.length?(o="en",a=r=null):1===arguments.length?(o="en",r=a,a=null):2===arguments.length&&(o=r,r=a,a=null);var l="datetime-"+r;return w.ext.type.order[l]||(w.ext.type.detect.unshift(function(t){return t===l&&l}),w.ext.type.order[l+"-asc"]=function(t,e){t=t.valueOf(),e=e.valueOf();return t===e?0:t<e?-1:1},w.ext.type.order[l+"-desc"]=function(t,e){t=t.valueOf(),e=e.valueOf();return t===e?0:e<t?-1:1}),function(t,e){var n;return null!==t&&t!==H||(t="--now"===i?(n=new Date,new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate(),n.getHours(),n.getMinutes(),n.getSeconds()))):""),"type"===e?l:""===t?"sort"!==e?"":Ue("0000-01-01 00:00:00",null,o):!(null===r||a!==r||"sort"===e||"type"===e||t instanceof Date)||null===(n=Ue(t,a,o))?t:"sort"===e?n:(t=null===r?Ee(n,"toDate","toJSDate","")[s]():Ee(n,"format","toFormat","toISOString",r),"display"===e?We(t):t)}}}var Xe=",",Je=".";if(j.Intl!==H)try{for(var qe=(new Intl.NumberFormat).formatToParts(100000.1),n=0;n<qe.length;n++)"group"===qe[n].type?Xe=qe[n].value:"decimal"===qe[n].type&&(Je=qe[n].value)}catch(t){}function $e(e){return function(){var t=[ge(this[w.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return w.ext.internal[e].apply(this,t)}}return w.datetime=function(n,a){var r="datetime-detect-"+n;a=a||"en",w.ext.type.order[r]||(w.ext.type.detect.unshift(function(t){var e=Ue(t,n,a);return!(""!==t&&!e)&&r}),w.ext.type.order[r+"-pre"]=function(t){return Ue(t,n,a)||0})},w.render={date:Ve("toLocaleDateString"),datetime:Ve("toLocaleString"),time:Ve("toLocaleTimeString"),number:function(a,r,o,i,l){return null!==a&&a!==H||(a=Xe),null!==r&&r!==H||(r=Je),{display:function(t){if("number"!=typeof t&&"string"!=typeof t)return t;if(""===t||null===t)return t;var e=t<0?"-":"",n=parseFloat(t);if(isNaN(n))return We(t);n=n.toFixed(o),t=Math.abs(n);n=parseInt(t,10),t=o?r+(t-n).toFixed(o).substring(2):"";return(e=0===n&&0===parseFloat(t)?"":e)+(i||"")+n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+t+(l||"")}}},text:function(){return{display:We,filter:We}}},P.extend(w.ext.internal,{_fnExternApiFunc:$e,_fnBuildAjax:Tt,_fnAjaxUpdate:xt,_fnAjaxParameters:At,_fnAjaxUpdateDraw:It,_fnAjaxDataSrc:Ft,_fnAddColumn:nt,_fnColumnOptions:at,_fnAdjustColumnSizing:O,_fnVisibleToColumnIndex:rt,_fnColumnIndexToVisible:ot,_fnVisbleColumns:T,_fnGetColumns:it,_fnColumnTypes:lt,_fnApplyColumnDefs:st,_fnHungarianMap:i,_fnCamelToHungarian:C,_fnLanguageCompat:Z,_fnBrowserDetect:tt,_fnAddData:x,_fnAddTr:ut,_fnNodeToDataIndex:function(t,e){return e._DT_RowIndex!==H?e._DT_RowIndex:null},_fnNodeToColumnIndex:function(t,e,n){return P.inArray(n,t.aoData[e].anCells)},_fnGetCellData:S,_fnSetCellData:ct,_fnSplitObjNotation:dt,_fnGetObjectDataFn:A,_fnSetObjectDataFn:b,_fnGetDataMaster:ht,_fnClearTable:pt,_fnDeleteIndex:gt,_fnInvalidate:bt,_fnGetRowElements:mt,_fnCreateTr:St,_fnBuildHead:yt,_fnDrawHead:Dt,_fnDraw:y,_fnReDraw:u,_fnAddOptionsHtml:_t,_fnDetectHeader:wt,_fnGetUniqueThs:Ct,_fnFeatureHtmlFilter:Lt,_fnFilterComplete:Rt,_fnFilterCustom:Pt,_fnFilterColumn:jt,_fnFilter:Ht,_fnFilterCreateSearch:Nt,_fnEscapeRegex:Ot,_fnFilterData:Wt,_fnFeatureHtmlInfo:Ut,_fnUpdateInfo:Vt,_fnInfoMacros:Xt,_fnInitialise:Jt,_fnInitComplete:qt,_fnLengthChange:$t,_fnFeatureHtmlLength:Gt,_fnFeatureHtmlPaginate:zt,_fnPageChange:Yt,_fnFeatureHtmlProcessing:Zt,_fnProcessingDisplay:D,_fnFeatureHtmlTable:Kt,_fnScrollDraw:Qt,_fnApplyToChildren:k,_fnCalculateColumnWidths:ee,_fnThrottle:ne,_fnConvertToWidth:ae,_fnGetWidestNode:re,_fnGetMaxLenString:oe,_fnStringToCss:M,_fnSortFlatten:I,_fnSort:ie,_fnSortAria:le,_fnSortListener:se,_fnSortAttachListener:ue,_fnSortingClasses:ce,_fnSortData:fe,_fnSaveState:de,_fnLoadState:he,_fnImplementState:pe,_fnSettingsFromNode:ge,_fnLog:W,_fnMap:F,_fnBindAction:me,_fnCallbackReg:L,_fnCallbackFire:R,_fnLengthOverflow:Se,_fnRenderer:ve,_fnDataSource:E,_fnRowAttributes:vt,_fnExtend:be,_fnCalculateEnd:function(){}}),((P.fn.dataTable=w).$=P).fn.dataTableSettings=w.settings,P.fn.dataTableExt=w.ext,P.fn.DataTable=function(t){return P(this).dataTable(t).api()},P.each(w,function(t,e){P.fn.DataTable[t]=e}),w}); \ No newline at end of file
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
index f2c45c833e..d4ac31234c 100644
--- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
@@ -657,7 +657,7 @@ $(document).ready(function() {
657 hljs.initHighlightingOnLoad(); 657 hljs.initHighlightingOnLoad();
658 658
659 // Prevent invalid links from jumping page scroll 659 // Prevent invalid links from jumping page scroll
660 $('a[href=#]').click(function() { 660 $('a[href="#"]').click(function() {
661 return false; 661 return false;
662 }); 662 });
663 663
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectpage.js b/bitbake/lib/toaster/toastergui/static/js/projectpage.js
index 506471e091..a3c95810a7 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projectpage.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projectpage.js
@@ -61,7 +61,7 @@ function projectPageInit(ctx) {
61 distroChangeInput.val(urlParams.setDistro); 61 distroChangeInput.val(urlParams.setDistro);
62 distroChangeBtn.click(); 62 distroChangeBtn.click();
63 } else { 63 } else {
64 updateDistroName(prjInfo.distro.name); 64 updateDistroName(prjInfo.distro?.name);
65 } 65 }
66 66
67 /* Now we're really ready show the page */ 67 /* Now we're really ready show the page */
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html
index 9e19cc33ca..e90be69620 100644
--- a/bitbake/lib/toaster/toastergui/templates/base.html
+++ b/bitbake/lib/toaster/toastergui/templates/base.html
@@ -14,11 +14,11 @@
14 14
15 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 15 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
16 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> 16 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
17 <script src="{% static 'js/jquery-2.0.3.min.js' %}"> 17 <script src="{% static 'js/jquery-3.7.1.min.js' %}">
18 </script> 18 </script>
19 <script src="{% static 'js/jquery.cookie.js' %}"> 19 <script src="{% static 'js/jquery.cookie.js' %}">
20 </script> 20 </script>
21 <script src="{% static 'js/bootstrap.min.js' %}"> 21 <script src="{% static 'js/bootstrap-3.4.1.min.js' %}">
22 </script> 22 </script>
23 <script src="{% static 'js/typeahead.jquery.js' %}"> 23 <script src="{% static 'js/typeahead.jquery.js' %}">
24 </script> 24 </script>
@@ -94,7 +94,7 @@
94 </a> 94 </a>
95 <a class="brand" href="/">Toaster</a> 95 <a class="brand" href="/">Toaster</a>
96 {% if DEBUG %} 96 {% if DEBUG %}
97 <span class="glyphicon glyphicon-info-sign" title="<strong>Toaster version information</strong>" data-content="<dl><dt>Git branch</dt><dd>{{TOASTER_BRANCH}}</dd><dt>Git revision</dt><dd>{{TOASTER_REVISION}}</dd></dl>"></i> 97 <span id="toaster-version-info-sign" class="glyphicon glyphicon-info-sign" title="<strong>Toaster version information</strong>" data-content="<dl><dt>Git branch</dt><dd>{{TOASTER_BRANCH}}</dd><dt>Git revision</dt><dd>{{TOASTER_REVISION}}</dd></dl>"></i>
98 {% endif %} 98 {% endif %}
99 </div> 99 </div>
100 </div> 100 </div>
@@ -123,7 +123,7 @@
123 {% endif %} 123 {% endif %}
124 {% endif %} 124 {% endif %}
125 <li id="navbar-docs"> 125 <li id="navbar-docs">
126 <a target="_blank" href="https://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html"> 126 <a target="_blank" href="http://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual">
127 <i class="glyphicon glyphicon-book"></i> 127 <i class="glyphicon glyphicon-book"></i>
128 Documentation 128 Documentation
129 </a> 129 </a>
@@ -132,7 +132,8 @@
132 {% if project_enable %} 132 {% if project_enable %}
133 <a class="btn btn-default navbar-btn navbar-right" id="new-project-button" href="{% url 'newproject' %}">New project</a> 133 <a class="btn btn-default navbar-btn navbar-right" id="new-project-button" href="{% url 'newproject' %}">New project</a>
134 {% endif %} 134 {% endif %}
135 </div> 135 <a class="btn btn-default navbar-btn navbar-right" id="import_page" style="margin-right: 5px !important" id="import-cmdline-button" href="{% url 'cmdlines' %}">Import command line builds</a>
136 </div>
136 </div> 137 </div>
137 </nav> 138 </nav>
138 139
diff --git a/bitbake/lib/toaster/toastergui/templates/base_specific.html b/bitbake/lib/toaster/toastergui/templates/base_specific.html
index e377cadd73..425f7ed73d 100644
--- a/bitbake/lib/toaster/toastergui/templates/base_specific.html
+++ b/bitbake/lib/toaster/toastergui/templates/base_specific.html
@@ -14,11 +14,11 @@
14 14
15 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 15 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
16 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> 16 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
17 <script src="{% static 'js/jquery-2.0.3.min.js' %}"> 17 <script src="{% static 'js/jquery-3.7.1.min.js' %}">
18 </script> 18 </script>
19 <script src="{% static 'js/jquery.cookie.js' %}"> 19 <script src="{% static 'js/jquery.cookie.js' %}">
20 </script> 20 </script>
21 <script src="{% static 'js/bootstrap.min.js' %}"> 21 <script src="{% static 'js/bootstrap-3.4.1.min.js' %}">
22 </script> 22 </script>
23 <script src="{% static 'js/typeahead.jquery.js' %}"> 23 <script src="{% static 'js/typeahead.jquery.js' %}">
24 </script> 24 </script>
diff --git a/bitbake/lib/toaster/toastergui/templates/command_line_builds.html b/bitbake/lib/toaster/toastergui/templates/command_line_builds.html
new file mode 100644
index 0000000000..05db6727e7
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/command_line_builds.html
@@ -0,0 +1,209 @@
1{% extends "base.html" %}
2{% load projecttags %}
3{% load humanize %}
4{% load static %}
5
6{% block title %} Import Builds from eventlogs - Toaster {% endblock %}
7
8{% block pagecontent %}
9
10<div class="container-fluid">
11 <div id="overlay" class="hide">
12 <div class="spinner">
13 <div class="fa-spin">
14 </div>
15 </div>
16 </div>
17 <div class="row">
18 <div class="col-md-12">
19 <div class="page-header">
20 <div class="row">
21 <div class="col-md-6">
22 <h1>Import command line builds</h1>
23 </div>
24 {% if import_all %}
25 <div class="col-md-6">
26 <button id="import_all" type="button" class="btn btn-primary navbar-btn navbar-right">
27 <span class="glyphicon glyphicon-upload" style="vertical-align: top;"></span> Import All
28 </button>
29 </div>
30 {% endif %}
31 </div>
32 </div>
33 {% if messages %}
34 <div class="row-fluid" id="empty-state-{{table_name}}">
35 {% for message in messages %}
36 <div class="alert alert-danger">{{message}}</div>
37 {%endfor%}
38 </div>
39 {% endif %}
40 <div class="row">
41 <h4 style="margin-left: 15px;"><strong>Import eventlog file</strong></h4>
42 <form method="POST" enctype="multipart/form-data" action="{% url 'cmdlines' %}" id="form_file">
43 {% csrf_token %}
44 <div class="col-md-6" style="padding-left: 20px;">
45 <div class="row">
46 <input type="hidden" value="{{dir}}" name="dir">
47 <div class="col-md-3"> {{ form.eventlog_file}} </div>
48 </div>
49 <div class="row" style="padding-top: 10px;">
50 <div class="col-md-6">
51 <button id="file_import" type="submit" disabled="disabled" class="btn btn-default navbar-btn" >
52 <span class="glyphicon glyphicon-upload" style="vertical-align: top;"></span> Import
53 </button>
54 </div>
55 </div>
56 </div>
57 </form>
58 </div>
59
60 <div class="row" style="padding-top: 20px;">
61 <div class="col-md-8 ">
62 <h4><strong>Eventlogs from existing build directory: </strong>
63 <a href="#" data-toggle="tooltip" title="{{dir}}">
64 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16" data-toggle="tooltip">
65 <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
66 <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
67 </svg>
68 </a>
69 </h4>
70 {% if files %}
71 <div class="table-responsive">
72 <table class="table col-md-6 table-bordered table-hover" id="eventlog-table" style="border-collapse: collapse;">
73 <thead>
74 <tr class="row">
75 <th scope="col">Name</th>
76 <th scope="col">Size</th>
77 <th scope="col">Action</th>
78 </tr>
79 </thead>
80 <tbody>
81 {% for file in files %}
82 <tr class="row" style="height: 48px;">
83 <th scope="row" class="col-md-4" style="vertical-align: middle;">
84 <input type="hidden" value="{{file.name}}" name="{{file.name}}">{{file.name}}
85 </th>
86 <td class="col-md-4 align-middle" style="vertical-align: middle;">{{file.size|filesizeformat}}</td>
87 <td class="col-md-4 align-middle" style="vertical-align: middle;">
88 {% if file.imported == True and file.build_id is not None %}
89 <a href="{% url 'builddashboard' file.build_id %}">Build Details</a>
90 {% elif request.session.file == file.name or request.session.all_builds %}
91 <a data-toggle="tooltip" title="Build in progress">
92 <span class="glyphicon glyphicon-upload" style="font-size: 18px; color:grey"></span>
93 </a>
94 {%else%}
95 <a onclick="_ajax_update('{{file.name}}', false, '{{dir}}')" data-toggle="tooltip" title="Import File">
96 <span class="glyphicon glyphicon-upload" style="font-size: 18px;"></span>
97 </a>
98 {%endif%}
99 </td>
100 </tr>
101 {% endfor%}
102 </tbody>
103 </table>
104 </div>
105 {% else %}
106 <div class="row-fluid" id="empty-state-{{table_name}}">
107 <div class="alert alert-info">Sorry - no files found</div>
108 </div>
109 {%endif%}
110 </div>
111 </div>
112 </div>
113 </div>
114</div>
115
116<link rel="stylesheet" href="{% static 'css/jquery.dataTables-1.13.8.min.css' %}" type='text/css'/>
117<script src="{% static 'js/jquery.dataTables-1.13.8.min.js' %}"> </script>
118<script>
119
120function _ajax_update(file, all, dir){
121 function getCookie(name) {
122 var cookieValue = null;
123 if (document.cookie && document.cookie !== '') {
124 var cookies = document.cookie.split(';');
125 for (var i = 0; i < cookies.length; i++) {
126 var cookie = jQuery.trim(cookies[i]);
127 // Does this cookie string begin with the name we want?
128 if (cookie.substring(0, name.length + 1) === (name + '=')) {
129 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
130 break;
131 }
132 }
133 }
134 return cookieValue;
135 }
136 var csrftoken = getCookie('csrftoken');
137
138 function csrfSafeMethod(method) {
139 // these HTTP methods do not require CSRF protection
140 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
141 }
142 $.ajaxSetup({
143 beforeSend: function (xhr, settings) {
144 if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
145 xhr.setRequestHeader("X-CSRFToken", csrftoken);
146 }
147 }
148 });
149
150 $.ajax({
151 url:'/toastergui/cmdline/',
152 type: "POST",
153 data: {file: file, all: all, dir: dir},
154 success:function(data){
155 if (data['response']=='building'){
156 location.reload()
157 } else {
158 window.location = '/toastergui/builds/'
159 }
160 },
161 complete:function(data){
162 },
163 error:function (xhr, textStatus, thrownError){
164 console.log('fail');
165 }
166 });
167}
168
169$('#import_all').on('click', function(){
170 _ajax_update("{{files | safe}}", true, "{{dir | safe}}");
171});
172
173
174$('#import_page').hide();
175
176$(function () {
177 $('[data-toggle="tooltip"]').tooltip()
178})
179
180
181$("#id_eventlog_file").change(function(){
182 $('#file_import').prop("disabled", false);
183 $('#file_import').addClass('btn-primary')
184 $('#file_import').removeClass('btn-default')
185})
186
187$(document).ajaxStart(function(){
188 $('#overlay').removeClass('hide');
189 window.setTimeout(
190 function() {
191 window.location = '/toastergui/builds/'
192 }, 10000)
193});
194
195$( "#form_file").on( "submit", function( event ) {
196 $('#overlay').removeClass('hide');
197 window.setTimeout(
198 function() {
199 window.location = '/toastergui/builds/'
200 }, 10000)
201});
202
203$(document).ready( function () {
204 $('#eventlog-table').DataTable({order: [[0, 'desc']], "pageLength": 50});
205});
206
207</script>
208
209{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/configvars.html b/bitbake/lib/toaster/toastergui/templates/configvars.html
index 33fef9316d..691dace3a2 100644
--- a/bitbake/lib/toaster/toastergui/templates/configvars.html
+++ b/bitbake/lib/toaster/toastergui/templates/configvars.html
@@ -66,7 +66,7 @@
66 <td class="description"> 66 <td class="description">
67 {% if variable.description %} 67 {% if variable.description %}
68 {{variable.description}} 68 {{variable.description}}
69 <a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-{{variable.variable_name|variable_parent_name}}" target="_blank"> 69 <a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-{{variable.variable_name|variable_parent_name}}" target="_blank">
70 <span class="glyphicon glyphicon-new-window get-info"></span></a> 70 <span class="glyphicon glyphicon-new-window get-info"></span></a>
71 {% endif %} 71 {% endif %}
72 </td> 72 </td>
diff --git a/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html b/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html
index ca248962f0..41553c4f9d 100644
--- a/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html
+++ b/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html
@@ -11,7 +11,7 @@
11<script src="{% static 'js/layerDepsModal.js' %}"></script> 11<script src="{% static 'js/layerDepsModal.js' %}"></script>
12<script src="{% static 'js/projectpage.js' %}"></script> 12<script src="{% static 'js/projectpage.js' %}"></script>
13 13
14<script src="{% static 'js/bootstrap.min.js' %}"></script> 14<script src="{% static 'js/bootstrap-3.4.1.min.js' %}"></script>
15<script src="{% static 'js/filtersnippet.js' %}"></script> 15<script src="{% static 'js/filtersnippet.js' %}"></script>
16<script src="{% static 'js/importlayer.js' %}"></script> 16<script src="{% static 'js/importlayer.js' %}"></script>
17<script src="{% static 'js/highlight.pack.js' %}"></script> 17<script src="{% static 'js/highlight.pack.js' %}"></script>
diff --git a/bitbake/lib/toaster/toastergui/templates/landing.html b/bitbake/lib/toaster/toastergui/templates/landing.html
index bfaaf6fc83..589ee22634 100644
--- a/bitbake/lib/toaster/toastergui/templates/landing.html
+++ b/bitbake/lib/toaster/toastergui/templates/landing.html
@@ -12,10 +12,10 @@
12 <div class="col-md-6"> 12 <div class="col-md-6">
13 <h1>This is Toaster</h1> 13 <h1>This is Toaster</h1>
14 14
15 <p>A web interface to <a href="https://www.openembedded.org">OpenEmbedded</a> and <a href="https://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="https://www.yoctoproject.org">Yocto Project</a> build system.</p> 15 <p>A web interface to <a href="https://www.openembedded.org">OpenEmbedded</a> and <a href="https://docs.yoctoproject.org/bitbake.html">BitBake</a>, the <a href="https://www.yoctoproject.org">Yocto Project</a> build system.</p>
16 16
17 <p class="top-air"> 17 <p class="top-air">
18 <a class="btn btn-info btn-lg" href="https://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#toaster-manual-setup-and-use"> 18 <a class="btn btn-info btn-lg" href="http://docs.yoctoproject.org/toaster-manual/setup-and-use.html#setting-up-and-using-toaster" style="min-width: 460px;">
19 Toaster is ready to capture your command line builds 19 Toaster is ready to capture your command line builds
20 </a> 20 </a>
21 </p> 21 </p>
@@ -23,7 +23,7 @@
23 {% if lvs_nos %} 23 {% if lvs_nos %}
24 {% if project_enable %} 24 {% if project_enable %}
25 <p class="top-air"> 25 <p class="top-air">
26 <a class="btn btn-primary btn-lg" href="{% url 'newproject' %}"> 26 <a class="btn btn-primary btn-lg" href="{% url 'newproject' %}" style="min-width: 460px;">
27 Create your first Toaster project to run manage builds 27 Create your first Toaster project to run manage builds
28 </a> 28 </a>
29 </p> 29 </p>
@@ -33,7 +33,7 @@
33 Toaster has no layer information. Without layer information, you cannot run builds. To generate layer information you can: 33 Toaster has no layer information. Without layer information, you cannot run builds. To generate layer information you can:
34 <ul> 34 <ul>
35 <li> 35 <li>
36 <a href="https://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#layer-source">Configure a layer source</a> 36 <a href="http://docs.yoctoproject.org/toaster-manual/reference.html#layer-source">Configure a layer source</a>
37 </li> 37 </li>
38 <li> 38 <li>
39 <a href="{% url 'newproject' %}">Create a project</a>, then import layers 39 <a href="{% url 'newproject' %}">Create a project</a>, then import layers
@@ -42,9 +42,15 @@
42 </div> 42 </div>
43 {% endif %} 43 {% endif %}
44 44
45 <p class="top-air">
46 <a class="btn btn-info btn-lg" href="{% url 'cmdlines' %}" style="min-width: 460px;">
47 Import command line event logs from build directory
48 </a>
49 </p>
50
45 <ul class="list-unstyled lead"> 51 <ul class="list-unstyled lead">
46 <li> 52 <li>
47 <a href="https://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html"> 53 <a href="http://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual">
48 Read the Toaster manual 54 Read the Toaster manual
49 </a> 55 </a>
50 </li> 56 </li>
diff --git a/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html b/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html
deleted file mode 100644
index e7200b8412..0000000000
--- a/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html
+++ /dev/null
@@ -1,34 +0,0 @@
1{% extends "base.html" %}
2
3{% load static %}
4{% load projecttags %}
5{% load humanize %}
6
7{% block title %} Welcome to Toaster {% endblock %}
8
9{% block pagecontent %}
10
11 <div class="container">
12 <div class="row">
13 <!-- Empty - no build module -->
14 <div class="page-header top-air">
15 <h1>
16 This page only works with Toaster in 'Build' mode
17 </h1>
18 </div>
19 <div class="alert alert-info lead">
20 <p">
21 The 'Build' mode allows you to configure and run your Yocto Project builds from Toaster.
22 <ul>
23 <li><a href="https://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#intro-modes">
24 Read about the 'Build' mode
25 </a></li>
26 <li><a href="/">
27 View your builds
28 </a></li>
29 </ul>
30 </p>
31 </div>
32 </div>
33
34{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/layerdetails.html b/bitbake/lib/toaster/toastergui/templates/layerdetails.html
index 1e26e31c8b..923ca3bfe4 100644
--- a/bitbake/lib/toaster/toastergui/templates/layerdetails.html
+++ b/bitbake/lib/toaster/toastergui/templates/layerdetails.html
@@ -355,7 +355,7 @@
355 {% if layerversion.layer_source == layer_source.TYPE_LAYERINDEX %} 355 {% if layerversion.layer_source == layer_source.TYPE_LAYERINDEX %}
356 <dt>Layer index</dt> 356 <dt>Layer index</dt>
357 <dd> 357 <dd>
358 <a href="http://layers.openembedded.org/layerindex/branch/{{layerversion.release.name}}/layer/{{layerversion.layer.name}}">Layer index {{layerversion.layer.name}}</a> 358 <a href="https://layers.openembedded.org/layerindex/branch/{{layerversion.release.name}}/layer/{{layerversion.layer.name}}">Layer index {{layerversion.layer.name}}</a>
359 </dd> 359 </dd>
360 {% endif %} 360 {% endif %}
361 </dl> 361 </dl>
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
index 98d9fac822..9fc7dfaee4 100644
--- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html
+++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
@@ -63,7 +63,7 @@
63 <%/if%> 63 <%/if%>
64 </div> 64 </div>
65 65
66 <div data-build-state="<%:state%>"> 66 <div class="build-state" data-build-state="<%:state%>">
67 <%if state == 'Cloning'%> 67 <%if state == 'Cloning'%>
68 <%include tmpl='#cloning-repos-build-template'/%> 68 <%include tmpl='#cloning-repos-build-template'/%>
69 <%else state == 'Parsing'%> 69 <%else state == 'Parsing'%>
diff --git a/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html
index a5d5893571..2493954deb 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html
@@ -18,7 +18,7 @@
18 </ul> 18 </ul>
19 <div class="tab-content"> 19 <div class="tab-content">
20 <div class="tab-pane active" id="dependencies"> 20 <div class="tab-pane active" id="dependencies">
21 {% ifequal runtime_deps|length 0 %} 21 {% if runtime_deps|length == 0 %}
22 <div class="alert alert-info"> 22 <div class="alert alert-info">
23 <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies. 23 <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies.
24 </div> 24 </div>
@@ -54,8 +54,8 @@
54 {% endfor %} 54 {% endfor %}
55 </tbody> 55 </tbody>
56 </table> 56 </table>
57 {% endifequal %} 57 {% endif %}
58 {% ifnotequal other_deps|length 0 %} 58 {% if other_deps|length != 0 %}
59 <h3>Other runtime relationships</h3> 59 <h3>Other runtime relationships</h3>
60 <table class="table table-bordered table-hover"> 60 <table class="table table-bordered table-hover">
61 <thead> 61 <thead>
@@ -93,7 +93,7 @@
93 {% endfor %} 93 {% endfor %}
94 </tbody> 94 </tbody>
95 </table> 95 </table>
96 {% endifnotequal %} 96 {% endif %}
97 </div> <!-- tab-pane --> 97 </div> <!-- tab-pane -->
98 </div> <!-- tab-content --> 98 </div> <!-- tab-content -->
99{% endblock tabcontent %} 99{% endblock tabcontent %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
index 66f8e7f069..a4fcd2aa42 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
@@ -127,7 +127,7 @@
127 {% comment %} 127 {% comment %}
128 # Removed per team meeting of 1/29/2014 until 128 # Removed per team meeting of 1/29/2014 until
129 # decision on index search algorithm 129 # decision on index search algorithm
130 <a href="http://layers.openembedded.org" target="_blank"> 130 <a href="https://layers.openembedded.org" target="_blank">
131 <i class="glyphicon glyphicon-share get-info"></i> 131 <i class="glyphicon glyphicon-share get-info"></i>
132 </a> 132 </a>
133 {% endcomment %} 133 {% endcomment %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html
index 95e56ded26..1f5ed6d913 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html
@@ -14,7 +14,7 @@
14 {% include "package_included_tabs.html" with active_tab="dependencies" %} 14 {% include "package_included_tabs.html" with active_tab="dependencies" %}
15 <div class="tab-content"> 15 <div class="tab-content">
16 <div class="tab-pane active" id="dependencies"> 16 <div class="tab-pane active" id="dependencies">
17 {% ifnotequal runtime_deps|length 0 %} 17 {% if runtime_deps|length != 0 %}
18 <table class="table table-bordered table-hover"> 18 <table class="table table-bordered table-hover">
19 <thead> 19 <thead>
20 <tr> 20 <tr>
@@ -48,9 +48,9 @@
48 <div class="alert alert-info"> 48 <div class="alert alert-info">
49 <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies. 49 <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies.
50 </div> 50 </div>
51 {% endifnotequal %} 51 {% endif %}
52 52
53 {% ifnotequal other_deps|length 0 %} 53 {% if other_deps|length != 0 %}
54 <h3>Other runtime relationships</h3> 54 <h3>Other runtime relationships</h3>
55 <table class="table table-bordered table-hover"> 55 <table class="table table-bordered table-hover">
56 <thead> 56 <thead>
@@ -103,7 +103,7 @@
103 {% endfor %} 103 {% endfor %}
104 </tbody> 104 </tbody>
105 </table> 105 </table>
106 {% endifnotequal %} 106 {% endif %}
107 </div> <!-- end tab-pane --> 107 </div> <!-- end tab-pane -->
108 </div> <!-- end tab content --> 108 </div> <!-- end tab content -->
109 {% endwith %} 109 {% endwith %}
diff --git a/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html b/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html
index fb310c7fc7..dae4549e21 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html
@@ -15,7 +15,7 @@
15 <div class="tab-content"> 15 <div class="tab-content">
16 <div class="tab-pane active" id="brought-in-by"> 16 <div class="tab-pane active" id="brought-in-by">
17 17
18 {% ifequal reverse_count 0 %} 18 {% if reverse_count == 0 %}
19 <div class="alert alert-info"> 19 <div class="alert alert-info">
20 <strong>{{package.fullpackagespec}}</strong> has no reverse runtime dependencies. 20 <strong>{{package.fullpackagespec}}</strong> has no reverse runtime dependencies.
21 </div> 21 </div>
@@ -43,7 +43,7 @@
43 {% endfor %} 43 {% endfor %}
44 </tbody> 44 </tbody>
45 </table> 45 </table>
46 {% endifequal %} 46 {% endif %}
47 </div> <!-- end tab-pane --> 47 </div> <!-- end tab-pane -->
48 </div> <!-- end tab content --> 48 </div> <!-- end tab content -->
49 {% endwith %} 49 {% endwith %}
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html
index d8ad2c79dc..22239a82fd 100644
--- a/bitbake/lib/toaster/toastergui/templates/project.html
+++ b/bitbake/lib/toaster/toastergui/templates/project.html
@@ -139,7 +139,7 @@
139 <ul> 139 <ul>
140 <li><a href="{% url 'projectlayers' project.id %}">Choose from the layers compatible with this project</a></li> 140 <li><a href="{% url 'projectlayers' project.id %}">Choose from the layers compatible with this project</a></li>
141 <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li> 141 <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li>
142 <li><a href="https://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li> 142 <li><a href="http://docs.yoctoproject.org/dev-manual/common-tasks.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li>
143 <li>Or type a layer name below</li> 143 <li>Or type a layer name below</li>
144 </ul> 144 </ul>
145 </div> 145 </div>
diff --git a/bitbake/lib/toaster/toastergui/templates/project_specific.html b/bitbake/lib/toaster/toastergui/templates/project_specific.html
index 42725c0dba..76d45b1b39 100644
--- a/bitbake/lib/toaster/toastergui/templates/project_specific.html
+++ b/bitbake/lib/toaster/toastergui/templates/project_specific.html
@@ -137,7 +137,7 @@
137 <ul> 137 <ul>
138 <li><a href="{% url 'projectlayers' project.id %}">Choose from the layers compatible with this project</a></li> 138 <li><a href="{% url 'projectlayers' project.id %}">Choose from the layers compatible with this project</a></li>
139 <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li> 139 <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li>
140 <li><a href="https://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li> 140 <li><a href="http://docs.yoctoproject.org/dev-manual/common-tasks.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li>
141 <li>Or type a layer name below</li> 141 <li>Or type a layer name below</li>
142 </ul> 142 </ul>
143 </div> 143 </div>
diff --git a/bitbake/lib/toaster/toastergui/templates/projectconf.html b/bitbake/lib/toaster/toastergui/templates/projectconf.html
index bd49f1f585..c306835832 100644
--- a/bitbake/lib/toaster/toastergui/templates/projectconf.html
+++ b/bitbake/lib/toaster/toastergui/templates/projectconf.html
@@ -73,7 +73,7 @@
73 73
74 {% if image_install_append_defined %} 74 {% if image_install_append_defined %}
75 <dt> 75 <dt>
76 <span class="js-config-var-name js-config-var-managed-name">IMAGE_INSTALL_append</span> 76 <span class="js-config-var-name js-config-var-managed-name">IMAGE_INSTALL:append</span>
77 <span class="glyphicon glyphicon-question-sign get-help" title="Specifies additional packages to install into an image. If your build creates more than one image, the packages will be installed in all of them"></span> 77 <span class="glyphicon glyphicon-question-sign get-help" title="Specifies additional packages to install into an image. If your build creates more than one image, the packages will be installed in all of them"></span>
78 </dt> 78 </dt>
79 <dd class="variable-list"> 79 <dd class="variable-list">
@@ -83,7 +83,7 @@
83 <form id="change-image_install-form" class="form-inline" style="display:none;"> 83 <form id="change-image_install-form" class="form-inline" style="display:none;">
84 <div class="row"> 84 <div class="row">
85 <div class="col-md-4"> 85 <div class="col-md-4">
86 <span class="help-block">To set IMAGE_INSTALL_append to more than one package, type the package names separated by a space.</span> 86 <span class="help-block">To set IMAGE_INSTALL:append to more than one package, type the package names separated by a space.</span>
87 </div> 87 </div>
88 </div> 88 </div>
89 <div class="form-group"> 89 <div class="form-group">
@@ -167,8 +167,8 @@
167 {% for fstype in vars_fstypes %} 167 {% for fstype in vars_fstypes %}
168 <input type="hidden" class="js-checkbox-fstypes-list" value="{{fstype}}"> 168 <input type="hidden" class="js-checkbox-fstypes-list" value="{{fstype}}">
169 {% endfor %} 169 {% endfor %}
170 {% for b in vars_blacklist %} 170 {% for b in vars_disallowed %}
171 <input type="hidden" class="js-config-blacklist-name" value="{{b}}"> 171 <input type="hidden" class="js-config-disallowed-name" value="{{b}}">
172 {% endfor %} 172 {% endfor %}
173 {% for b in vars_managed %} 173 {% for b in vars_managed %}
174 <input type="hidden" class="js-config-managed-name" value="{{b}}"> 174 <input type="hidden" class="js-config-managed-name" value="{{b}}">
@@ -201,12 +201,12 @@
201 <p>Toaster cannot set any variables that impact 1) the configuration of the build servers, 201 <p>Toaster cannot set any variables that impact 1) the configuration of the build servers,
202 or 2) where artifacts produced by the build are stored. Such variables include: </p> 202 or 2) where artifacts produced by the build are stored. Such variables include: </p>
203 <p> 203 <p>
204 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-BB_DISKMON_DIRS" target="_blank">BB_DISKMON_DIRS</a></code> 204 <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-BB_DISKMON_DIRS" target="_blank">BB_DISKMON_DIRS</a></code>
205 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-BB_NUMBER_THREADS" target="_blank">BB_NUMBER_THREADS</a></code> 205 <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-BB_NUMBER_THREADS" target="_blank">BB_NUMBER_THREADS</a></code>
206 <code>CVS_PROXY_HOST</code> 206 <code>CVS_PROXY_HOST</code>
207 <code>CVS_PROXY_PORT</code> 207 <code>CVS_PROXY_PORT</code>
208 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-PARALLEL_MAKE" target="_blank">PARALLEL_MAKE</a></code> 208 <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-PARALLEL_MAKE" target="_blank">PARALLEL_MAKE</a></code>
209 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-TMPDIR" target="_blank">TMPDIR</a></code></p> 209 <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-TMPDIR" target="_blank">TMPDIR</a></code></p>
210 <p>Plus the following standard shell environment variables:</p> 210 <p>Plus the following standard shell environment variables:</p>
211 <p><code>http_proxy</code> <code>ftp_proxy</code> <code>https_proxy</code> <code>all_proxy</code></p> 211 <p><code>http_proxy</code> <code>ftp_proxy</code> <code>https_proxy</code> <code>all_proxy</code></p>
212 </div> 212 </div>
@@ -238,9 +238,9 @@ function validate_new_variable() {
238 } 238 }
239 } 239 }
240 240
241 var blacklist_configvars = document.getElementsByClassName('js-config-blacklist-name'); 241 var disallowed_configvars = document.getElementsByClassName('js-config-disallowed-name');
242 for (var i = 0, length = blacklist_configvars.length; i < length; i++) { 242 for (var i = 0, length = disallowed_configvars.length; i < length; i++) {
243 if (blacklist_configvars[i].value.toUpperCase() == variable.toUpperCase()) { 243 if (disallowed_configvars[i].value.toUpperCase() == variable.toUpperCase()) {
244 error_msg = "You cannot edit this variable in Toaster because it is set by the build servers"; 244 error_msg = "You cannot edit this variable in Toaster because it is set by the build servers";
245 } 245 }
246 } 246 }
@@ -771,10 +771,10 @@ $(document).ready(function() {
771 771
772 {% if image_install_append_defined %} 772 {% if image_install_append_defined %}
773 773
774 // init IMAGE_INSTALL_append trash icon 774 // init IMAGE_INSTALL:append trash icon
775 setDeleteTooltip($('#delete-image_install-icon')); 775 setDeleteTooltip($('#delete-image_install-icon'));
776 776
777 // change IMAGE_INSTALL_append variable 777 // change IMAGE_INSTALL:append variable
778 $('#change-image_install-icon').click(function() { 778 $('#change-image_install-icon').click(function() {
779 // preset the edit value 779 // preset the edit value
780 var current_val = $("span#image_install").text().trim(); 780 var current_val = $("span#image_install").text().trim();
@@ -814,7 +814,7 @@ $(document).ready(function() {
814 $('#apply-change-image_install').click(function(){ 814 $('#apply-change-image_install').click(function(){
815 // insure these non-empty values have single space prefix 815 // insure these non-empty values have single space prefix
816 var value = " " + $('#new-image_install').val().trim(); 816 var value = " " + $('#new-image_install').val().trim();
817 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+value}); 817 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL:append:'+value});
818 $('#image_install').text(value); 818 $('#image_install').text(value);
819 $('#image_install').removeClass('text-muted'); 819 $('#image_install').removeClass('text-muted');
820 $("#change-image_install-form").slideUp(function () { 820 $("#change-image_install-form").slideUp(function () {
@@ -826,10 +826,10 @@ $(document).ready(function() {
826 }); 826 });
827 }); 827 });
828 828
829 // delete IMAGE_INSTALL_append variable value 829 // delete IMAGE_INSTALL:append variable value
830 $('#delete-image_install-icon').click(function(){ 830 $('#delete-image_install-icon').click(function(){
831 $(this).tooltip('hide'); 831 $(this).tooltip('hide');
832 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+''}); 832 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL:append:'+''});
833 $('#image_install').parent().fadeOut(1000, function(){ 833 $('#image_install').parent().fadeOut(1000, function(){
834 $('#image_install').addClass('text-muted'); 834 $('#image_install').addClass('text-muted');
835 $('#image_install').text('Not set'); 835 $('#image_install').text('Not set');
@@ -1011,7 +1011,7 @@ $(document).ready(function() {
1011 $(".save").attr("disabled","disabled"); 1011 $(".save").attr("disabled","disabled");
1012 1012
1013 // Reload page if admin-removed core managed value is manually added back in 1013 // Reload page if admin-removed core managed value is manually added back in
1014 if (0 <= " DISTRO DL_DIR IMAGE_FSTYPES IMAGE_INSTALL_append PACKAGE_CLASSES SSTATE_DIR ".indexOf( " "+variable+" " )) { 1014 if (0 <= " DISTRO DL_DIR IMAGE_FSTYPES IMAGE_INSTALL:append PACKAGE_CLASSES SSTATE_DIR ".indexOf( " "+variable+" " )) {
1015 // delayed reload to avoid race condition with postEditAjaxRequest 1015 // delayed reload to avoid race condition with postEditAjaxRequest
1016 do_reload=true; 1016 do_reload=true;
1017 } 1017 }
diff --git a/bitbake/lib/toaster/toastergui/templates/recipe.html b/bitbake/lib/toaster/toastergui/templates/recipe.html
index 3f76e656fe..4b5301b548 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipe.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipe.html
@@ -186,9 +186,9 @@
186 <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i> 186 <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i>
187 </td> 187 </td>
188 <td> 188 <td>
189 {% ifnotequal task.sstate_result task.SSTATE_NA %} 189 {% if task.sstate_result != task.SSTATE_NA %}
190 {{task.get_sstate_result_display}} 190 {{task.get_sstate_result_display}}
191 {% endifnotequal %} 191 {% endif %}
192 </td> 192 </td>
193 193
194 </tr> 194 </tr>
diff --git a/bitbake/lib/toaster/toastergui/templates/target.html b/bitbake/lib/toaster/toastergui/templates/target.html
index 1924a0dad7..d5f60e77a8 100644
--- a/bitbake/lib/toaster/toastergui/templates/target.html
+++ b/bitbake/lib/toaster/toastergui/templates/target.html
@@ -8,11 +8,11 @@
8 8
9{% block nav-target %} 9{% block nav-target %}
10 {% for t in build.get_sorted_target_list %} 10 {% for t in build.get_sorted_target_list %}
11 {% ifequal target.pk t.pk %} 11 {% if target.pk == t.pk %}
12 <li class="active"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> 12 <li class="active"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
13 {% else %} 13 {% else %}
14 <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> 14 <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
15 {% endifequal %} 15 {% endif %}
16 {% endfor %} 16 {% endfor %}
17{% endblock %} 17{% endblock %}
18 18
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
index c432f59a78..aee9bbcd14 100644
--- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
+++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py
@@ -167,8 +167,8 @@ def check_filter_status(options, filter):
167def variable_parent_name(value): 167def variable_parent_name(value):
168 """ filter extended variable names to the parent name 168 """ filter extended variable names to the parent name
169 """ 169 """
170 value=re.sub('_\$.*', '', value) 170 value = re.sub(r'_\$.*', '', value)
171 return re.sub('_[a-z].*', '', value) 171 return re.sub(r'_[a-z].*', '', value)
172 172
173@register.filter 173@register.filter
174def filter_setin_files(file_list, matchstr): 174def filter_setin_files(file_list, matchstr):
@@ -233,7 +233,6 @@ def filter_sizeovertotal(package_object, total_size):
233 233
234 return '{:.1%}'.format(float(size)/float(total_size)) 234 return '{:.1%}'.format(float(size)/float(total_size))
235 235
236from django.utils.safestring import mark_safe
237@register.filter 236@register.filter
238def format_vpackage_rowclass(size): 237def format_vpackage_rowclass(size):
239 if size == -1: 238 if size == -1:
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index d2df4e6048..7f8489d3aa 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -6,7 +6,7 @@
6# SPDX-License-Identifier: GPL-2.0-only 6# SPDX-License-Identifier: GPL-2.0-only
7# 7#
8 8
9from django.conf.urls import url 9from django.urls import re_path as url
10from django.views.generic import RedirectView 10from django.views.generic import RedirectView
11 11
12from toastergui import tables 12from toastergui import tables
@@ -95,6 +95,7 @@ urlpatterns = [
95 # project URLs 95 # project URLs
96 url(r'^newproject/$', views.newproject, name='newproject'), 96 url(r'^newproject/$', views.newproject, name='newproject'),
97 97
98 url(r'^cmdline/$', views.CommandLineBuilds.as_view(), name='cmdlines'),
98 url(r'^projects/$', 99 url(r'^projects/$',
99 tables.ProjectsTable.as_view(template_name="projects-toastertable.html"), 100 tables.ProjectsTable.as_view(template_name="projects-toastertable.html"),
100 name='all-projects'), 101 name='all-projects'),
@@ -206,8 +207,7 @@ urlpatterns = [
206 url(r'^js-unit-tests/$', views.jsunittests, name='js-unit-tests'), 207 url(r'^js-unit-tests/$', views.jsunittests, name='js-unit-tests'),
207 208
208 # image customisation functionality 209 # image customisation functionality
209 url(r'^xhr_customrecipe/(?P<recipe_id>\d+)' 210 url(r'^xhr_customrecipe/(?P<recipe_id>\d+)/packages/(?P<package_id>\d+|)$',
210 '/packages/(?P<package_id>\d+|)$',
211 api.XhrCustomRecipePackages.as_view(), 211 api.XhrCustomRecipePackages.as_view(),
212 name='xhr_customrecipe_packages'), 212 name='xhr_customrecipe_packages'),
213 213
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 9a5e48e3bb..061e6436c8 100644
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -6,24 +6,36 @@
6# SPDX-License-Identifier: GPL-2.0-only 6# SPDX-License-Identifier: GPL-2.0-only
7# 7#
8 8
9import ast
9import re 10import re
11import subprocess
12import sys
13
14import bb.cooker
15from bb.ui import toasterui
16from bb.ui import eventreplay
10 17
11from django.db.models import F, Q, Sum 18from django.db.models import F, Q, Sum
12from django.db import IntegrityError 19from django.db import IntegrityError
13from django.shortcuts import render, redirect, get_object_or_404 20from django.shortcuts import render, redirect, get_object_or_404, HttpResponseRedirect
14from django.utils.http import urlencode 21from django.utils.http import urlencode
15from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe 22from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe
16from orm.models import LogMessage, Variable, Package_Dependency, Package 23from orm.models import LogMessage, Variable, Package_Dependency, Package
17from orm.models import Task_Dependency, Package_File 24from orm.models import Task_Dependency, Package_File
18from orm.models import Target_Installed_Package, Target_File 25from orm.models import Target_Installed_Package, Target_File
19from orm.models import TargetKernelFile, TargetSDKFile, Target_Image_File 26from orm.models import TargetKernelFile, TargetSDKFile, Target_Image_File
20from orm.models import BitbakeVersion, CustomImageRecipe 27from orm.models import BitbakeVersion, CustomImageRecipe, EventLogsImports
21 28
22from django.urls import reverse, resolve 29from django.urls import reverse, resolve
30from django.contrib import messages
31
23from django.core.exceptions import ObjectDoesNotExist 32from django.core.exceptions import ObjectDoesNotExist
33from django.core.files.storage import FileSystemStorage
34from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile
24from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 35from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
25from django.http import HttpResponseNotFound, JsonResponse 36from django.http import HttpResponseNotFound, JsonResponse
26from django.utils import timezone 37from django.utils import timezone
38from django.views.generic import TemplateView
27from datetime import timedelta, datetime 39from datetime import timedelta, datetime
28from toastergui.templatetags.projecttags import json as jsonfilter 40from toastergui.templatetags.projecttags import json as jsonfilter
29from decimal import Decimal 41from decimal import Decimal
@@ -32,13 +44,20 @@ import os
32from os.path import dirname 44from os.path import dirname
33import mimetypes 45import mimetypes
34 46
47from toastergui.forms import LoadFileForm
48
49from collections import namedtuple
50
35import logging 51import logging
36 52
53from toastermain.logs import log_view_mixin
54
37logger = logging.getLogger("toaster") 55logger = logging.getLogger("toaster")
38 56
39# Project creation and managed build enable 57# Project creation and managed build enable
40project_enable = ('1' == os.environ.get('TOASTER_BUILDSERVER')) 58project_enable = ('1' == os.environ.get('TOASTER_BUILDSERVER'))
41is_project_specific = ('1' == os.environ.get('TOASTER_PROJECTSPECIFIC')) 59is_project_specific = ('1' == os.environ.get('TOASTER_PROJECTSPECIFIC'))
60import_page = False
42 61
43class MimeTypeFinder(object): 62class MimeTypeFinder(object):
44 # setting this to False enables additional non-standard mimetypes 63 # setting this to False enables additional non-standard mimetypes
@@ -56,6 +75,7 @@ class MimeTypeFinder(object):
56 return guessed_type 75 return guessed_type
57 76
58# single point to add global values into the context before rendering 77# single point to add global values into the context before rendering
78@log_view_mixin
59def toaster_render(request, page, context): 79def toaster_render(request, page, context):
60 context['project_enable'] = project_enable 80 context['project_enable'] = project_enable
61 context['project_specific'] = is_project_specific 81 context['project_specific'] = is_project_specific
@@ -352,7 +372,6 @@ def _get_parameters_values(request, default_count, default_order):
352# set cookies for parameters. this is usefull in case parameters are set 372# set cookies for parameters. this is usefull in case parameters are set
353# manually from the GET values of the link 373# manually from the GET values of the link
354def _set_parameters_values(pagesize, orderby, request): 374def _set_parameters_values(pagesize, orderby, request):
355 from django.urls import resolve
356 current_url = resolve(request.path_info).url_name 375 current_url = resolve(request.path_info).url_name
357 request.session['%s_count' % current_url] = pagesize 376 request.session['%s_count' % current_url] = pagesize
358 request.session['%s_orderby' % current_url] =orderby 377 request.session['%s_orderby' % current_url] =orderby
@@ -665,20 +684,20 @@ def recipe_packages(request, build_id, recipe_id):
665 return response 684 return response
666 685
667from django.http import HttpResponse 686from django.http import HttpResponse
687@log_view_mixin
668def xhr_dirinfo(request, build_id, target_id): 688def xhr_dirinfo(request, build_id, target_id):
669 top = request.GET.get('start', '/') 689 top = request.GET.get('start', '/')
670 return HttpResponse(_get_dir_entries(build_id, target_id, top), content_type = "application/json") 690 return HttpResponse(_get_dir_entries(build_id, target_id, top), content_type = "application/json")
671 691
672from django.utils.functional import Promise 692from django.utils.functional import Promise
673from django.utils.encoding import force_text 693from django.utils.encoding import force_str
674class LazyEncoder(json.JSONEncoder): 694class LazyEncoder(json.JSONEncoder):
675 def default(self, obj): 695 def default(self, obj):
676 if isinstance(obj, Promise): 696 if isinstance(obj, Promise):
677 return force_text(obj) 697 return force_str(obj)
678 return super(LazyEncoder, self).default(obj) 698 return super(LazyEncoder, self).default(obj)
679 699
680from toastergui.templatetags.projecttags import filtered_filesizeformat 700from toastergui.templatetags.projecttags import filtered_filesizeformat
681import os
682def _get_dir_entries(build_id, target_id, start): 701def _get_dir_entries(build_id, target_id, start):
683 node_str = { 702 node_str = {
684 Target_File.ITYPE_REGULAR : '-', 703 Target_File.ITYPE_REGULAR : '-',
@@ -1404,7 +1423,7 @@ if True:
1404 if not os.path.isdir('%s/conf' % request.POST['importdir']): 1423 if not os.path.isdir('%s/conf' % request.POST['importdir']):
1405 raise BadParameterException("Bad path or missing 'conf' directory (%s)" % request.POST['importdir']) 1424 raise BadParameterException("Bad path or missing 'conf' directory (%s)" % request.POST['importdir'])
1406 from django.core import management 1425 from django.core import management
1407 management.call_command('buildimport', '--command=import', '--name=%s' % request.POST['projectname'], '--path=%s' % request.POST['importdir'], interactive=False) 1426 management.call_command('buildimport', '--command=import', '--name=%s' % request.POST['projectname'], '--path=%s' % request.POST['importdir'])
1408 prj = Project.objects.get(name = request.POST['projectname']) 1427 prj = Project.objects.get(name = request.POST['projectname'])
1409 prj.merged_attr = True 1428 prj.merged_attr = True
1410 prj.save() 1429 prj.save()
@@ -1606,12 +1625,13 @@ if True:
1606 # make sure we have a machine set for this project 1625 # make sure we have a machine set for this project
1607 ProjectVariable.objects.get_or_create(project=new_project, 1626 ProjectVariable.objects.get_or_create(project=new_project,
1608 name="MACHINE", 1627 name="MACHINE",
1609 value="qemux86") 1628 value="qemux86-64")
1610 context = {'project': new_project} 1629 context = {'project': new_project}
1611 return toaster_render(request, "js-unit-tests.html", context) 1630 return toaster_render(request, "js-unit-tests.html", context)
1612 1631
1613 from django.views.decorators.csrf import csrf_exempt 1632 from django.views.decorators.csrf import csrf_exempt
1614 @csrf_exempt 1633 @csrf_exempt
1634 @log_view_mixin
1615 def xhr_testreleasechange(request, pid): 1635 def xhr_testreleasechange(request, pid):
1616 def response(data): 1636 def response(data):
1617 return HttpResponse(jsonfilter(data), 1637 return HttpResponse(jsonfilter(data),
@@ -1648,6 +1668,7 @@ if True:
1648 except Exception as e: 1668 except Exception as e:
1649 return response({"error": str(e) }) 1669 return response({"error": str(e) })
1650 1670
1671 @log_view_mixin
1651 def xhr_configvaredit(request, pid): 1672 def xhr_configvaredit(request, pid):
1652 try: 1673 try:
1653 prj = Project.objects.get(id = pid) 1674 prj = Project.objects.get(id = pid)
@@ -1683,12 +1704,12 @@ if True:
1683 t=request.POST['configvarDel'].strip() 1704 t=request.POST['configvarDel'].strip()
1684 pt = ProjectVariable.objects.get(pk = int(t)).delete() 1705 pt = ProjectVariable.objects.get(pk = int(t)).delete()
1685 1706
1686 # return all project settings, filter out blacklist and elsewhere-managed variables 1707 # return all project settings, filter out disallowed and elsewhere-managed variables
1687 vars_managed,vars_fstypes,vars_blacklist = get_project_configvars_context() 1708 vars_managed,vars_fstypes,vars_disallowed = get_project_configvars_context()
1688 configvars_query = ProjectVariable.objects.filter(project_id = pid).all() 1709 configvars_query = ProjectVariable.objects.filter(project_id = pid).all()
1689 for var in vars_managed: 1710 for var in vars_managed:
1690 configvars_query = configvars_query.exclude(name = var) 1711 configvars_query = configvars_query.exclude(name = var)
1691 for var in vars_blacklist: 1712 for var in vars_disallowed:
1692 configvars_query = configvars_query.exclude(name = var) 1713 configvars_query = configvars_query.exclude(name = var)
1693 1714
1694 return_data = { 1715 return_data = {
@@ -1708,7 +1729,7 @@ if True:
1708 except ProjectVariable.DoesNotExist: 1729 except ProjectVariable.DoesNotExist:
1709 pass 1730 pass
1710 try: 1731 try:
1711 return_data['image_install_append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL_append").value, 1732 return_data['image_install:append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL:append").value,
1712 except ProjectVariable.DoesNotExist: 1733 except ProjectVariable.DoesNotExist:
1713 pass 1734 pass
1714 try: 1735 try:
@@ -1726,6 +1747,7 @@ if True:
1726 return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") 1747 return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
1727 1748
1728 1749
1750 @log_view_mixin
1729 def customrecipe_download(request, pid, recipe_id): 1751 def customrecipe_download(request, pid, recipe_id):
1730 recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id) 1752 recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id)
1731 1753
@@ -1781,7 +1803,7 @@ if True:
1781 'MACHINE', 'BBLAYERS' 1803 'MACHINE', 'BBLAYERS'
1782 } 1804 }
1783 1805
1784 vars_blacklist = { 1806 vars_disallowed = {
1785 'PARALLEL_MAKE','BB_NUMBER_THREADS', 1807 'PARALLEL_MAKE','BB_NUMBER_THREADS',
1786 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT', 1808 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT',
1787 'PARALLEL_MAKE','TMPDIR', 1809 'PARALLEL_MAKE','TMPDIR',
@@ -1790,7 +1812,7 @@ if True:
1790 1812
1791 vars_fstypes = Target_Image_File.SUFFIXES 1813 vars_fstypes = Target_Image_File.SUFFIXES
1792 1814
1793 return(vars_managed,sorted(vars_fstypes),vars_blacklist) 1815 return(vars_managed,sorted(vars_fstypes),vars_disallowed)
1794 1816
1795 def projectconf(request, pid): 1817 def projectconf(request, pid):
1796 1818
@@ -1799,12 +1821,12 @@ if True:
1799 except Project.DoesNotExist: 1821 except Project.DoesNotExist:
1800 return HttpResponseNotFound("<h1>Project id " + pid + " is unavailable</h1>") 1822 return HttpResponseNotFound("<h1>Project id " + pid + " is unavailable</h1>")
1801 1823
1802 # remove blacklist and externally managed varaibles from this list 1824 # remove disallowed and externally managed varaibles from this list
1803 vars_managed,vars_fstypes,vars_blacklist = get_project_configvars_context() 1825 vars_managed,vars_fstypes,vars_disallowed = get_project_configvars_context()
1804 configvars = ProjectVariable.objects.filter(project_id = pid).all() 1826 configvars = ProjectVariable.objects.filter(project_id = pid).all()
1805 for var in vars_managed: 1827 for var in vars_managed:
1806 configvars = configvars.exclude(name = var) 1828 configvars = configvars.exclude(name = var)
1807 for var in vars_blacklist: 1829 for var in vars_disallowed:
1808 configvars = configvars.exclude(name = var) 1830 configvars = configvars.exclude(name = var)
1809 1831
1810 context = { 1832 context = {
@@ -1812,7 +1834,7 @@ if True:
1812 'configvars': configvars, 1834 'configvars': configvars,
1813 'vars_managed': vars_managed, 1835 'vars_managed': vars_managed,
1814 'vars_fstypes': vars_fstypes, 1836 'vars_fstypes': vars_fstypes,
1815 'vars_blacklist': vars_blacklist, 1837 'vars_disallowed': vars_disallowed,
1816 } 1838 }
1817 1839
1818 try: 1840 try:
@@ -1839,7 +1861,7 @@ if True:
1839 except ProjectVariable.DoesNotExist: 1861 except ProjectVariable.DoesNotExist:
1840 pass 1862 pass
1841 try: 1863 try:
1842 context['image_install_append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL_append").value 1864 context['image_install:append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL:append").value
1843 context['image_install_append_defined'] = "1" 1865 context['image_install_append_defined'] = "1"
1844 except ProjectVariable.DoesNotExist: 1866 except ProjectVariable.DoesNotExist:
1845 pass 1867 pass
@@ -1933,3 +1955,163 @@ if True:
1933 except (ObjectDoesNotExist, IOError): 1955 except (ObjectDoesNotExist, IOError):
1934 return toaster_render(request, "unavailable_artifact.html") 1956 return toaster_render(request, "unavailable_artifact.html")
1935 1957
1958
1959class CommandLineBuilds(TemplateView):
1960 model = EventLogsImports
1961 template_name = 'command_line_builds.html'
1962
1963 def get_context_data(self, **kwargs):
1964 context = super(CommandLineBuilds, self).get_context_data(**kwargs)
1965 #get value from BB_DEFAULT_EVENTLOG defined in bitbake.conf
1966 eventlog = subprocess.check_output(['bitbake-getvar', 'BB_DEFAULT_EVENTLOG', '--value'])
1967 if eventlog:
1968 logs_dir = os.path.dirname(eventlog.decode().strip('\n'))
1969 files = os.listdir(logs_dir)
1970 imported_files = EventLogsImports.objects.all()
1971 files_list = []
1972
1973 # Filter files that end with ".json"
1974 event_files = []
1975 for file in files:
1976 if file.endswith(".json"):
1977 # because BB_DEFAULT_EVENTLOG is a directory, we need to check if the file is a valid eventlog
1978 with open("{}/{}".format(logs_dir, file)) as efile:
1979 content = efile.read()
1980 if 'allvariables' in content:
1981 event_files.append(file)
1982
1983 #build dict for template using db data
1984 for event_file in event_files:
1985 if imported_files.filter(name=event_file):
1986 files_list.append({
1987 'name': event_file,
1988 'imported': True,
1989 'build_id': imported_files.filter(name=event_file)[0].build_id,
1990 'size': os.path.getsize("{}/{}".format(logs_dir, event_file))
1991 })
1992 else:
1993 files_list.append({
1994 'name': event_file,
1995 'imported': False,
1996 'build_id': None,
1997 'size': os.path.getsize("{}/{}".format(logs_dir, event_file))
1998 })
1999 context['import_all'] = True
2000
2001 context['files'] = files_list
2002 context['dir'] = logs_dir
2003 else:
2004 context['files'] = []
2005 context['dir'] = ''
2006
2007 # enable session variable
2008 if not self.request.session.get('file'):
2009 self.request.session['file'] = ""
2010
2011 context['form'] = LoadFileForm()
2012 context['project_enable'] = project_enable
2013 return context
2014
2015 def post(self, request, **kwargs):
2016 logs_dir = request.POST.get('dir')
2017 all_files = request.POST.get('all')
2018
2019 # check if a build is already in progress
2020 if Build.objects.filter(outcome=Build.IN_PROGRESS):
2021 messages.add_message(
2022 self.request,
2023 messages.ERROR,
2024 "A build is already in progress. Please wait for it to complete before starting a new build."
2025 )
2026 return JsonResponse({'response': 'building'})
2027 imported_files = EventLogsImports.objects.all()
2028 try:
2029 if all_files == 'true':
2030 # use of session variable to deactivate icon for builds in progress
2031 request.session['all_builds'] = True
2032 request.session.modified = True
2033 request.session.save()
2034
2035 files = ast.literal_eval(request.POST.get('file'))
2036 for file in files:
2037 if imported_files.filter(name=file.get('name')).exists():
2038 imported_files.filter(name=file.get('name'))[0].imported = True
2039 else:
2040 with open("{}/{}".format(logs_dir, file.get('name'))) as eventfile:
2041 # load variables from the first line
2042 variables = None
2043 while line := eventfile.readline().strip():
2044 try:
2045 variables = json.loads(line)['allvariables']
2046 break
2047 except (KeyError, json.JSONDecodeError):
2048 continue
2049 if not variables:
2050 raise Exception("File content missing build variables")
2051 eventfile.seek(0)
2052 params = namedtuple('ConfigParams', ['observe_only'])(True)
2053 player = eventreplay.EventPlayer(eventfile, variables)
2054
2055 toasterui.main(player, player, params)
2056 event_log_import = EventLogsImports.objects.create(name=file.get('name'), imported=True)
2057 event_log_import.build_id = Build.objects.last().id
2058 event_log_import.save()
2059 else:
2060 if self.request.FILES.get('eventlog_file'):
2061 file = self.request.FILES['eventlog_file']
2062 else:
2063 file = request.POST.get('file')
2064 # use of session variable to deactivate icon for build in progress
2065 request.session['file'] = file
2066 request.session['all_builds'] = False
2067 request.session.modified = True
2068 request.session.save()
2069
2070 if imported_files.filter(name=file).exists():
2071 imported_files.filter(name=file)[0].imported = True
2072 else:
2073 if isinstance(file, InMemoryUploadedFile) or isinstance(file, TemporaryUploadedFile):
2074 variables = None
2075 while line := file.readline().strip():
2076 try:
2077 variables = json.loads(line)['allvariables']
2078 break
2079 except (KeyError, json.JSONDecodeError):
2080 continue
2081 if not variables:
2082 raise Exception("File content missing build variables")
2083 file.seek(0)
2084 params = namedtuple('ConfigParams', ['observe_only'])(True)
2085 player = eventreplay.EventPlayer(file, variables)
2086 if not os.path.exists('{}/{}'.format(logs_dir, file.name)):
2087 fs = FileSystemStorage(location=logs_dir)
2088 fs.save(file.name, file)
2089 toasterui.main(player, player, params)
2090 else:
2091 with open("{}/{}".format(logs_dir, file)) as eventfile:
2092 # load variables from the first line
2093 variables = None
2094 while line := eventfile.readline().strip():
2095 try:
2096 variables = json.loads(line)['allvariables']
2097 break
2098 except (KeyError, json.JSONDecodeError):
2099 continue
2100 if not variables:
2101 raise Exception("File content missing build variables")
2102 eventfile.seek(0)
2103 params = namedtuple('ConfigParams', ['observe_only'])(True)
2104 player = eventreplay.EventPlayer(eventfile, variables)
2105 toasterui.main(player, player, params)
2106 event_log_import = EventLogsImports.objects.create(name=file, imported=True)
2107 event_log_import.build_id = Build.objects.last().id
2108 event_log_import.save()
2109 request.session['file'] = ""
2110 except Exception:
2111 messages.add_message(
2112 self.request,
2113 messages.ERROR,
2114 "The file content is not in the correct format. Update file content or upload a different file."
2115 )
2116 return HttpResponseRedirect("/toastergui/cmdline/")
2117 return HttpResponseRedirect('/toastergui/builds/')
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py
index ceff52942e..b32abf40b3 100644
--- a/bitbake/lib/toaster/toastergui/widgets.py
+++ b/bitbake/lib/toaster/toastergui/widgets.py
@@ -7,6 +7,7 @@
7# 7#
8 8
9from django.views.generic import View, TemplateView 9from django.views.generic import View, TemplateView
10from django.utils.decorators import method_decorator
10from django.views.decorators.cache import cache_control 11from django.views.decorators.cache import cache_control
11from django.shortcuts import HttpResponse 12from django.shortcuts import HttpResponse
12from django.core.cache import cache 13from django.core.cache import cache
@@ -31,6 +32,7 @@ import re
31import os 32import os
32 33
33from toastergui.tablefilter import TableFilterMap 34from toastergui.tablefilter import TableFilterMap
35from toastermain.logs import log_view_mixin
34 36
35try: 37try:
36 from urllib import unquote_plus 38 from urllib import unquote_plus
@@ -63,8 +65,8 @@ class ToasterTable(TemplateView):
63 self.default_orderby = "" 65 self.default_orderby = ""
64 66
65 # prevent HTTP caching of table data 67 # prevent HTTP caching of table data
66 @cache_control(must_revalidate=True, 68 @method_decorator(cache_control(must_revalidate=True,
67 max_age=0, no_store=True, no_cache=True) 69 max_age=0, no_store=True, no_cache=True))
68 def dispatch(self, *args, **kwargs): 70 def dispatch(self, *args, **kwargs):
69 return super(ToasterTable, self).dispatch(*args, **kwargs) 71 return super(ToasterTable, self).dispatch(*args, **kwargs)
70 72
@@ -83,6 +85,7 @@ class ToasterTable(TemplateView):
83 85
84 return context 86 return context
85 87
88 @log_view_mixin
86 def get(self, request, *args, **kwargs): 89 def get(self, request, *args, **kwargs):
87 if request.GET.get('format', None) == 'json': 90 if request.GET.get('format', None) == 'json':
88 91
@@ -304,6 +307,7 @@ class ToasterTable(TemplateView):
304 307
305 self.setup_columns(**kwargs) 308 self.setup_columns(**kwargs)
306 309
310 self.apply_orderby('pk')
307 if search: 311 if search:
308 self.apply_search(search) 312 self.apply_search(search)
309 if filters: 313 if filters:
@@ -413,6 +417,7 @@ class ToasterTypeAhead(View):
413 def __init__(self, *args, **kwargs): 417 def __init__(self, *args, **kwargs):
414 super(ToasterTypeAhead, self).__init__() 418 super(ToasterTypeAhead, self).__init__()
415 419
420 @log_view_mixin
416 def get(self, request, *args, **kwargs): 421 def get(self, request, *args, **kwargs):
417 def response(data): 422 def response(data):
418 return HttpResponse(json.dumps(data, 423 return HttpResponse(json.dumps(data,
@@ -468,6 +473,7 @@ class MostRecentBuildsView(View):
468 473
469 return False 474 return False
470 475
476 @log_view_mixin
471 def get(self, request, *args, **kwargs): 477 def get(self, request, *args, **kwargs):
472 """ 478 """
473 Returns a list of builds in JSON format. 479 Returns a list of builds in JSON format.
diff --git a/bitbake/lib/toaster/toastermain/logs.py b/bitbake/lib/toaster/toastermain/logs.py
new file mode 100644
index 0000000000..62d871963a
--- /dev/null
+++ b/bitbake/lib/toaster/toastermain/logs.py
@@ -0,0 +1,158 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4import os
5import logging
6import json
7from pathlib import Path
8from django.http import HttpRequest
9
10BUILDDIR = Path(os.environ.get('BUILDDIR', '/tmp'))
11
12def log_api_request(request, response, view, logger_name='api'):
13 """Helper function for LogAPIMixin"""
14
15 repjson = {
16 'view': view,
17 'path': request.path,
18 'method': request.method,
19 'status': response.status_code
20 }
21
22 logger = logging.getLogger(logger_name)
23 logger.info(
24 json.dumps(repjson, indent=4, separators=(", ", " : "))
25 )
26
27
28def log_view_mixin(view):
29 def log_view_request(*args, **kwargs):
30 # get request from args else kwargs
31 request = None
32 if len(args) > 0:
33 for req in args:
34 if isinstance(req, HttpRequest):
35 request = req
36 break
37 elif request is None:
38 request = kwargs.get('request')
39
40 response = view(*args, **kwargs)
41 view_name = 'unknown'
42 if hasattr(request, 'resolver_match'):
43 if hasattr(request.resolver_match, 'view_name'):
44 view_name = request.resolver_match.view_name
45
46 log_api_request(
47 request, response, view_name, 'toaster')
48 return response
49 return log_view_request
50
51
52
53class LogAPIMixin:
54 """Logs API requests
55
56 tested with:
57 - APIView
58 - ModelViewSet
59 - ReadOnlyModelViewSet
60 - GenericAPIView
61
62 Note: you can set `view_name` attribute in View to override get_view_name()
63 """
64
65 def get_view_name(self):
66 if hasattr(self, 'view_name'):
67 return self.view_name
68 return super().get_view_name()
69
70 def finalize_response(self, request, response, *args, **kwargs):
71 log_api_request(request, response, self.get_view_name())
72 return super().finalize_response(request, response, *args, **kwargs)
73
74
75LOGGING_SETTINGS = {
76 'version': 1,
77 'disable_existing_loggers': False,
78 'filters': {
79 'require_debug_false': {
80 '()': 'django.utils.log.RequireDebugFalse'
81 }
82 },
83 'formatters': {
84 'datetime': {
85 'format': '%(asctime)s %(levelname)s %(message)s'
86 },
87 'verbose': {
88 'format': '{levelname} {asctime} {module} {name}.{funcName} {process:d} {thread:d} {message}',
89 'datefmt': "%d/%b/%Y %H:%M:%S",
90 'style': '{',
91 },
92 'api': {
93 'format': '\n{levelname} {asctime} {name}.{funcName}:\n{message}',
94 'style': '{'
95 }
96 },
97 'handlers': {
98 'mail_admins': {
99 'level': 'ERROR',
100 'filters': ['require_debug_false'],
101 'class': 'django.utils.log.AdminEmailHandler'
102 },
103 'console': {
104 'level': 'DEBUG',
105 'class': 'logging.StreamHandler',
106 'formatter': 'datetime',
107 },
108 'file_django': {
109 'level': 'INFO',
110 'class': 'logging.handlers.TimedRotatingFileHandler',
111 'filename': BUILDDIR / 'toaster_logs/django.log',
112 'when': 'D', # interval type
113 'interval': 1, # defaults to 1
114 'backupCount': 10, # how many files to keep
115 'formatter': 'verbose',
116 },
117 'file_api': {
118 'level': 'INFO',
119 'class': 'logging.handlers.TimedRotatingFileHandler',
120 'filename': BUILDDIR / 'toaster_logs/api.log',
121 'when': 'D',
122 'interval': 1,
123 'backupCount': 10,
124 'formatter': 'verbose',
125 },
126 'file_toaster': {
127 'level': 'INFO',
128 'class': 'logging.handlers.TimedRotatingFileHandler',
129 'filename': BUILDDIR / 'toaster_logs/web.log',
130 'when': 'D',
131 'interval': 1,
132 'backupCount': 10,
133 'formatter': 'verbose',
134 },
135 },
136 'loggers': {
137 'django.request': {
138 'handlers': ['file_django', 'console'],
139 'level': 'WARN',
140 'propagate': True,
141 },
142 'django': {
143 'handlers': ['file_django', 'console'],
144 'level': 'WARNING',
145 'propogate': True,
146 },
147 'toaster': {
148 'handlers': ['file_toaster'],
149 'level': 'INFO',
150 'propagate': False,
151 },
152 'api': {
153 'handlers': ['file_api'],
154 'level': 'INFO',
155 'propagate': False,
156 }
157 }
158}
diff --git a/bitbake/lib/toaster/toastermain/management/commands/buildimport.py b/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
index 59da6ff7ac..f7139aa041 100644
--- a/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
+++ b/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
@@ -451,7 +451,7 @@ class Command(BaseCommand):
451 # Catch vars relevant to Toaster (in case no Toaster section) 451 # Catch vars relevant to Toaster (in case no Toaster section)
452 self.update_project_vars(project,'DISTRO') 452 self.update_project_vars(project,'DISTRO')
453 self.update_project_vars(project,'MACHINE') 453 self.update_project_vars(project,'MACHINE')
454 self.update_project_vars(project,'IMAGE_INSTALL_append') 454 self.update_project_vars(project,'IMAGE_INSTALL:append')
455 self.update_project_vars(project,'IMAGE_FSTYPES') 455 self.update_project_vars(project,'IMAGE_FSTYPES')
456 self.update_project_vars(project,'PACKAGE_CLASSES') 456 self.update_project_vars(project,'PACKAGE_CLASSES')
457 # These vars are typically only assigned by Toaster 457 # These vars are typically only assigned by Toaster
@@ -545,7 +545,7 @@ class Command(BaseCommand):
545 # Find the directory's release, and promote to default_release if local paths 545 # Find the directory's release, and promote to default_release if local paths
546 release = self.find_import_release(layers_list,lv_dict,default_release) 546 release = self.find_import_release(layers_list,lv_dict,default_release)
547 # create project, SANITY: reuse any project of same name 547 # create project, SANITY: reuse any project of same name
548 project = Project.objects.create_project(project_name,release,project) 548 project = Project.objects.create_project(project_name,release,project, imported=True)
549 # Apply any new layers or variables 549 # Apply any new layers or variables
550 self.apply_conf_variables(project,layers_list,lv_dict,release) 550 self.apply_conf_variables(project,layers_list,lv_dict,release)
551 # WORKAROUND: since we now derive the release, redirect 'newproject_specific' to 'project_specific' 551 # WORKAROUND: since we now derive the release, redirect 'newproject_specific' to 'project_specific'
diff --git a/bitbake/lib/toaster/toastermain/management/commands/checksocket.py b/bitbake/lib/toaster/toastermain/management/commands/checksocket.py
index 811fd5d516..b2c002da7a 100644
--- a/bitbake/lib/toaster/toastermain/management/commands/checksocket.py
+++ b/bitbake/lib/toaster/toastermain/management/commands/checksocket.py
@@ -13,7 +13,7 @@ import errno
13import socket 13import socket
14 14
15from django.core.management.base import BaseCommand, CommandError 15from django.core.management.base import BaseCommand, CommandError
16from django.utils.encoding import force_text 16from django.utils.encoding import force_str
17 17
18DEFAULT_ADDRPORT = "0.0.0.0:8000" 18DEFAULT_ADDRPORT = "0.0.0.0:8000"
19 19
@@ -51,7 +51,7 @@ class Command(BaseCommand):
51 if hasattr(err, 'errno') and err.errno in errors: 51 if hasattr(err, 'errno') and err.errno in errors:
52 errtext = errors[err.errno] 52 errtext = errors[err.errno]
53 else: 53 else:
54 errtext = force_text(err) 54 errtext = force_str(err)
55 raise CommandError(errtext) 55 raise CommandError(errtext)
56 56
57 self.stdout.write("OK") 57 self.stdout.write("OK")
diff --git a/bitbake/lib/toaster/toastermain/settings.py b/bitbake/lib/toaster/toastermain/settings.py
index a4b370c8d4..d2a449627f 100644
--- a/bitbake/lib/toaster/toastermain/settings.py
+++ b/bitbake/lib/toaster/toastermain/settings.py
@@ -9,6 +9,8 @@
9# Django settings for Toaster project. 9# Django settings for Toaster project.
10 10
11import os 11import os
12from pathlib import Path
13from toastermain.logs import LOGGING_SETTINGS
12 14
13DEBUG = True 15DEBUG = True
14 16
@@ -39,6 +41,9 @@ DATABASES = {
39 } 41 }
40} 42}
41 43
44# New in Django 3.2
45DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
46
42# Needed when Using sqlite especially to add a longer timeout for waiting 47# Needed when Using sqlite especially to add a longer timeout for waiting
43# for the database lock to be released 48# for the database lock to be released
44# https://docs.djangoproject.com/en/1.6/ref/databases/#database-is-locked-errors 49# https://docs.djangoproject.com/en/1.6/ref/databases/#database-is-locked-errors
@@ -84,14 +89,17 @@ else:
84 from pytz.exceptions import UnknownTimeZoneError 89 from pytz.exceptions import UnknownTimeZoneError
85 try: 90 try:
86 if pytz.timezone(zonename) is not None: 91 if pytz.timezone(zonename) is not None:
87 zonefilelist[hashlib.md5(open(filepath, 'rb').read()).hexdigest()] = zonename 92 with open(filepath, 'rb') as f:
93 zonefilelist[hashlib.md5(f.read()).hexdigest()] = zonename
88 except UnknownTimeZoneError as ValueError: 94 except UnknownTimeZoneError as ValueError:
89 # we expect timezone failures here, just move over 95 # we expect timezone failures here, just move over
90 pass 96 pass
91 except ImportError: 97 except ImportError:
92 zonefilelist[hashlib.md5(open(filepath, 'rb').read()).hexdigest()] = zonename 98 with open(filepath, 'rb') as f:
99 zonefilelist[hashlib.md5(f.read()).hexdigest()] = zonename
93 100
94 TIME_ZONE = zonefilelist[hashlib.md5(open('/etc/localtime', 'rb').read()).hexdigest()] 101 with open('/etc/localtime', 'rb') as f:
102 TIME_ZONE = zonefilelist[hashlib.md5(f.read()).hexdigest()]
95 103
96# Language code for this installation. All choices can be found here: 104# Language code for this installation. All choices can be found here:
97# http://www.i18nguy.com/unicode/language-identifiers.html 105# http://www.i18nguy.com/unicode/language-identifiers.html
@@ -103,10 +111,6 @@ SITE_ID = 1
103# to load the internationalization machinery. 111# to load the internationalization machinery.
104USE_I18N = True 112USE_I18N = True
105 113
106# If you set this to False, Django will not format dates, numbers and
107# calendars according to the current locale.
108USE_L10N = True
109
110# If you set this to False, Django will not use timezone-aware datetimes. 114# If you set this to False, Django will not use timezone-aware datetimes.
111USE_TZ = True 115USE_TZ = True
112 116
@@ -147,6 +151,8 @@ STATICFILES_FINDERS = (
147# Make this unique, and don't share it with anybody. 151# Make this unique, and don't share it with anybody.
148SECRET_KEY = 'NOT_SUITABLE_FOR_HOSTED_DEPLOYMENT' 152SECRET_KEY = 'NOT_SUITABLE_FOR_HOSTED_DEPLOYMENT'
149 153
154TMPDIR = os.environ.get('TOASTER_DJANGO_TMPDIR', '/tmp')
155
150class InvalidString(str): 156class InvalidString(str):
151 def __mod__(self, other): 157 def __mod__(self, other):
152 from django.template.base import TemplateSyntaxError 158 from django.template.base import TemplateSyntaxError
@@ -183,7 +189,13 @@ TEMPLATES = [
183 'django.template.loaders.app_directories.Loader', 189 'django.template.loaders.app_directories.Loader',
184 #'django.template.loaders.eggs.Loader', 190 #'django.template.loaders.eggs.Loader',
185 ], 191 ],
186 'string_if_invalid': InvalidString("%s"), 192 # https://docs.djangoproject.com/en/4.2/ref/templates/api/#how-invalid-variables-are-handled
193 # Generally, string_if_invalid should only be enabled in order to debug
194 # a specific template problem, then cleared once debugging is complete.
195 # If you assign a value other than '' to string_if_invalid,
196 # you will experience rendering problems with these templates and sites.
197 # 'string_if_invalid': InvalidString("%s"),
198 'string_if_invalid': "",
187 'debug': DEBUG, 199 'debug': DEBUG,
188 }, 200 },
189 }, 201 },
@@ -207,7 +219,7 @@ CACHES = {
207 # }, 219 # },
208 'default': { 220 'default': {
209 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 221 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
210 'LOCATION': '/tmp/toaster_cache_%d' % os.getuid(), 222 'LOCATION': '%s/toaster_cache_%d' % (TMPDIR, os.getuid()),
211 'TIMEOUT': 1, 223 'TIMEOUT': 1,
212 } 224 }
213 } 225 }
@@ -239,6 +251,9 @@ INSTALLED_APPS = (
239 'django.contrib.humanize', 251 'django.contrib.humanize',
240 'bldcollector', 252 'bldcollector',
241 'toastermain', 253 'toastermain',
254
255 # 3rd-lib
256 "log_viewer",
242) 257)
243 258
244 259
@@ -283,7 +298,6 @@ SOUTH_TESTS_MIGRATE = False
283 298
284# We automatically detect and install applications here if 299# We automatically detect and install applications here if
285# they have a 'models.py' or 'views.py' file 300# they have a 'models.py' or 'views.py' file
286import os
287currentdir = os.path.dirname(__file__) 301currentdir = os.path.dirname(__file__)
288for t in os.walk(os.path.dirname(currentdir)): 302for t in os.walk(os.path.dirname(currentdir)):
289 modulename = os.path.basename(t[0]) 303 modulename = os.path.basename(t[0])
@@ -299,43 +313,21 @@ for t in os.walk(os.path.dirname(currentdir)):
299# the site admins on every HTTP 500 error when DEBUG=False. 313# the site admins on every HTTP 500 error when DEBUG=False.
300# See http://docs.djangoproject.com/en/dev/topics/logging for 314# See http://docs.djangoproject.com/en/dev/topics/logging for
301# more details on how to customize your logging configuration. 315# more details on how to customize your logging configuration.
302LOGGING = { 316LOGGING = LOGGING_SETTINGS
303 'version': 1, 317
304 'disable_existing_loggers': False, 318# Build paths inside the project like this: BASE_DIR / 'subdir'.
305 'filters': { 319BUILDDIR = os.environ.get("BUILDDIR", TMPDIR)
306 'require_debug_false': { 320
307 '()': 'django.utils.log.RequireDebugFalse' 321# LOG VIEWER
308 } 322# https://pypi.org/project/django-log-viewer/
309 }, 323LOG_VIEWER_FILES_PATTERN = '*.log*'
310 'formatters': { 324LOG_VIEWER_FILES_DIR = os.path.join(BUILDDIR, "toaster_logs/")
311 'datetime': { 325LOG_VIEWER_PAGE_LENGTH = 25 # total log lines per-page
312 'format': '%(asctime)s %(levelname)s %(message)s' 326LOG_VIEWER_MAX_READ_LINES = 100000 # total log lines will be read
313 } 327LOG_VIEWER_PATTERNS = ['INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL']
314 }, 328
315 'handlers': { 329# Optionally you can set the next variables in order to customize the admin:
316 'mail_admins': { 330LOG_VIEWER_FILE_LIST_TITLE = "Logs list"
317 'level': 'ERROR',
318 'filters': ['require_debug_false'],
319 'class': 'django.utils.log.AdminEmailHandler'
320 },
321 'console': {
322 'level': 'DEBUG',
323 'class': 'logging.StreamHandler',
324 'formatter': 'datetime',
325 }
326 },
327 'loggers': {
328 'toaster' : {
329 'handlers': ['console'],
330 'level': 'DEBUG',
331 },
332 'django.request': {
333 'handlers': ['console'],
334 'level': 'WARN',
335 'propagate': True,
336 },
337 }
338}
339 331
340if DEBUG and SQL_DEBUG: 332if DEBUG and SQL_DEBUG:
341 LOGGING['loggers']['django.db.backends'] = { 333 LOGGING['loggers']['django.db.backends'] = {
diff --git a/bitbake/lib/toaster/toastermain/settings_test.py b/bitbake/lib/toaster/toastermain/settings_test.py
index 6538d9e453..74def2d240 100644
--- a/bitbake/lib/toaster/toastermain/settings_test.py
+++ b/bitbake/lib/toaster/toastermain/settings_test.py
@@ -19,10 +19,10 @@ TEMPLATE_DEBUG = DEBUG
19DATABASES = { 19DATABASES = {
20 'default': { 20 'default': {
21 'ENGINE': 'django.db.backends.sqlite3', 21 'ENGINE': 'django.db.backends.sqlite3',
22 'NAME': '/tmp/toaster-test-db.sqlite', 22 'NAME': '%s/toaster-test-db.sqlite' % TMPDIR,
23 'TEST': { 23 'TEST': {
24 'ENGINE': 'django.db.backends.sqlite3', 24 'ENGINE': 'django.db.backends.sqlite3',
25 'NAME': '/tmp/toaster-test-db.sqlite', 25 'NAME': '%s/toaster-test-db.sqlite' % TMPDIR,
26 } 26 }
27 } 27 }
28} 28}
diff --git a/bitbake/lib/toaster/toastermain/urls.py b/bitbake/lib/toaster/toastermain/urls.py
index 5fb520b384..3be46fcf0c 100644
--- a/bitbake/lib/toaster/toastermain/urls.py
+++ b/bitbake/lib/toaster/toastermain/urls.py
@@ -6,7 +6,7 @@
6# SPDX-License-Identifier: GPL-2.0-only 6# SPDX-License-Identifier: GPL-2.0-only
7# 7#
8 8
9from django.conf.urls import include, url 9from django.urls import re_path as url, include
10from django.views.generic import RedirectView, TemplateView 10from django.views.generic import RedirectView, TemplateView
11from django.views.decorators.cache import never_cache 11from django.views.decorators.cache import never_cache
12import bldcollector.views 12import bldcollector.views
@@ -28,6 +28,8 @@ urlpatterns = [
28 # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 28 # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
29 29
30 30
31 url(r'^logs/', include('log_viewer.urls')),
32
31 # This is here to maintain backward compatibility and will be deprecated 33 # This is here to maintain backward compatibility and will be deprecated
32 # in the future. 34 # in the future.
33 url(r'^orm/eventfile$', bldcollector.views.eventfile), 35 url(r'^orm/eventfile$', bldcollector.views.eventfile),
diff --git a/bitbake/lib/toaster/tox.ini b/bitbake/lib/toaster/tox.ini
new file mode 100644
index 0000000000..1516a527ae
--- /dev/null
+++ b/bitbake/lib/toaster/tox.ini
@@ -0,0 +1,24 @@
1[tox]
2envlist = py38, py39, py310, py311, py312
3skipsdist = True
4toxworkdir = {env:TOX_WORKDIR:.tox}
5passenv = *
6
7[testenv]
8passenv =
9 SSTATE_DIR
10 DL_DIR
11 TOASTER_DJANGO_TMPDIR
12setenv =
13 DJANGO_SETTINGS_MODULE=toastermain.settings_test
14 TOASTER_BUILDSERVER=1
15 BUILDDIR = {env:BUILDDIR}
16 EVENTREPLAY_DIR = {env:EVENTREPLAY_DIR:BUILDDIR}
17commands =
18 python3 {toxinidir}/manage.py test tests.db tests.commands tests.builds tests.browser tests.functional tests.views
19deps =
20 -r {toxinidir}/../../toaster-requirements.txt
21 -r {toxinidir}/tests/toaster-tests-requirements.txt
22
23[testenv:chrome]
24commands={[testenv]commands} --splinter-webdriver=chrome \ No newline at end of file