├── container
├── container-entrypoint.sh
├── favicon.xpm
└── whatcanidoforfedora-web.conf
├── requirements.txt
├── .coafile
├── static
├── jquery.uls
│ ├── img
│ │ ├── clear.png
│ │ ├── close.png
│ │ ├── search.png
│ │ ├── world_map.png
│ │ ├── icon-language.png
│ │ ├── clear.svg
│ │ ├── close.svg
│ │ ├── search.svg
│ │ ├── icon-language.svg
│ │ └── world_map.svg
│ ├── css
│ │ ├── jquery.uls.compact.css
│ │ ├── jquery.uls.lcd.css
│ │ ├── jquery.uls.grid.css
│ │ ├── jquery.uls.css
│ │ └── jquery.uls.mobile.css
│ └── js
│ │ ├── jquery.uls.regionfilter.js
│ │ ├── jquery.uls.languagefilter.js
│ │ ├── jquery.uls.lcd.js
│ │ ├── jquery.uls.core.js
│ │ ├── jquery.uls.data.utils.js
│ │ └── jquery.uls.data.js
├── themes
│ └── fedora
│ │ ├── img
│ │ └── sidebar-logo.png
│ │ └── css
│ │ └── site.css
└── site.js
├── .gitignore
├── questions
├── includes
│ └── fedora
│ │ ├── i18n.yml
│ │ ├── coding
│ │ ├── scala.yml
│ │ ├── haskell.yml
│ │ ├── c++.yml
│ │ ├── java.yml
│ │ ├── c.yml
│ │ ├── python.yml
│ │ └── web.yml
│ │ ├── server.yml
│ │ ├── packaging.yml
│ │ ├── advocacy.yml
│ │ ├── cloud.yml
│ │ ├── desktop.yml
│ │ ├── community.yml
│ │ ├── translation.yml
│ │ ├── qa.yml
│ │ ├── design.yml
│ │ ├── coding.yml
│ │ └── writing.yml
└── fedora.yml
├── docker-compose.yml
├── .travis.yml
├── tests
└── test_yaml.py
├── compile-translations.sh
├── setup.py
├── Dockerfile
├── asknot-ng.py
├── README.md
├── templates
└── index.html
└── asknot_lib.py
/container/container-entrypoint.sh:
--------------------------------------------------------------------------------
1 | exec httpd -DFOREGROUND -DNO_DETACH
2 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | mako
2 | PyYAML
3 |
4 | # nose is only required for testing
5 | nose2
6 |
--------------------------------------------------------------------------------
/.coafile:
--------------------------------------------------------------------------------
1 | [Default]
2 | bears = SpaceConsistencyBear
3 | use_spaces = true
4 | files = **/*.(html|css)
5 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/jquery.uls/img/clear.png
--------------------------------------------------------------------------------
/static/jquery.uls/img/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/jquery.uls/img/close.png
--------------------------------------------------------------------------------
/static/jquery.uls/img/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/jquery.uls/img/search.png
--------------------------------------------------------------------------------
/static/jquery.uls/img/world_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/jquery.uls/img/world_map.png
--------------------------------------------------------------------------------
/static/jquery.uls/img/icon-language.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/jquery.uls/img/icon-language.png
--------------------------------------------------------------------------------
/static/themes/fedora/img/sidebar-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fedora-infra/asknot-ng/develop/static/themes/fedora/img/sidebar-logo.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.html
2 | *.svg
3 | *.pyc
4 | *.egg-info
5 | build
6 | *.mo
7 | env
8 | venv
9 | /.venv
10 | .zanata-cache
11 | container/l10n.conf
12 |
--------------------------------------------------------------------------------
/questions/includes/fedora/i18n.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: i18n
4 | subtitle: the Fedora Internationalization subproject
5 | link: https://fedoraproject.org/wiki/I18N
6 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/scala.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Fedora Mobile
4 | subtitle: Interact with Fedora's community on the go!
5 | link: https://github.com/fedora-infra/mobile
6 |
--------------------------------------------------------------------------------
/questions/includes/fedora/server.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Server SIG
4 | subtitle: the special-interest-group for Fedora Server
5 | link: https://fedoraproject.org/wiki/SIGs/Server
6 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 |
3 | services:
4 | web:
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | image: asknot-ng
9 | ports:
10 | - "8080:80"
11 | network_mode: "host"
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "3.9"
4 | cache: pip
5 |
6 | # command to install dependencies
7 | install: pip install nose2 PyYAML
8 | # command to run tests
9 | script: nose2
10 |
11 | notifications:
12 | email: false
13 |
--------------------------------------------------------------------------------
/questions/includes/fedora/packaging.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Package Maintainer
4 | subtitle: steward of the packages in Fedora
5 | link: https://docs.fedoraproject.org/en-US/package-maintainers/Joining_the_Package_Maintainers/
6 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/haskell.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Haskell Special Interest Group
4 | subtitle: Work with the community to make Haskell development in Fedora be awesome!
5 | link: https://fedoraproject.org/wiki/Haskell_SIG
6 |
--------------------------------------------------------------------------------
/questions/includes/fedora/advocacy.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Ambassador
4 | subtitle: the representatives of Fedora
5 | image: https://badges.fedoraproject.org/pngs/fas-ambassador.png
6 | link: https://fedoraproject.org/wiki/Ambassadors#Who_are_we.3F
7 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/clear.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/questions/includes/fedora/cloud.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Cloud SIG
4 | subtitle: the special-interest-group for Fedora Cloud
5 | link: https://fedoraproject.org/wiki/Cloud_SIG
6 | - title: RDO
7 | subtitle: the OpenStack distro for Fedora
8 | link: https://www.rdoproject.org/documentation/onboarding/
9 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/c++.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: LibreOffice
4 | subtitle: a free and open source office suite
5 | link: https://www.libreoffice.org/about-us/source-code/
6 |
7 | - title: KDE
8 | subtitle: an integrated set of cross-platform applications
9 | link: https://community.kde.org/Get_Involved/development
10 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_yaml.py:
--------------------------------------------------------------------------------
1 | import os, fnmatch
2 | import yaml
3 |
4 | def validate_yaml_file(filename):
5 | print("Validating {0}".format(filename))
6 | try:
7 | load_yaml = yaml.load(open(filename, 'r'), Loader=yaml.BaseLoader)
8 | except (yaml.YAMLError) as err:
9 | raise ValueError("Invalid YAML file: {0}".format(filename))
10 |
11 |
12 | def test_yaml():
13 | # Check YAML files for errors
14 | for root, dirs, files in os.walk('questions'):
15 | for filename in fnmatch.filter(files, "*.yml"):
16 | validate_yaml_file(os.path.join(root, filename))
17 |
--------------------------------------------------------------------------------
/compile-translations.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 |
3 | ASKNOT_LOCALE_DIR=${ASKNOT_LOCALE_DIR:-l10n/fedora/locale}
4 | rm -f container/l10n.conf
5 |
6 | for locale in $(ls $ASKNOT_LOCALE_DIR/*.po); do
7 | echo $locale;
8 | locale=$(basename $locale)
9 | locale=${locale%.po};
10 | mkdir -p $ASKNOT_LOCALE_DIR/$locale/LC_MESSAGES/;
11 | msgfmt -o $ASKNOT_LOCALE_DIR/$locale/LC_MESSAGES/asknot-ng.mo $ASKNOT_LOCALE_DIR/$locale.po;
12 |
13 | printf "RewriteCond %%{HTTP:Accept-Language} ^${locale//_/$'-'} [NC]\n" >> container/l10n.conf
14 | printf "RewriteRule \"^/$\" \"/$locale/\" [L,R]\n\n" >> container/l10n.conf
15 | done
16 |
17 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/java.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Java Special Interest Group
4 | subtitle: Work with the community on Java packaging and development
5 | link: https://fedoraproject.org/wiki/SIGs/Java
6 |
7 | - title: JBoss
8 | subtitle: A suite of enterprise middleware
9 | link: https://tools.jboss.org/getinvolved/
10 |
11 | - title: fedmsg-java
12 | subtitle: Interact with fedmsg from the JVM
13 | link: https://github.com/fedora-infra/fedmsg-java
14 |
15 | - title: jenkins-fedmsg-emit
16 | subtitle: Send fedmsg messages related to Jenkins builds
17 | link: https://github.com/fedora-infra/jenkins-fedmsg-emit
18 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/c.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: OSTree
4 | subtitle: git for operating system binaries
5 | link: https://ostreedev.github.io/ostree/
6 |
7 | - title: systemd
8 | subtitle: widely renowned init system and suite of building blocks
9 | link: https://www.freedesktop.org/wiki/Software/systemd/
10 |
11 | - title: Cockpit
12 | subtitle: a server manager that makes it easy to administer via a web browser
13 | link: https://cockpit-project.org/
14 |
15 | - title: GNOME
16 | subtitle: an easy and elegant way to use your computer
17 | link: https://gitlab.gnome.org/GNOME
18 |
19 | - title: The Linux Kernel
20 | subtitle: that thing that connects application software to the hardware of a computer
21 | link: https://kernelnewbies.org/FirstKernelPatch
22 |
--------------------------------------------------------------------------------
/questions/includes/fedora/desktop.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Workstation Working Group
4 | subtitle: the group behind Fedora Workstation
5 | link: https://docs.fedoraproject.org/en-US/workstation-working-group/
6 |
7 | - title: Cinnamon SIG
8 | subtitle: for those excited about Cinnamon desktop environment spiciness in Fedora
9 | link: https://fedoraproject.org/wiki/Cinnamon_Spin
10 |
11 | - title: KDE SIG
12 | subtitle: to provide high-quality, usable KDE software packages
13 | link: https://fedoraproject.org/wiki/SIGs/KDE
14 |
15 | - title: LXDE SIG
16 | subtitle: to define a high-quality LXDE experience for Fedora users
17 | link: https://fedoraproject.org/wiki/LXDE_SIG
18 |
19 | - title: XFCE SIG
20 | subtitle: for those excited about integration of the Xfce desktop environment
21 | link: https://fedoraproject.org/wiki/SIGs/Xfce
22 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | description = 'Ask not what $ORG can do for you, but what you can do for $ORG'
4 |
5 | setup(
6 | name='asknot-ng',
7 | version='1.0',
8 | description=description,
9 | license='GPLv3+',
10 | author='Ralph Bean',
11 | author_email='rbean@redhat.com',
12 | url='https://github.com/fedora-infra/asknot-ng',
13 | install_requires=[
14 | 'mako',
15 | 'PyYAML',
16 | ],
17 | extras_require={
18 | 'tests': ['nose2'],
19 | },
20 | packages=[],
21 | py_modules=['asknot_lib'],
22 |
23 | # This declares our special-case extractor to 'babel', a python l18n tool.
24 | entry_points="""
25 | [babel.extractors]
26 | asknot = asknot_lib:extract
27 | """,
28 |
29 | # This further declares that babel should use our extractor on yaml files
30 | # in the questions/ directory.
31 | message_extractors={
32 | "questions": [
33 | ('**.yml', 'asknot', None),
34 | ]
35 | }
36 | )
37 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM fedora:34 as builder
2 |
3 | COPY . /code
4 | WORKDIR /code
5 |
6 | RUN dnf -y install gettext python3-setuptools python3-pyyaml python3-mako python3-babel python3-pygraphviz && dnf clean all && python3 setup.py install && ./build.sh
7 |
8 | FROM fedora:34
9 |
10 | COPY --from=builder /code/build /var/www/html/
11 | COPY --from=builder /code/container/l10n.conf /etc/httpd/conf/l10n.conf
12 | COPY container/favicon.xpm /var/www/html/static/image/favicon.xpm
13 | COPY container/whatcanidoforfedora-web.conf /etc/httpd/conf/httpd.conf
14 | RUN dnf -y install httpd && dnf clean all\
15 | && chown apache:0 /etc/httpd/conf/httpd.conf \
16 | && chmod g+r /etc/httpd/conf/httpd.conf \
17 | && chown apache:0 /etc/httpd/conf/l10n.conf \
18 | && chmod g+r /etc/httpd/conf/l10n.conf \
19 | && chown apache:0 /var/log/httpd \
20 | && chmod g+rwX /var/log/httpd \
21 | && chown apache:0 /var/run/httpd \
22 | && chmod g+rwX /var/run/httpd\
23 | && chown -R apache:0 /var/www/html \
24 | && chmod -R g+rwX /var/www/html
25 | EXPOSE 8080
26 | USER apache
27 | ADD container/container-entrypoint.sh /srv
28 | ENTRYPOINT ["bash", "/srv/container-entrypoint.sh"]
29 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/python.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Anaconda
4 | subtitle: the OS installer and all its related projects
5 | link: https://fedoraproject.org/wiki/Anaconda/Contribute
6 |
7 | - title: ABRT
8 | subtitle: the Automatic Bug Reporting Tool
9 | link: https://github.com/abrt/abrt/wiki/overview
10 |
11 | - title: DNF
12 | subtitle: Dandified Yum (DNF) is a major rewrite of yum
13 | link: https://github.com/rpm-software-management/dnf
14 |
15 | - title: Firewalld
16 | subtitle: a dynamically managed firewall with support for network zones
17 | link: https://www.firewalld.org/contribute/
18 |
19 | - title: PortingDB
20 | subtitle: a dynamic database of Python 2 packages needing to be updated to Python 3
21 | link: https://fedora.portingdb.xyz/
22 |
23 | - title: Cockpit
24 | subtitle: a web interface for managing and administrating Linux web servers
25 | link: https://cockpit-project.org/
26 |
27 | - title: Web Services
28 | subtitle: Fedora Infrastructure team for the win
29 | link: https://fedoraproject.org/wiki/Infrastructure/GettingStarted
30 |
--------------------------------------------------------------------------------
/questions/includes/fedora/community.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: General
4 | subtitle: on how to join the Community Operations team?
5 | image: https://badges.fedoraproject.org/pngs/fpl-blessing.png
6 | link: https://docs.fedoraproject.org/en-US/commops/contribute/commops-landing/
7 |
8 | - title: Specific
9 | subtitle: on different kinds of community tasks
10 | image: https://badges.fedoraproject.org/pngs/the_panda_is_in.png
11 | segue1: Excellent!
12 | segue2: How does this sound?
13 |
14 | children:
15 | - title: Ambassador
16 | subtitle: the representatives of Fedora
17 | link: https://fedoraproject.org/wiki/Ambassadors#Who_are_we.3F
18 | image: https://badges.fedoraproject.org/pngs/fas-ambassador.png
19 | - title: Community Blog
20 | subtitle: the central hub of all Fedora news, across the subprojects
21 | link: https://communityblog.fedoraproject.org/writing-community-blog-article/
22 | - title: 5 Things in Fedora This Week
23 | subtitle: finding information for a weekly article about the happenings in Fedora
24 | link: https://docs.fedoraproject.org/en-US/commops/contribute/commops-landing/#toolbox
25 |
--------------------------------------------------------------------------------
/questions/includes/fedora/translation.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: General
4 | subtitle: about how to join the L10N team?
5 | link: https://fedoraproject.org/wiki/L10N#Joining_the_Fedora_Localization_Project
6 |
7 | - title: Specific
8 | subtitle: about L10N tasks
9 | segue1: Let's get down to business.
10 | segue2: Perhaps you'd be interested in translating...
11 |
12 | children:
13 | - title: User Interfaces
14 | subtitle: there are some essential projects that need translating
15 | link: https://fedoraproject.org/wiki/L10N_GUI
16 | - title: Wiki Pages
17 | subtitle: usually from English to another language
18 | link: https://fedoraproject.org/wiki/Fedora_Project_Wiki:Translating
19 | - title: Documentation
20 | subtitle: all the guides and release notes
21 | link: https://docs.fedoraproject.org/en-US/fedora-docs/contributing-docs/
22 | - title: GNOME
23 | subtitle: which has its own translation resources
24 | link: https://wiki.gnome.org/TranslationProject
25 | - title: KDE
26 | subtitle: also with its own translation process
27 | link: https://l10n.kde.org/docs/translation-howto/
28 |
--------------------------------------------------------------------------------
/container/favicon.xpm:
--------------------------------------------------------------------------------
1 | /* XPM */
2 | static char * linux_xpm[] = {
3 | "20 20 55 1",
4 | " c None",
5 | ". c #51A1DB",
6 | "+ c #51A2DA",
7 | "@ c #52A2DA",
8 | "# c #51A2DB",
9 | "$ c #79B1DE",
10 | "% c #68AADC",
11 | "& c #71AFDE",
12 | "* c #CEE3F3",
13 | "= c #F2F6F8",
14 | "- c #F0F5F8",
15 | "; c #E2EEF7",
16 | "> c #6FAEDE",
17 | ", c #51A3DA",
18 | "' c #D4E7F4",
19 | ") c #C7DFF0",
20 | "! c #59A6DC",
21 | "~ c #62ABDE",
22 | "{ c #CBE1F1",
23 | "] c #DFEDF6",
24 | "^ c #7AB1DE",
25 | "/ c #F7F8F9",
26 | "( c #7EB4E0",
27 | "_ c #97C0E4",
28 | ": c #7AB2DE",
29 | "< c #F9FAFA",
30 | "[ c #92BDE3",
31 | "} c #B7D6ED",
32 | "| c #6AABDD",
33 | "1 c #A6CEEA",
34 | "2 c #F2F7FA",
35 | "3 c #FFFFFF",
36 | "4 c #FAFAFA",
37 | "5 c #F9F9FA",
38 | "6 c #8CC1E5",
39 | "7 c #A7CFEA",
40 | "8 c #E6F0F8",
41 | "9 c #6FB1E0",
42 | "0 c #52A3DA",
43 | "a c #EDF4F9",
44 | "b c #6DB0DF",
45 | "c c #F3F6FA",
46 | "d c #67ADDE",
47 | "e c #71B0DF",
48 | "f c #BBD9EE",
49 | "g c #E3EFF6",
50 | "h c #63ABDD",
51 | "i c #80B5E0",
52 | "j c #D7E8F4",
53 | "k c #E4F0F8",
54 | "l c #5AA7DC",
55 | "m c #B2D5EC",
56 | "n c #E7F0F7",
57 | "o c #EDF3F7",
58 | "p c #51A2D9",
59 | " ",
60 | " .+@@+# ",
61 | " ++++++++++ ",
62 | " ++++++++++++ ",
63 | " +++++++$$$%+++ ",
64 | " +++++++&*=-;>++, ",
65 | " ++++++%')!~{]%++ ",
66 | " +++++++^/(++_=%++@ ",
67 | " #++++++:<$++[}++++ ",
68 | " ++++%$$:<$++++++++ ",
69 | " +++|12<:3456++++++ ",
70 | " +++7890:3$++++++++ ",
71 | " ++$ab++:3$++++++++ ",
72 | " ++$cd++e-$+++++++ ",
73 | " ++$fghijk++++++++ ",
74 | " +++lmno*e+++++++ ",
75 | " ++++%$$$+++++++ ",
76 | " p++++++++++++# ",
77 | " ++++++++++, ",
78 | " "};
79 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/icon-language.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/jquery.uls/css/jquery.uls.compact.css:
--------------------------------------------------------------------------------
1 | .uls-compact .uls-icon-close,
2 | .uls-compact .uls-title-region,
3 | .uls-compact .uls-map-block,
4 | .uls-compact #uls-settings-block {
5 | display: none !important;
6 | }
7 |
8 | .uls-compact.uls-menu {
9 | border-radius: 0;
10 | }
11 |
12 | .uls-compact .uls-search {
13 | background: white;
14 | border-top: none;
15 | padding: 0.8em 0;
16 | border-bottom-width: 1px;
17 | border-bottom-style: solid;
18 | border-bottom-color: #DDD;
19 | }
20 |
21 | .uls-compact .uls-filterinput,
22 | .uls-compact .uls-filterinput:focus {
23 | background-color: transparent;
24 | border: none;
25 | box-shadow: none;
26 | outline: none;
27 | font-size: 18px;
28 | left: 0;
29 | }
30 |
31 | .uls-compact .uls-language-list {
32 | background: #FCFCFC;
33 | height: 20em;
34 | }
35 |
36 | .uls-compact .uls-search-label {
37 | background-size: 25px;
38 | height: 26px;
39 | width: 26px;
40 | float: right;
41 | opacity: 0.8;
42 | }
43 |
44 | .uls-compact .uls-languagefilter-clear {
45 | margin-left: 0;
46 | }
47 |
48 | .uls-compact .uls-title-region a {
49 | color: #777;
50 | display: inline-block;
51 | margin: 15px 0 5px 19px;
52 | cursor: pointer;
53 | padding: 6px;
54 | text-decoration: none;
55 | font-size: 14px;
56 | border: 1px solid transparent;
57 | }
58 |
59 | .uls-compact .uls-title-region a:hover {
60 | color: #252525;
61 | background: #F0F0F0;
62 | border: 1px solid #DDD;
63 | border-radius: 3px;
64 | }
65 |
66 | .uls-compact .uls-title-region a:before {
67 | display: inline-block;
68 | width: 0;
69 | height: 0;
70 | border-right: 4px solid #777;
71 | border-top: 4px solid transparent;
72 | border-bottom: 4px solid transparent;
73 | content: "";
74 | margin: 0 6px 0 0;
75 | }
76 |
--------------------------------------------------------------------------------
/questions/includes/fedora/qa.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: General
4 | subtitle: about how to join the QA team?
5 | link: https://fedoraproject.org/wiki/QA/Join
6 |
7 | - title: Specific
8 | subtitle: about different QA and testing tasks
9 | segue1: Certainly.
10 | segue2: We need people to...
11 |
12 | children:
13 | - title: Validate Releases
14 | subtitle: when there's an upcoming release, that is
15 | link: https://fedoraproject.org/wiki/QA/Join#release-validation
16 | - title: Test Updates
17 | subtitle: before they hit the stable repo
18 | link: https://fedoraproject.org/wiki/QA:Updates_Testing#What_to_test.2C_testing.2C_and_reporting_results
19 | - title: Create Test Cases
20 | subtitle: otherwise we won't know what to test
21 | link: https://fedoraproject.org/wiki/QA:SOP_test_case_creation
22 |
23 | - title: Develop Tools
24 | subtitle: for continuous awesomeness
25 | segue1: I'm of the same mind.
26 | segue2: We need people to hack on
27 |
28 | children:
29 | - title: BlockerBugs
30 | subtitle: used to propose and track release blocking bugs
31 | link: https://qa.fedoraproject.org/blockerbugs/
32 | - title: Bodhi
33 | subtitle: the Fedora Updates System
34 | link: https://github.com/fedora-infra/bodhi
35 | - title: fedora-easy-karma
36 | subtitle: a handsome tool to ease testing updates
37 | link: https://fedoraproject.org/wiki/Fedora_Easy_Karma
38 |
39 | - title: Take Over
40 | subtitle: some basically abandoned tasks
41 | segue1: That's huge of you.
42 | segue2: we need someone to head up...
43 |
44 | children:
45 | - title: Bug Triage
46 | subtitle: you'll need a heart of gold
47 | link: https://fedoraproject.org/wiki/QA/Join#triage
48 |
--------------------------------------------------------------------------------
/questions/includes/fedora/design.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Design Team
4 | subtitle: creatives serving as a design firm for the Fedora community
5 | image: https://badges.fedoraproject.org/pngs/artist-01-apprentice.png
6 | segue1: Ok.
7 | segue2: Would you like something more
8 |
9 | children:
10 | - title: General
11 | subtitle: on how to join the design team?
12 | image: https://badges.fedoraproject.org/pngs/artist-02-badger-of-urbino.png
13 | link: https://fedoraproject.org/wiki/Join_the_Design_Team
14 |
15 | - title: Specific
16 | subtitle: on different kinds of design tasks
17 | image: https://badges.fedoraproject.org/pngs/artist-03-birth-of-badger.png
18 | segue1: Excellent!
19 | segue2: How does this sound?
20 |
21 | children:
22 | - title: Artwork Requests
23 | subtitle: there are people in need of good taste -- you can help
24 | link: https://gitlab.com/fedora/design/team/requests/-/issues
25 | image: https://badges.fedoraproject.org/pngs/artist-04-putti.png
26 | - title: Hackergotchis
27 | subtitle: making cute cut-outs of people's faces
28 | image: https://badges.fedoraproject.org/pngs/artist-05-vitruvian-badger.png
29 | link: https://fedoraproject.org/wiki/Artwork/HackergotchiService
30 | - title: Fedora Badges
31 | subtitle: make awesome badge art that fuels badges.fp.o
32 | image: https://badges.fedoraproject.org/pngs/artist-06-creation-of-badger.png
33 | link: https://pagure.io/fedora-badges
34 |
35 | - title: Websites Team
36 | subtitle: web developers that build getfedora.org and other awesome sites
37 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
38 | children: coding/web.yml
39 |
--------------------------------------------------------------------------------
/static/jquery.uls/css/jquery.uls.lcd.css:
--------------------------------------------------------------------------------
1 | .uls-lcd-region-section ul li:hover {
2 | background-color: #eaeff7;
3 | }
4 |
5 | .uls-lcd-region-section {
6 | margin-top: 10px;
7 | }
8 |
9 | /* Language list */
10 | .uls-language-list {
11 | height: 17em;
12 | overflow: auto;
13 | width: auto;
14 | }
15 |
16 | .uls-language-block ul {
17 | margin: 0 0 1.5em;
18 | }
19 |
20 | .uls-language-list ul li {
21 | cursor: pointer;
22 | font-weight: normal;
23 | overflow: hidden;
24 | white-space: nowrap;
25 |
26 | /*
27 | * Some languages have long names for various reasons and we still want
28 | * them to appear on one line.
29 | * To make it work correctly, the directionality must be set correctly
30 | * on the item level.
31 | */
32 | text-overflow: ellipsis;
33 |
34 | /*
35 | * The directionality (ltr/rtl) for each list item is set dynamically
36 | * as HTML attributes in JavaScript. Setting directionality also applies
37 | * alignment, but a list with mixed alignment is hard to read.
38 | * All items are therefore explicitly aligned to the left, including names
39 | * of right-to-left languages in left-to-right environment and vice versa.
40 | * As long as the directionality of the item is set correctly, the text
41 | * is readable.
42 | */
43 | text-align: left;
44 |
45 | /*
46 | * We don't want any visible bullets in this list.
47 | */
48 | list-style-image: none;
49 | list-style-type: none;
50 | }
51 |
52 | .uls-language-list strong {
53 | text-decoration: underline;
54 | }
55 |
56 | .uls-language-list a {
57 | font-weight: normal;
58 | text-decoration: none;
59 | color: #3366bb;
60 | font-size: 14px;
61 | line-height: 1.6em;
62 | }
63 |
64 | .uls-language-block {
65 | width: 100%;
66 | }
67 |
68 | .uls-no-results-view {
69 | color: #555;
70 | height: 100%;
71 | }
72 |
73 | .uls-no-found-more {
74 | font-size: 0.9em;
75 | background: #F8F8F8;
76 | width: 100%;
77 | margin-top: 1.6em;
78 | line-height: 1.6em;
79 | position: absolute;
80 | bottom: 0;
81 | left: 0;
82 | }
83 |
84 | .uls-no-found-more a {
85 | cursor: pointer;
86 | }
87 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Python
4 | subtitle: a dynamic language for rapid development
5 | segue1: So, you enjoy traceback-driven development? What could go wrong?
6 | segue2: Are you interested in hacking on...
7 | children: coding/python.yml
8 |
9 | - title: C
10 | subtitle: close to the metal
11 | segue1: So, you think OOP is for hipsters? Let me tell you, back in my day...
12 | segue2: How about working on...
13 | children: coding/c.yml
14 |
15 | - title: Haskell
16 | subtitle: a nondynamic language for rapid development
17 | segue1: So, programming without side-effects is what you're all about? Sounds useful!
18 | segue2: How about...
19 | children: coding/haskell.yml
20 |
21 | - title: Java
22 | subtitle: a nondynamic language for nonrapid development
23 | segue1: So you're a believer in AbstractMethodFactoryBeans? Straightforward enough...
24 | segue2: How about...
25 | children: coding/java.yml
26 |
27 | - title: Scala
28 | subtitle: a nondynamic language for semirapid development
29 | segue1: So, just OOP or functional languages wouldn't do it? You had to have both, huh?
30 | segue2: How about working on...
31 | children: coding/scala.yml
32 |
33 | - title: JavaScript
34 | subtitle: a dynamic web-oriented language for backend and frontend
35 | segue1: So, you think having native integers is over-rated? What could go wrong?
36 | segue2: There's plenty to do. How about joining the..
37 | children:
38 | - title: Websites Team
39 | subtitle: web developers that build getfedora.org and other awesome sites
40 | segue1: Great!
41 | segue2: Would you like something more
42 | children: coding/web.yml
43 |
44 | - title: Ruby
45 | subtitle: hashrockets and bare words
46 | link: https://fedoraproject.org/wiki/Ruby_SIG
47 |
48 | - title: C++
49 | subtitle: imperative and object-oriented with the power of low-level memory manipulation
50 | segue1: So, you're not happy if your error messages are comprehensible? We have a place for you.
51 | segue2: Try digging into...
52 | children: coding/c++.yml
53 |
--------------------------------------------------------------------------------
/questions/includes/fedora/coding/web.yml:
--------------------------------------------------------------------------------
1 | tree:
2 |
3 | children:
4 | - title: General
5 | subtitle: on how to join the websites team?
6 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
7 | link: https://fedoraproject.org/wiki/Websites/Join
8 |
9 | - title: Specific
10 | subtitle: on different kinds of website tasks
11 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
12 | segue1: That's my style too.
13 | segue2: How about working on the...
14 |
15 | children:
16 | - title: Release Site
17 | subtitle: "getfedora.org is awesome"
18 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
19 | link: https://fedoraproject.org/wiki/Websites
20 | - title: Magazine
21 | subtitle: "did you even know we had a magazine ?"
22 | image: https://badges.fedoraproject.org/pngs/extra!-extra!.png
23 | link: https://fedoraproject.org/wiki/Magazine
24 | - title: Wiki Theme
25 | subtitle: it's a little crusty
26 | image: https://badges.fedoraproject.org/pngs/junior-editor.png
27 | link: "https://fedoraproject.org/wiki/Websites#Wiki_Theme_Update"
28 | - title: General Theme
29 | subtitle: there's a list of sites that need standardizing
30 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
31 | link: "https://fedoraproject.org/wiki/Websites#All_Fedora_Websites_Theme_Update"
32 | - title: Translations
33 | subtitle: we're an international community after all
34 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
35 | link: https://fedoraproject.org/wiki/Websites#Translations
36 | - title: User Gallery
37 | subtitle: gallery for mini-interview-style user profiles and stories
38 | image: https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png
39 | link: https://fedoraproject.org/wiki/Websites#User_gallery
40 | - title: AskNot Site
41 | subtitle: this thing -- the page you're looking at right now!
42 | image: https://badges.fedoraproject.org/pngs/rock-the-web.png
43 | link: https://github.com/fedora-infra/asknot-ng
44 |
--------------------------------------------------------------------------------
/container/whatcanidoforfedora-web.conf:
--------------------------------------------------------------------------------
1 |
2 | Alias /favicon.ico /var/www/html/static/image/favicon.xpm
3 |
4 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/x-javascript
5 |
6 | FileETag MTime Size
7 |
8 | ExpiresActive On
9 | ExpiresDefault "access plus 30 minutes"
10 |
11 | RewriteEngine On
12 | Include /etc/httpd/conf/l10n.conf
13 | RewriteRule "^/$" "/en/" [R]
14 | RewriteRule "^/index.html$" "/en/" [R]
15 |
16 | ServerRoot "/etc/httpd"
17 |
18 | Listen 8080
19 |
20 | Include conf.modules.d/*.conf
21 |
22 | User apache
23 | Group apache
24 |
25 | ServerAdmin root@localhost
26 |
27 |
28 | AllowOverride none
29 | Require all denied
30 |
31 |
32 | DocumentRoot "/var/www/html"
33 |
34 |
35 | AllowOverride None
36 | # Allow open access:
37 | Require all granted
38 |
39 |
40 |
41 | Options Indexes FollowSymLinks
42 | AllowOverride None
43 | Require all granted
44 |
45 |
46 |
47 | DirectoryIndex index.html
48 |
49 |
50 | Require all denied
51 |
52 |
53 | ErrorLog "logs/error_log"
54 |
55 | LogLevel warn
56 |
57 |
58 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
59 | LogFormat "%h %l %u %t \"%r\" %>s %b" common
60 |
61 |
62 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
63 |
64 |
65 | CustomLog "logs/access_log" combined
66 |
67 |
68 |
69 | ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
70 |
71 |
72 |
73 | AllowOverride None
74 | Options None
75 | Require all granted
76 |
77 |
78 |
79 | TypesConfig /etc/mime.types
80 | AddType application/x-compress .Z
81 | AddType application/x-gzip .gz .tgz
82 | AddType text/html .shtml
83 | AddOutputFilter INCLUDES .shtml
84 |
85 |
86 | AddDefaultCharset UTF-8
87 |
88 |
89 | MIMEMagicFile conf/magic
90 |
91 |
92 | #EnableMMAP off
93 | EnableSendfile on
94 |
95 | # Load config files in the "/etc/httpd/conf.d" directory, if any.
96 | IncludeOptional conf.d/*.conf
97 |
--------------------------------------------------------------------------------
/questions/includes/fedora/writing.yml:
--------------------------------------------------------------------------------
1 | tree:
2 | children:
3 | - title: Documentation
4 | subtitle: so people know how to use this crazy stuff
5 | segue1: Without you no-one would be able to "RTFM", as they say.
6 | segue2: Would you be interested in something...
7 |
8 | children:
9 | - title: General
10 | subtitle: about how to join the docs team?
11 | link: https://fedoraproject.org/wiki/Join_the_Docs_Project
12 |
13 | - title: Specific
14 | subtitle: about documentation related tasks
15 | segue1: Now we're talking!
16 | segue2: Let's see. How about working on...
17 |
18 | children:
19 | - title: Wiki Gardening
20 | subtitle: it tends to get a little overgrown
21 | link: https://fedoraproject.org/wiki/Wiki_gardening_tasks
22 | - title: A Guide
23 | subtitle: a more technical type of documentation
24 | link: https://fedoraproject.org/wiki/Category:Docs_Project_tasks#Guides
25 | - title: Real Issues
26 | subtitle: that people have reported
27 | link: https://bugzilla.redhat.com/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&classification=Fedora&list_id=3214328&product=Fedora%20Documentation&query_format=advanced
28 |
29 | - title: Blogging
30 | subtitle: 21st century journalism, my friend
31 | segue1: Only the news that's fit to print.
32 | segue2: How about something...
33 | children:
34 | - title: More Formal
35 | subtitle: something "official"
36 | segue1: Yes! The spotlight!
37 | segue2: You should get involved in writing for...
38 | children:
39 | - title: Fedora Magazine
40 | subtitle: all Fedora news, all the Fedora time
41 | link: https://fedoramagazine.org/writing-an-article-for-the-fedora-magazine/
42 | - title: Less Formal
43 | subtitle: something more personal
44 | segue1: We have just the thing for you.
45 | segue2: Get your own blog added to the...
46 | children:
47 | - title: Community Blog
48 | subtitle: the central hub of all Fedora news, across the subprojects
49 | link: https://communityblog.fedoraproject.org/writing-community-blog-article/
50 | - title: Fedora Planet
51 | subtitle: an aggregator of Fedora bloggers
52 | link: https://fedoraproject.org/wiki/Planet
53 |
--------------------------------------------------------------------------------
/static/site.js:
--------------------------------------------------------------------------------
1 | // Setup our own endsWith definition since midori doesn't know about it.
2 | String.prototype.endsWith = function(suffix) {
3 | return this.indexOf(suffix, this.length - suffix.length) !== -1;
4 | };
5 |
6 | function hashSelect(first) {
7 | console.log("Changing to new hash...");
8 | var found = false;
9 | $.each(all_ids, function(i, idx) {
10 | var curr = $('#' + idx);
11 | if (location.href.endsWith(SEP + idx)) {
12 | curr.removeClass('hidden');
13 | found = true;
14 | }
15 | else {
16 | var isHidden = curr.hasClass('hidden');
17 | if (! isHidden) {
18 | curr.addClass('hidden');
19 | }
20 | }
21 | });
22 | if (! found) {
23 | $("#" + first).removeClass('hidden');
24 | var original = location.href.replace(/\/$/, "");
25 | history.pushState({}, '', original + SEP + first);
26 | }
27 | }
28 |
29 | $(document).ready(function() {
30 | // First thing.. hide the warning about javascript being required.
31 | $("#js-warning").addClass('hidden');
32 |
33 | var first = question_tree.children[0].id;
34 | hashSelect(first);
35 |
36 | // Wire up the "yes" links
37 | $("a.yes").click(function(event) {
38 | $(this).parent().parent().addClass('hidden');
39 | var next = $(this).attr('data-next');
40 | $('#' + next).removeClass('hidden');
41 | var original = location.href.replace(/\/$/, "");
42 | history.pushState({}, '', original + SEP + next);
43 | });
44 |
45 | // Wire up the "nope" links
46 | $("a.nope").click(function(event) {
47 | $(this).parent().parent().addClass('hidden');
48 | var next = $(this).attr('data-next');
49 | $('#' + next).removeClass('hidden');
50 | var tokens = location.href.replace(/\/$/, "").split(SEP).slice(0, -1);
51 | tokens.push(next);
52 | history.replaceState({}, '', tokens.join(SEP));
53 | });
54 |
55 | // Wire up the "back" links
56 | $("a.back").click(function(event) {
57 | $(this).parent().parent().addClass('hidden');
58 | var tokens = location.href.replace(/\/$/, "").split(SEP).slice(0, -1);
59 | var next = tokens.slice(-1).pop();
60 | history.go(-1);
61 | $('#' + next).removeClass('hidden');
62 | });
63 | $(window).on('hashchange', function() {
64 | // Detect hash changes for "back" functions
65 | hashSelect(first);
66 | });
67 |
68 | });
69 | function reloadHome() {
70 | window.location = "#";
71 | window.location.reload();
72 | }
73 |
--------------------------------------------------------------------------------
/asknot-ng.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """ asknot-ng.py [OPTIONS] template.html questions.yml path/to/locale
3 |
4 | Ask not what $ORG can do for you... but what can you do for $ORG.
5 | """
6 |
7 | from __future__ import print_function
8 |
9 | import argparse
10 | import copy
11 | import gettext
12 | import json
13 | import os
14 | import shutil
15 | import sys
16 | import traceback
17 |
18 | from asknot_lib import (
19 | defaults,
20 | load_template,
21 | load_yaml,
22 | prepare_tree,
23 | gather_ids,
24 | produce_graph,
25 | )
26 |
27 |
28 | def work(question_filename, template, lang, languages, graph, build, _, **kw):
29 | """ Main work function. Called once per 'lang' from ``main``.
30 |
31 | The function does all the things needed to build a copy of the site.
32 | Shortly, it:
33 | - loads the template used to render the html
34 | - loads the tree of questions from a questions file
35 | - recursively pulls in any other included questions files
36 | - prepares the tree by adding unique ids to each node
37 | - renders the template using the in-memory copy of the questions
38 | - writes out a copy of the rendered html to disk
39 | """
40 |
41 | template = load_template(template)
42 |
43 | data = load_yaml(question_filename)
44 |
45 | data['tree'] = prepare_tree(data, data['tree'], _=_)
46 | data['all_ids'] = list(gather_ids(data['tree']))
47 | data['all_ids_as_json'] = json.dumps(data['all_ids'], indent=4)
48 | data['tree_as_json'] = json.dumps(data['tree'], indent=4)
49 |
50 | kwargs = copy.copy(defaults)
51 | kwargs.update(data)
52 | kwargs.update(kw)
53 | kwargs['lang'] = lang
54 | kwargs['languages'] = languages
55 |
56 | if graph:
57 | dot = produce_graph(kwargs['tree'])
58 | dot.layout()#prog='dot')
59 | filename = '%s.svg' % kwargs.get('theme', 'asknot')
60 | dot.draw(filename)
61 | print("Wrote", filename)
62 |
63 | html = template.render(**kwargs)
64 |
65 | outdir = os.path.join(build, lang)
66 |
67 | if not os.path.exists(outdir):
68 | os.makedirs(outdir)
69 |
70 | outfile = os.path.join(outdir, 'index.html')
71 | with open(outfile, 'wb') as f:
72 | f.write(html)
73 | print("Wrote", outfile)
74 |
75 |
76 | def main(localedir, languages, strict, build, static, **kw):
77 | """ Main entry point for for the command line tool.
78 |
79 | This function loops over all translated copies of the site that it can find
80 | and renders a copy of the site for each language by calling ``work``.
81 | """
82 | if languages is None:
83 | languages = [
84 | d for d in os.listdir(localedir)
85 | if os.path.isdir(os.path.join(localedir, d))]
86 |
87 | # Default to english..
88 | if 'en' not in languages and not strict:
89 | languages = languages + ['en']
90 | else:
91 | languages = languages.split(',')
92 |
93 | if not languages:
94 | print("No languages found.")
95 |
96 | fallback = not strict
97 | for lang in languages:
98 | try:
99 | translation = gettext.translation(
100 | 'asknot-ng', localedir, languages=[lang], fallback=fallback)
101 | except IOError:
102 | traceback.print_exc()
103 | raise IOError("No translation found for %r" % lang)
104 | except ValueError:
105 | print("Got the following error for language %r" % lang)
106 | traceback.print_exc()
107 | continue
108 | translation.install()
109 |
110 |
111 | if sys.version_info[0] == 3:
112 | _ = translation.gettext
113 | else:
114 | _ = translation.ugettext
115 |
116 | work(_=_, lang=lang, languages=languages, build=build, **kw)
117 |
118 | staticdir = os.path.abspath(static)
119 | global_staticdir = os.path.join(build, "static")
120 | shutil.copytree(staticdir, global_staticdir, symlinks=True, dirs_exist_ok=True)
121 | print("Copied %s to %s" % (staticdir, global_staticdir))
122 |
123 |
124 | def process_args():
125 | parser = argparse.ArgumentParser(__doc__)
126 | parser.add_argument("template", help="Path to a mako template "
127 | "for the site.")
128 | parser.add_argument("question_filename", help="Path to a .yaml file "
129 | "containing the config and question tree.")
130 | parser.add_argument("localedir", help="Location of the locale directory.")
131 | parser.add_argument("-t", "--theme", default="default",
132 | help="Theme name to use.")
133 | parser.add_argument("-s", "--static", default="static",
134 | help="Directory of static files (js, css..).")
135 | parser.add_argument("-b", "--build", default="build",
136 | help="Directory to write output.")
137 | parser.add_argument("-l", "--languages", default=None,
138 | help="List of languages to use. Defaults to all.")
139 | parser.add_argument("-S", "--strict", default=False, action="store_true",
140 | help="Fail if no translation is found.")
141 | parser.add_argument("-g", "--graph", default=False, action="store_true",
142 | help="Also generate a graph of the question tree.")
143 | return parser.parse_args()
144 |
145 |
146 | if __name__ == '__main__':
147 | args = process_args()
148 | args = vars(args)
149 | main(**args)
150 |
--------------------------------------------------------------------------------
/questions/fedora.yml:
--------------------------------------------------------------------------------
1 | title: What can I do for Fedora?
2 | description: What can I do for Fedora?
3 | favicon: https://getfedora.org/static/images/favicon.ico
4 | google-site-verification: a-S_XZt6rQej92LXTbscezXa1RLTN1KoaLoPUyvwAGM
5 | negatives:
6 | - "No"
7 | - Nope, nope, nope
8 | - Nope
9 | - No, thanks
10 | - Not on your life
11 | - Doesn't sound like me
12 | - Absolutely not
13 | - Next, please
14 | affirmatives:
15 | - "Yes"
16 | - Sounds awesome
17 | - Tell me more
18 | - That's me!
19 | - Totally
20 | - Sure
21 | backlinks:
22 | - I was wrong, take me back
23 | - I think I made a mistake
24 | - Get me outta here!
25 |
26 | navlinks:
27 | - name: Home
28 | link: "javascript:reloadHome();"
29 | - name: Get Fedora
30 | link: https://getfedora.org
31 | - name: CoC
32 | link: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
33 | - name: Chat
34 | link: https://docs.fedoraproject.org/en-US/fedora-join/#communication
35 |
36 | tree:
37 | segue1: Want to help Fedora? Tell me...
38 | segue2: what's your area of interest?
39 | children:
40 | - title: Design!
41 | subtitle: pixel ninjas
42 | image: https://badges.fedoraproject.org/pngs/design-team.png
43 | segue1: So you enjoy working on the way users interact with websites and programs?
44 | segue2: How about the...
45 | children: includes/fedora/design.yml
46 |
47 | - title: Coding
48 | subtitle: hacking the gibson
49 | image: https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png
50 | segue1: "Zeroes and ones #allday? Me too."
51 | segue2: What's your favorite language?
52 | children: includes/fedora/coding.yml
53 |
54 | - title: Community Ops
55 | subtitle: connecting the dots
56 | image: https://badges.fedoraproject.org/pngs/the-write-stuff.png
57 | segue1: Have a knack for community-building?
58 | segue2: Would you like something more
59 | children: includes/fedora/community.yml
60 |
61 | - title: Writing
62 | subtitle: wordsmithery
63 | image: https://badges.fedoraproject.org/pngs/the-write-stuff.png
64 | segue1: So, you have a way with words?
65 | segue2: Would you be more interested in...
66 | children: includes/fedora/writing.yml
67 |
68 | - title: Translation
69 | subtitle: we're an international effort, after all
70 | image: https://badges.fedoraproject.org/pngs/irc-support-sig_member.png
71 | segue1: So you know more than one language? We need you!
72 | segue2: Would you be more interested in...
73 | children: includes/fedora/translation.yml
74 |
75 | - title: Advocacy
76 | subtitle: spreading the good word
77 | image: https://badges.fedoraproject.org/pngs/fedora-ambassador-mentor.png
78 | segue1: So you're a people person?
79 | segue2: How about becoming a Fedora...
80 | children: includes/fedora/advocacy.yml
81 |
82 | - title: Packaging
83 | subtitle: getting new software into Fedora
84 | image: https://badges.fedoraproject.org/pngs/copr-build.png
85 | segue1: So you want to help build the OS? Excellent.
86 | segue2: Then you'll need to become a Fedora...
87 | children: includes/fedora/packaging.yml
88 |
89 | - title: QA and Testing
90 | subtitle: as they say, "if it's not tested, it's broken"
91 | image: https://badges.fedoraproject.org/pngs/kernel-tester.png
92 | segue1: So you like to push all the buttons and break all the things?
93 | segue2: Are you more interested in something...
94 | children: includes/fedora/qa.yml
95 |
96 | - title: Modularity
97 | subtitle: rethinking how we compose the distro
98 | # image: https://docs.pagure.org/modularity/_static/logo.png
99 | link: https://docs.fedoraproject.org/en-US/modularity/community/
100 |
101 | - title: The Desktop
102 | subtitle: for those who are passionate about user and developer experience
103 | # image: https://getfedora.org/static/images/logo-color-workstation.png
104 | segue1: So you're into making the OS polished and easy to use?
105 | segue2: You probably want to join the Fedora...
106 | children: includes/fedora/desktop.yml
107 |
108 | - title: The Server
109 | subtitle: the best and latest for the datacenter
110 | # image: https://getfedora.org/static/images/logo-color-server.png
111 | segue1: So you're into making the OS powerful and flexible?
112 | segue2: You probably want to join the Fedora...
113 | children: includes/fedora/server.yml
114 |
115 | - title: The Cloud
116 | subtitle: it's where the future lives
117 | # image: https://getfedora.org/static/images/logo-color-cloud.png
118 | segue1: High-minded?
119 | segue2: You probably want to join the Fedora...
120 | children: includes/fedora/cloud.yml
121 |
122 | - title: Internationalization
123 | subtitle: making Fedora work better for all languages
124 | image: https://badges.fedoraproject.org/pngs/irc-support-sig_member.png
125 | segue1: Have a regional or world perspective?
126 | segue2: You probably want to join the Fedora...
127 | children: includes/fedora/i18n.yml
128 |
129 | - title: Instruction
130 | image: https://badges.fedoraproject.org/pngs/sensei.png
131 | subtitle: spread your knowledge to others in the community
132 | link: https://fedoraproject.org/wiki/Classroom
133 |
--------------------------------------------------------------------------------
/static/jquery.uls/css/jquery.uls.grid.css:
--------------------------------------------------------------------------------
1 | /* Generated using Foundation http://foundation.zurb.com/docs/grid.php */
2 | /* Global Reset & Standards ---------------------- */
3 | .grid * {
4 | -webkit-box-sizing: border-box;
5 | -moz-box-sizing: border-box;
6 | box-sizing: border-box;
7 | }
8 |
9 | /* Misc ---------------------- */
10 | .grid .left {
11 | float: left;
12 | }
13 |
14 | .grid .right {
15 | float: right;
16 | }
17 |
18 | .grid .text-left {
19 | text-align: left;
20 | }
21 |
22 | .grid .text-right {
23 | text-align: right;
24 | }
25 |
26 | .grid .text-center {
27 | text-align: center;
28 | }
29 |
30 | .grid .hide {
31 | display: none;
32 | }
33 |
34 | .grid .highlight {
35 | background: #ffff99;
36 | }
37 |
38 | /* The Grid ---------------------- */
39 | .grid .row {
40 | width: 100%;
41 | max-width: none;
42 | min-width: 600px;
43 | margin: 0 auto;
44 | }
45 |
46 | .grid .row .row {
47 | width: auto;
48 | max-width: none;
49 | min-width: 0;
50 | margin: 0 -5px;
51 | }
52 |
53 | .grid .row.collapse .column,
54 | .grid .row.collapse .columns {
55 | padding: 0;
56 | }
57 |
58 | .grid .row .row {
59 | width: auto;
60 | max-width: none;
61 | min-width: 0;
62 | margin: 0 -5px;
63 | }
64 |
65 | .grid .row .row.collapse {
66 | margin: 0;
67 | }
68 |
69 | .grid .column, .grid .columns {
70 | float: left;
71 | min-height: 1px;
72 | padding: 0 5px;
73 | position: relative;
74 | }
75 |
76 | .grid .column.centered, .grid .columns.centered {
77 | float: none;
78 | margin: 0 auto;
79 | }
80 |
81 | .grid .row .one {
82 | width: 8.333%;
83 | }
84 |
85 | .grid .row .two {
86 | width: 16.667%;
87 | }
88 |
89 | .grid .row .three {
90 | width: 25%;
91 | }
92 |
93 | .grid .row .four {
94 | width: 33.333%;
95 | }
96 |
97 | .grid .row .five {
98 | width: 41.667%;
99 | }
100 |
101 | .grid .row .six {
102 | width: 50%;
103 | }
104 |
105 | .grid .row .seven {
106 | width: 58.333%;
107 | }
108 |
109 | .grid .row .eight {
110 | width: 66.667%;
111 | }
112 |
113 | .grid .row .nine {
114 | width: 75%;
115 | }
116 |
117 | .grid .row .ten {
118 | width: 83.333%;
119 | }
120 |
121 | .grid .row .eleven {
122 | width: 91.667%;
123 | }
124 |
125 | .grid .row .twelve {
126 | width: 100%;
127 | }
128 |
129 | .grid .row .offset-by-one {
130 | margin-left: 8.333%;
131 | }
132 |
133 | .grid .row .offset-by-two {
134 | margin-left: 16.667%;
135 | }
136 |
137 | .grid .row .offset-by-three {
138 | margin-left: 25%;
139 | }
140 |
141 | .grid .row .offset-by-four {
142 | margin-left: 33.333%;
143 | }
144 |
145 | .grid .row .offset-by-five {
146 | margin-left: 41.667%;
147 | }
148 |
149 | .grid .row .offset-by-six {
150 | margin-left: 50%;
151 | }
152 |
153 | .grid .row .offset-by-seven {
154 | margin-left: 58.333%;
155 | }
156 |
157 | .grid .row .offset-by-eight {
158 | margin-left: 66.667%;
159 | }
160 |
161 | .grid .row .offset-by-nine {
162 | margin-left: 75%;
163 | }
164 |
165 | .grid .row .offset-by-ten {
166 | margin-left: 83.333%;
167 | }
168 |
169 | .grid .push-two {
170 | left: 16.667%;
171 | }
172 |
173 | .grid .pull-two {
174 | right: 16.667%;
175 | }
176 |
177 | .grid .push-three {
178 | left: 25%;
179 | }
180 |
181 | .grid .pull-three {
182 | right: 25%;
183 | }
184 |
185 | .grid .push-four {
186 | left: 33.333%;
187 | }
188 |
189 | .grid .pull-four {
190 | right: 33.333%;
191 | }
192 |
193 | .grid .push-five {
194 | left: 41.667%;
195 | }
196 |
197 | .grid .pull-five {
198 | right: 41.667%;
199 | }
200 |
201 | .grid .push-six {
202 | left: 50%;
203 | }
204 |
205 | .grid .pull-six {
206 | right: 50%;
207 | }
208 |
209 | .grid .push-seven {
210 | left: 58.333%;
211 | }
212 |
213 | .grid .pull-seven {
214 | right: 58.333%;
215 | }
216 |
217 | .grid .push-eight {
218 | left: 66.667%;
219 | }
220 |
221 | .grid .pull-eight {
222 | right: 66.667%;
223 | }
224 |
225 | .grid .push-nine {
226 | left: 75%;
227 | }
228 |
229 | .grid .pull-nine {
230 | right: 75%;
231 | }
232 |
233 | .grid .push-ten {
234 | left: 83.333%;
235 | }
236 |
237 | .grid .pull-ten {
238 | right: 83.333%;
239 | }
240 |
241 | /* Nicolas Gallagher's micro clearfix */
242 | .grid .row {
243 | *zoom: 1;
244 | }
245 |
246 | .grid .row:before, .grid .row:after {
247 | content: "";
248 | display: table;
249 | }
250 |
251 | .grid .row:after {
252 | clear: both;
253 | }
254 |
255 | /* Block Grids ---------------------- */
256 | /* These are 2-up, 3-up, 4-up and 5-up ULs, suited
257 | for repeating blocks of content. Add 'mobile' to
258 | them to switch them just like the layout grid
259 | (one item per line) on phones
260 |
261 | For IE7/8 compatibility block-grid items need to be
262 | the same height. You can optionally uncomment the
263 | lines below to support arbitrary height, but know
264 | that IE7/8 do not support :nth-child.
265 | -------------------------------------------------- */
266 | .grid .block-grid {
267 | display: block;
268 | overflow: hidden;
269 | padding: 0;
270 | }
271 |
272 | .grid .block-grid > li {
273 | display: block;
274 | height: auto;
275 | float: left;
276 | }
277 |
278 | .grid .block-grid.two-up {
279 | margin: 0 -15px;
280 | }
281 |
282 | .grid .block-grid.two-up > li {
283 | width: 50%;
284 | padding: 0 15px 15px;
285 | }
286 |
287 | /* .block-grid.two-up>li:nth-child(2n+1) {clear: left;} */
288 | .grid .block-grid.three-up {
289 | margin: 0 -12px;
290 | }
291 |
292 | .grid .block-grid.three-up > li {
293 | width: 33.33%;
294 | padding: 0 12px 12px;
295 | }
296 |
297 | /* .block-grid.three-up>li:nth-child(3n+1) {clear: left;} */
298 | .grid .block-grid.four-up {
299 | margin: 0 -10px;
300 | }
301 |
302 | .grid .block-grid.four-up > li {
303 | width: 25%;
304 | padding: 0 10px 10px;
305 | }
306 |
307 | /* .block-grid.four-up>li:nth-child(4n+1) {clear: left;} */
308 | .grid .block-grid.five-up {
309 | margin: 0 -8px;
310 | }
311 |
312 | .grid .block-grid.five-up > li {
313 | width: 20%;
314 | padding: 0 8px 8px;
315 | }
316 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.regionfilter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery region filter plugin.
3 | *
4 | * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
5 | * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
6 | * contributors. See CREDITS for a list.
7 | *
8 | * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
9 | * have to do anything special to choose one license or the other and you don't
10 | * have to notify anyone which license you are using. You are free to use
11 | * UniversalLanguageSelector in commercial projects as long as the copyright
12 | * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
13 | *
14 | * @file
15 | * @ingroup Extensions
16 | * @licence GNU General Public Licence 2.0 or later
17 | * @licence MIT License
18 | */
19 |
20 | ( function ( $ ) {
21 | 'use strict';
22 |
23 | /* RegionSelector plugin definition */
24 |
25 | var RegionSelector;
26 |
27 | /**
28 | * Region selector is a language selector based on regions.
29 | * Usage: $( 'jqueryselector' ).regionselector( options );
30 | * The attached element should have data-regiongroup attribute
31 | * that defines the regiongroup for the selector.
32 | */
33 | RegionSelector = function ( element, options ) {
34 | this.$element = $( element );
35 | this.options = $.extend( {}, $.fn.regionselector.defaults, options );
36 | this.$element.addClass( 'regionselector' );
37 | this.regions = [];
38 | this.cache = null;
39 | this.regionGroup = this.$element.data( 'regiongroup' );
40 | this.init();
41 | this.listen();
42 | };
43 |
44 | RegionSelector.prototype = {
45 | constructor: RegionSelector,
46 |
47 | init: function () {
48 | var region = this.$element.data( 'region' );
49 | this.regions = $.uls.data.getRegionsInGroup( this.regionGroup );
50 |
51 | if ( region ) {
52 | this.regions.push( region );
53 | }
54 | },
55 |
56 | test: function ( langCode ) {
57 | var region, i,
58 | langRegions = $.uls.data.getRegions( langCode );
59 |
60 | for ( i = 0; i < this.regions.length; i++ ) {
61 | region = this.regions[i];
62 |
63 | if ( $.inArray( region, langRegions ) >= 0 ) {
64 | this.render( langCode, region );
65 | this.cache[langCode] = region;
66 |
67 | return;
68 | }
69 | }
70 | },
71 |
72 | show: function () {
73 | var result, languagesByScriptGroup, scriptGroup, languages, i,
74 | $element = this.options.$target && this.options.$target.$element,
75 | $parent = $element && $element.parent(),
76 | $prev = $element && $element.prev();
77 |
78 | if ( $element && $parent ) {
79 | // Avoid reflows while adding new elements to the list
80 | // Use .detach() to keep jQuery events and data associated with elements
81 | $element.detach();
82 | }
83 |
84 | if ( this.cache ) {
85 | // If the result cache is present, render the results from there.
86 | //noinspection JSUnusedAssignment
87 | result = null;
88 |
89 | for ( result in this.cache ) {
90 | this.render( result, this.cache[result] );
91 | }
92 | } else {
93 | this.cache = {};
94 | // Get the languages grouped by script group
95 | languagesByScriptGroup = $.uls.data.getLanguagesByScriptGroup( this.options.languages );
96 |
97 | // Make sure that we go by the original order
98 | // of script groups
99 | for ( scriptGroup in $.uls.data.scriptgroups ) {
100 | // Get the languages for the script group
101 | languages = languagesByScriptGroup[scriptGroup];
102 |
103 | // It's possible that some script groups are missing
104 | if ( !languages ) {
105 | continue;
106 | }
107 |
108 | // Sort it based on autonym
109 | languages.sort( $.uls.data.sortByAutonym );
110 |
111 | for ( i = 0; i < languages.length; i++ ) {
112 | // Check whether it belongs to the region
113 | this.test( languages[i] );
114 | }
115 | }
116 | }
117 |
118 | if ( $element && $parent ) {
119 | // Restore the element to where we removed it from
120 | if ( $prev ) {
121 | $prev.after( $element );
122 | } else {
123 | $parent.append( $element );
124 | }
125 | }
126 |
127 | if ( this.options.success ) {
128 | this.options.success( this );
129 | }
130 | },
131 |
132 | render: function ( langCode, region ) {
133 | var $target = this.options.$target;
134 |
135 | if ( !$target ) {
136 | return;
137 | }
138 |
139 | $target.append( langCode, region );
140 | },
141 |
142 | listen: function () {
143 | this.$element.on( 'click', $.proxy( this.click, this ) );
144 | },
145 |
146 | click: function () {
147 | var $list, $firstTargetRegion;
148 |
149 | // Don't do anything if a region is selected already
150 | if ( this.$element.hasClass( 'active' ) ) {
151 | return;
152 | }
153 |
154 | $list = this.options.$target.$element;
155 | $firstTargetRegion = $list.find( '#' + this.regions[0] );
156 |
157 | // Scroll to appropriate area
158 | $list.scrollTop(
159 | $firstTargetRegion.offset().top - $list.offset().top + $list.scrollTop()
160 | );
161 |
162 | // Make the selected region (and it only) active
163 | $( '.regionselector' ).removeClass( 'active' );
164 |
165 | if ( this.regionGroup ) {
166 | // if there is a region group, make it active.
167 | this.$element.addClass( 'active' );
168 | }
169 | }
170 | };
171 |
172 | /* RegionSelector plugin definition */
173 |
174 | $.fn.regionselector = function ( option ) {
175 | return this.each( function () {
176 | var $this = $( this ),
177 | data = $this.data( 'regionselector' ),
178 | options = typeof option === 'object' && option;
179 |
180 | if ( !data ) {
181 | $this.data( 'regionselector', ( data = new RegionSelector( this, options ) ) );
182 | }
183 |
184 | if ( typeof option === 'string' ) {
185 | data[option]();
186 | }
187 | } );
188 | };
189 |
190 | $.fn.regionselector.defaults = {
191 | $target: null, // Where to render the results
192 | success: null, // callback if any results found.
193 | noresults: null, // callback when no results to show
194 | languages: null
195 | };
196 |
197 | $.fn.regionselector.Constructor = RegionSelector;
198 | } ( jQuery ) );
199 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # asknot-ng
2 |
3 | [](https://travis-ci.org/fedora-infra/asknot-ng)
4 |
5 | Ask not what `$ORG` can do for you, but what you can do for `$ORG`.
6 |
7 | Written by [@ralphbean][threebean]. Inspired by [the original work][wcidfm] of
8 | [Josh Matthews][jdm], [Henri Koivuneva][wham], and [others][asknot-contribs].
9 |
10 | I stumbled upon and loved the original [whatcanidoformozilla.org][wcidfm] and
11 | wanted to deploy it for the [Fedora Community][fedora] but I found that I
12 | couldn’t easily change the questions and links that were presented. A year
13 | went by and in 2015 I wrote this: “asknot-ng”.
14 |
15 | The gist of this “next generation” rewrite is to make it as configurable as
16 | possible. There is a primary script, ``asknot-ng.py``
17 | that works like a static-site generator. It takes as input three things:
18 |
19 | - A questions file, written in yaml (see the [example][example-questions] or
20 | [Fedora’s file][fedora-questions]). You’ll have to write your own one of
21 | these.
22 | - A template file, written in mako (the [default][default-template] should work
23 | for everybody).
24 | - A ‘theme’ argument to specify what CSS to use. The default is nice enough,
25 | but you’ll probably want to customize it to your own use case.
26 |
27 | We have a [Fedora instance up and running][wcidff] if you’d like to poke it.
28 |
29 | [](https://translate.fedoraproject.org/engage/fedora-infra/?utm_source=widget)
30 |
31 | ## Tools
32 |
33 | 1. HTML5 - The Structure.
34 | 2. CSS3 - The Style.
35 | 3. Javascript - The Functions.
36 | 4. Jquery - JavaScript libraries to select, remove, clone, and modify different elements on the page.
37 | 5. Bootstrap - Bootstrap is a front end framework used to design responsive web pages and applications.
38 |
39 | ## Requirements
40 |
41 | The site-generator script is written in Python, so you’ll need that.
42 | Furthermore, see [requirements.txt][requirements] or just run::
43 |
44 | $ sudo dnf install python-mako PyYAML python-virtualenv
45 |
46 | The script can optionally generate an svg visualizing your question tree. This
47 | requires pygraphviz which you could install like so:
48 |
49 | $ sudo dnf install python-pygraphviz
50 |
51 | ## Giving it a run
52 |
53 | Install the requirements, first.
54 |
55 | Clone the repo::
56 |
57 | $ git clone https://github.com/fedora-infra/asknot-ng.git
58 | $ cd asknot-ng
59 |
60 | Create a virtualenv into which you can install the module.
61 |
62 | $ virtualenv --system-site-packages venv
63 | $ source venv/bin/activate
64 | $ python setup.py develop
65 |
66 | Run the script with the Fedora configuration::
67 |
68 | $ ./asknot-ng.py templates/index.html questions/fedora.yml l10n/fedora/locale --theme fedora
69 | Wrote build/en/index.html
70 |
71 | and open up `build/en/index.html` in your favorite browser.
72 |
73 | ## Preparing Translations
74 |
75 | First, setup a virtualenv, install Babel, and build the egg info.
76 |
77 | $ virtualenv venv
78 | $ source venv/bin/activate
79 | $ pip install Babel
80 | $ python setup.py develop
81 |
82 | Then, extract the translatable strings:
83 |
84 | $ python setup.py extract_messages --output-file l10n/fedora/locale/asknot-ng.pot --input-dir=.
85 |
86 | ## Container
87 |
88 | Asknot can be build and released as a container, to do so you can use the provided Dockerfile.
89 |
90 | ###### Releasing a container
91 |
92 | ```
93 | podman build -t asknot .
94 | ```
95 |
96 | The Dockerfile makes use of multistage container build, meaning that in a first stage a container is used to prepare the translations and build the static pages then the static content is copied to a second container which is used to serve this content.
97 |
98 | ###### Running Container
99 |
100 | ```
101 | podman run --name=asknot -d -p 8080:80 --net=host localhost/asknot
102 | ```
103 |
104 | ###### Composing Container
105 |
106 | Asknot can be build and released as a container, in other similar way to do so you can use the provided Dockerfile-compose file.
107 |
108 | ```
109 | podman-compose up -d
110 | ```
111 |
112 | ###### Verifiying
113 |
114 | In your Favorite Browser Just type:
115 |
116 | ```
117 | localhost:8080
118 | ```
119 |
120 | ## Application Deployment
121 |
122 | ``asknot-ng`` currently runs on Fedora infrastructure Openshift instance. There are 2 deployments one in [staging] and one in [production].
123 |
124 | The deployment of new version to these environment is managed from the github repository, thanks to the following 2 branches ``staging`` and ``production``.
125 |
126 | ### Staging
127 |
128 | To deploy a change to the staging environment you need to push the commits to the ``staging`` branch, then Openshift will trigger a build using the Dockerfile located
129 | in this repository and deploy the new application.
130 |
131 | ### Production
132 |
133 | To deploy a change in the production environment you need to push the commits to the ``production`` branch, then Openshift will trigger a build using the Dockerfile located
134 | in this repository and deploy the new application.
135 |
136 | ## Contributing back
137 |
138 | ``asknot-ng`` is licensed GPLv3+ and we’d love to get patches back containing
139 | even the things you might not think we want. If you have a questions file for
140 | your repo, a modified template, or a CSS theme for your use case, please
141 | [send them to us][patches]. It would be nice to build a library of deployments
142 | so we can all learn.
143 |
144 | **Note**: While the application is licensed GPLv3+, The [Fedora 22 wallpaper](static/themes/fedora/img/background.png) used is licensed under a *Creative Commons Attribution 4 License*.
145 |
146 | Of course, bug reports and patches to the main script are appreciated as
147 | always.
148 |
149 | Happy Hacking!
150 |
151 | [threebean]: http://threebean.org
152 | [fedora]: http://getfedora.org
153 | [example-questions]: https://github.com/fedora-infra/asknot-ng/blob/develop/questions/example.yml
154 | [fedora-questions]: https://github.com/fedora-infra/asknot-ng/blob/develop/questions/fedora.yml
155 | [default-template]: https://github.com/fedora-infra/asknot-ng/blob/develop/templates/index.html
156 | [requirements]: https://github.com/fedora-infra/asknot-ng/blob/develop/requirements.txt
157 | [patches]: https://help.github.com/articles/editing-files-in-another-user-s-repository/
158 | [wcidfm]: https://web.archive.org/web/20220714110613/https://www.whatcanidoformozilla.org/
159 | [wcidff]: http://whatcanidoforfedora.org
160 | [jdm]: http://www.joshmatthews.net
161 | [wham]: http://wham.fi
162 | [asknot-contribs]: https://github.com/jdm/asknot/contributors
163 | [staging]: https://stg.whatcanidoforfedora.org/
164 | [production]: https://whatcanidoforfedora.org/
165 |
--------------------------------------------------------------------------------
/static/themes/fedora/css/site.css:
--------------------------------------------------------------------------------
1 | a,
2 | a:focus,
3 | a:hover {
4 | color: #fff;
5 | }
6 | .bandana a,
7 | .bandana a:focus,
8 | .bandana a:hover {
9 | color: #27ae60;
10 | }
11 |
12 | /* Custom default button */
13 | .btn-default,
14 | .btn-default:hover,
15 | .btn-default:focus {
16 | color: #333;
17 | text-shadow: none; /* Prevent inheritence from `body` */
18 | background-color: #fff;
19 | border: 1px solid #fff;
20 | }
21 |
22 | html,
23 | body {
24 | height: 100%;
25 | background-color: white;
26 | background-size: 100% auto;
27 | }
28 |
29 | body {
30 | color: black;
31 | font-family: 'Open Sans';
32 | font-style: normal;
33 | font-weight: 400;
34 | text-align: center;
35 | text-shadow: 0 1px 3px rgba(0,0,0,.5);
36 | }
37 |
38 | .site-wrapper {
39 | width: 100%;
40 | height: 100%; /* For at least Firefox */
41 | min-height: 100%;
42 | /* -webkit-box-shadow: inset 0 0 75px rgba(0,0,0,.5);
43 | box-shadow: inset 0 0 75px rgba(0,0,0,.5); */
44 | }
45 |
46 | .site-wrapper-inner {
47 | height: -webkit-calc(100% - 40px);
48 | height: -moz-calc(100% - 40px);
49 | height: calc(100% - 40px);
50 | }
51 |
52 | .cover-container {
53 | position: relative;
54 | top: 40%;
55 | -webkit-transform: translateY(-45%);
56 | -ms-transform: translateY(-45%);
57 | transform: translateY(-45%);
58 | width: 100%;
59 | }
60 |
61 | /* Padding for spacing */
62 | .inner {
63 | padding: 30px;
64 | }
65 |
66 | #js-warning .panel-body {
67 | background-color: #3c6eb4;
68 | }
69 |
70 | /*
71 | * Header
72 | */
73 | .masthead-brand {
74 | background: url('../img/sidebar-logo.png');
75 | margin-bottom: 10px;
76 | margin-right: auto;
77 | margin-left: auto;
78 | display: block;
79 | width: 141px;
80 | height: 50px;
81 | background-repeat: no-repeat;
82 |
83 | text-indent: -9999px;
84 |
85 | }
86 |
87 | .masthead.clearfix{
88 | background-color: #51a2da;
89 | border: 2px solid #51a2da;
90 | /* border-radius: 8px; */
91 | }
92 |
93 | .masthead-nav > li {
94 | display: inline-block;
95 | }
96 |
97 | .masthead-nav > li + li {
98 | margin-left: 20px;
99 | }
100 |
101 | .masthead-nav > li > a {
102 | padding-right: 0;
103 | padding-left: 0;
104 | font-size: 16px;
105 | font-weight: bold;
106 | font-family: Montserrat;
107 | font-style: normal;
108 | font-weight: 400;
109 | /* color: #fff; /* IE8 proofing */
110 | /* color: rgba(255,255,255,.75); */
111 | color: black;
112 | border-bottom: 2px solid transparent;
113 | }
114 |
115 | .masthead-nav > li > a:hover,
116 | .masthead-nav > li > a:focus {
117 | background-color: transparent;
118 | border-bottom-color: #a9a9a9;
119 | border-bottom-color: rgba(255,255,255,.25);
120 | }
121 |
122 | .masthead-nav > .active > a,
123 | .masthead-nav > .active > a:hover,
124 | .masthead-nav > .active > a:focus,
125 | .masthead-nav > .open > a,
126 | .masthead-nav > .open > a:hover,
127 | .masthead-nav > .open > a:focus {
128 | color: #fff;
129 | background-color: transparent;
130 | border-bottom-color: #fff;
131 | }
132 |
133 | .dropdown-menu {
134 | min-width: 105px;
135 | }
136 |
137 | .cover .btn-lg {
138 | padding: 10px 20px;
139 | font-weight: bold;
140 | }
141 |
142 | .bandana {
143 | background-color: #fff;
144 | width: 100%;
145 | margin-bottom: 25px;
146 | padding: 20px;
147 |
148 | position: relative;
149 | overflow: hidden;
150 | }
151 |
152 | .main-text {
153 | vertical-align: middle;
154 | display: inline-block;
155 | /* This has to be relative just so z-index applies */
156 | position: relative;
157 | z-index: 2;
158 | }
159 |
160 | .bandana .img {
161 | display: none;
162 |
163 | margin-top: -100px;
164 | margin-bottom: -100px;
165 | position: absolute;
166 | right: 10%;
167 | opacity: 0.5;
168 | z-index: 0;
169 | }
170 |
171 | .bandana .img img {
172 | z-index: -1;
173 | height: 400px;
174 | width: 400px
175 | }
176 |
177 | /*
178 | * Footer
179 | */
180 | .mastfoot {
181 | color: #999; /* IE8 proofing */
182 | color: rgba(255,255,255,.5);
183 | /* display: none; */
184 | display: block;
185 | }
186 |
187 | .mastfoot {
188 | height: 40px;
189 | background-color: #51a2da;
190 | border: 2px solid #51a2da;
191 | /* border-radius: 8px; */
192 | }
193 |
194 | .masthead, .mastfoot {
195 | margin-right: auto;
196 | margin-left: auto;
197 | }
198 |
199 | .title {
200 | font-size: 40pt;
201 | font-weight: 900;
202 | color: #294172;
203 | text-transform: uppercase;
204 | }
205 |
206 | .segue1 {
207 | font-size: 12pt;
208 | font-style: italic;
209 | margin-bottom: -10px;
210 | }
211 |
212 | .segue2 {
213 | font-size: 15pt;
214 | font-style: italic;
215 | }
216 |
217 | .subtitle {
218 | font-size: 15pt;
219 | font-style: italic;
220 | margin-top: -10px;
221 | padding-bottom: 12px;
222 | color: #3c6eb4;
223 | border-bottom: dashed 1px #3c6eb4;
224 | display: inline;
225 | }
226 |
227 | /* Extra small devices (phones, 600px and down) */
228 | @media only screen and (max-width: 600px) {
229 | .title { font-size: 25px; }
230 | .segue1 { font-size: 15pt; }
231 | .segue2 { font-size: 15pt; }
232 | .subtitle { font-size: 10pt; }
233 | .bandana .img { display: inline-block; }
234 | .masthead-brand { float: top; }
235 | .masthead-nav { float: center; }
236 | .mastfoot {
237 | float: bottom;
238 | }
239 | .masthead.clearfix {
240 | width: 100%;
241 | height: 20%;
242 | }
243 | .inner {
244 | padding: 6px;
245 | }
246 | .btn-lg {
247 | font-size: 12px;
248 | }
249 |
250 | .masthead-nav > li > a {
251 | font-size: 12px;
252 | }
253 | }
254 |
255 | /* Small devices (portrait tablets and large phones, 600px and up) */
256 | @media only screen and (min-width: 600px) {
257 | .title { font-size: 64pt; }
258 | .segue1 { font-size: 18pt; }
259 | .segue2 { font-size: 32pt; }
260 | .subtitle { font-size: 24pt; }
261 | .bandana .img { display: inline-block; }
262 | .masthead-brand {
263 | float: left;
264 | }
265 | .masthead-nav {
266 | float: center;
267 | }
268 | .mastfoot {
269 | float: bottom;
270 | }
271 | }
272 |
273 | /* Medium devices (landscape tablets, 768px and up) */
274 | @media only screen and (min-width: 768px) {
275 | .title { font-size: 64pt; }
276 | .segue1 { font-size: 18pt; }
277 | .segue2 { font-size: 32pt; }
278 | .subtitle { font-size: 24pt; }
279 | .bandana .img { display: inline-block; }
280 | .masthead-brand {
281 | float: left;
282 | }
283 | .masthead-nav {
284 | float: center;
285 | }
286 | .mastfoot {
287 | float: bottom;
288 | }
289 | }
290 |
291 | /* Large devices (laptops/desktops, 992px and up) */
292 | @media only screen and (min-width: 992px) {
293 | .title { font-size: 64pt; }
294 | .segue1 { font-size: 18pt; }
295 | .segue2 { font-size: 32pt; }
296 | .subtitle { font-size: 24pt; }
297 | .bandana .img { display: inline-block; }
298 | .masthead-brand {
299 | float: left;
300 | }
301 | .masthead-nav {
302 | float: center;
303 | }
304 | .mastfoot {
305 | float: bottom;
306 | }
307 | }
308 |
309 | /* Extra large devices (large laptops and desktops, 1200px and up) */
310 | @media only screen and (min-width: 1200px) {
311 | .title { font-size: 64pt; }
312 | .segue1 { font-size: 18pt; }
313 | .segue2 { font-size: 32pt; }
314 | .subtitle { font-size: 24pt; }
315 | .bandana .img { display: inline-block; }
316 | .masthead-brand {
317 | float: left;
318 | }
319 | .masthead-nav {
320 | float: center;
321 | }
322 | .mastfoot {
323 | float: bottom;
324 | }
325 | }
326 |
--------------------------------------------------------------------------------
/static/jquery.uls/css/jquery.uls.css:
--------------------------------------------------------------------------------
1 | .uls-trigger {
2 | /* @embed */
3 | background: transparent url('../img/icon-language.png') no-repeat scroll left center;
4 | /* @embed */
5 | background-image: -webkit-linear-gradient(transparent, transparent), url('../img/icon-language.svg');
6 | /* @embed */
7 | background-image: linear-gradient(transparent, transparent), url('../img/icon-language.svg');
8 | padding-left: 30px;
9 | }
10 |
11 | .uls-menu {
12 | position: absolute;
13 | z-index: 1000;
14 | display: none;
15 | margin-top: 1px;
16 | /* Styling */
17 | background-color: #ffffff;
18 | border: 1px solid #ccc;
19 | border: 1px solid rgba(0, 0, 0, 0.2);
20 | border-radius: 5px;
21 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
22 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
23 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
24 | -webkit-background-clip: padding-box;
25 | -moz-background-clip: padding;
26 | background-clip: padding-box;
27 | }
28 |
29 | .uls-wide {
30 | min-width: 715px;
31 | width: 45%;
32 | }
33 |
34 | .uls-title-region a {
35 | padding-left: 15px;
36 | }
37 |
38 | .uls-menu .uls-title {
39 | font-weight: normal;
40 | border: none;
41 | padding-top: 1.25em;
42 | padding-left: 15px;
43 | padding-bottom: 3px;
44 | font-size: 18pt;
45 | line-height: 1.25em;
46 | color: #555;
47 | }
48 |
49 | .uls-menu .uls-no-results-found-title {
50 | font-size: 16pt;
51 | font-weight: bold;
52 | line-height: 1.5em;
53 | padding-left: 6px;
54 | padding-top: 10px;
55 | margin-top: 0;
56 | margin-bottom: 15px;
57 | border-bottom: none;
58 | color: #555;
59 | }
60 |
61 | .uls-menu .uls-lcd-region-section .uls-lcd-region-title {
62 | color: #777;
63 | font-size: 14pt;
64 | font-weight: lighter;
65 | line-height: 1.5em;
66 | padding-left: 0;
67 | margin-top: 0;
68 | margin-bottom: 10px;
69 | border-bottom: none;
70 | }
71 |
72 | .uls-worldmap {
73 | /* @embed */
74 | background: transparent url('../img/world_map.png') no-repeat scroll right top;
75 | /* @embed */
76 | background-image: -webkit-linear-gradient(transparent, transparent), url('../img/world_map.svg');
77 | /* @embed */
78 | background-image: linear-gradient(transparent, transparent), url('../img/world_map.svg');
79 | background-size: 100%;
80 | }
81 |
82 | div.uls-region {
83 | cursor: pointer;
84 | padding: 0;
85 | margin: 0;
86 | height: 120px;
87 | border-bottom-color: transparent;
88 | border-bottom-style: solid;
89 | border-bottom-width: 2px;
90 | }
91 |
92 | .uls-worldmap .uls-region { /* The map doesn't flip */
93 | /* @noflip */
94 | float: left;
95 | }
96 |
97 | .uls-region a {
98 | bottom: 2px;
99 | left: 2px;
100 | padding: 0;
101 | position: absolute;
102 | font-size: 13px;
103 | line-height: 1.2em;
104 | text-decoration: none;
105 | overflow: hidden;
106 | text-overflow: ellipsis;
107 | width: 99%;
108 | }
109 |
110 | .uls-region:hover {
111 | /*Cross-browser background transparency*/
112 | background: #3366bb;
113 | background: rgba(51, 102, 187, 0.1);
114 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#253366bb, endColorstr=#253366bb );
115 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#253366bb, endColorstr=#253366bb)";
116 | }
117 |
118 | .uls-map-block .active {
119 | border-bottom-color: #3366bb;
120 | border-bottom-style: solid;
121 | }
122 |
123 | .uls-menu .row .uls-map-block {
124 | top: 1px;
125 | margin-right: 0;
126 | padding-right: 0;
127 | float: right;
128 | overflow: hidden;
129 | opacity: 0.7;
130 | -moz-transition: opacity 0.2s linear;
131 | -o-transition: opacity 0.2s linear;
132 | -webkit-transition: opacity 0.2s linear;
133 | transition: opacity 0.2s linear;
134 | }
135 |
136 | .uls-map-block a {
137 | color: #333;
138 | opacity: 0;
139 | -moz-transition: opacity 0.15s linear;
140 | -o-transition: opacity 0.15s linear;
141 | -webkit-transition: opacity 0.15s linear;
142 | transition: opacity 0.15s linear;
143 | }
144 |
145 | .uls-menu .uls-map-block:hover,
146 | .uls-menu .uls-map-block:hover a {
147 | opacity: 1;
148 | color: #333;
149 | }
150 |
151 | .uls-map-block .uls-region-1 {
152 | border-color: transparent;
153 | }
154 |
155 | .uls-map-block:hover .active {
156 | border-color: #3366bb;
157 | }
158 |
159 | .uls-map-block .active a {
160 | font-weight: bold;
161 | }
162 |
163 | .uls-icon-close {
164 | /* @embed */
165 | background: transparent url('../img/close.png') no-repeat scroll center center;
166 | /* @embed */
167 | background-image: -webkit-linear-gradient(transparent, transparent), url('../img/close.svg');
168 | /* @embed */
169 | background-image: linear-gradient(transparent, transparent), url('../img/close.svg');
170 | float: right;
171 | padding: 15px;
172 | cursor: pointer;
173 | }
174 |
175 | .uls-menu .uls-languagefilter {
176 | background-color: transparent;
177 | border: 1px solid #c9c9c9;
178 | border-radius: 2px 2px 2px 2px;
179 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset;
180 | color: #333;
181 | display: block;
182 | padding: 6px;
183 | -moz-transition: border 0.15s linear 0s;
184 | -o-transition: border 0.15s linear 0s;
185 | -webkit-transition: border 0.15s linear 0s;
186 | transition: border 0.15s linear 0s;
187 | }
188 |
189 | .uls-menu .uls-languagefilter:focus {
190 | border: 1px solid #3366bb;
191 | }
192 |
193 | .uls-menu .uls-search {
194 | position: relative;
195 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F0F0F0', endColorstr='#FBFBFB');
196 | background: #f8f8f8;
197 | background: -webkit-gradient(linear, left top, left bottom, from(#F0F0F0), to(#FBFBFB));
198 | background: -webkit-linear-gradient(top, #F0F0F0, #FBFBFB);
199 | background: -moz-linear-gradient(top, #F0F0F0, #FBFBFB);
200 | background: -o-linear-gradient(top, #F0F0F0, #FBFBFB);
201 | background: linear-gradient(#F0F0F0, #FBFBFB);
202 | border-top-color: #AAA;
203 | border-top-style: solid;
204 | border-top-width: 1px;
205 | padding: 0.8em 0;
206 | border-bottom-width: 1px;
207 | border-bottom-style: solid;
208 | border-bottom-color: #DDD;
209 | }
210 |
211 | .uls-menu .uls-search-label {
212 | /* @embed */
213 | background: transparent url('../img/search.png') no-repeat scroll right center;
214 | /* @embed */
215 | background-image: -webkit-linear-gradient(transparent, transparent), url('../img/search.svg');
216 | /* @embed */
217 | background-image: linear-gradient(transparent, transparent), url('../img/search.svg');
218 | background-size: 30px;
219 | height: 32px;
220 | width: 32px;
221 | float: right;
222 | }
223 |
224 | .uls-menu .uls-languagefilter-clear {
225 | /* @embed */
226 | background: transparent url('../img/clear.png') no-repeat scroll left center;
227 | /* @embed */
228 | background-image: -webkit-linear-gradient(transparent, transparent), url('../img/clear.svg');
229 | /* @embed */
230 | background-image: linear-gradient(transparent, transparent), url('../img/clear.svg');
231 | cursor: pointer;
232 | height: 32px;
233 | position: absolute;
234 | width: 32px;
235 | margin-left: -32px;
236 | }
237 |
238 | .uls-menu .uls-filterinput {
239 | position: absolute;
240 | top: 0;
241 | left: 0;
242 | font-size: 14px;
243 | height: 32px;
244 | width: 100%;
245 | text-align: left;
246 | }
247 |
248 | .uls-menu .uls-filtersuggestion {
249 | padding: 6px;
250 | background-color: white;
251 | color: #888;
252 | border: 1px transparent;
253 | border-radius: 2px 2px 2px 2px;
254 | box-shadow: 0 1px 2px transparent inset;
255 | left: 1px;
256 | }
257 |
258 | .uls-menu .uls-search-input-block {
259 | position: relative;
260 | }
261 |
--------------------------------------------------------------------------------
/static/jquery.uls/css/jquery.uls.mobile.css:
--------------------------------------------------------------------------------
1 | @media only screen and (max-width: 767px) {
2 |
3 | .uls-mobile.uls-menu {
4 | width: 95%;
5 | left: 2.5%;
6 | }
7 |
8 | .uls-mobile .uls-language-list {
9 | -webkit-overflow-scrolling: touch;
10 | }
11 |
12 | .uls-mobile .uls-language-block {
13 | padding-left: 15px !important;
14 | }
15 |
16 | .uls-mobile .uls-language-block ul {
17 | min-height: 14em;
18 | }
19 |
20 | .uls-mobile .uls-language-block a {
21 | font-size: 16px;
22 | line-height: 1.7em;
23 | }
24 |
25 | .uls-mobile div.uls-region {
26 | width: 33% !important;
27 | float: left !important;
28 | }
29 |
30 | .uls-mobile .uls-map-block a,
31 | .uls-mobile .uls-map-block {
32 | opacity: 1 !important;
33 | }
34 |
35 | .uls-mobile .row {
36 | width: auto;
37 | min-width: 0;
38 | margin-left: 0;
39 | margin-right: 0;
40 | }
41 |
42 | .uls-mobile .column,
43 | .uls-mobile .columns {
44 | width: auto !important;
45 | float: none;
46 | }
47 |
48 | .uls-mobile .column:last-child,
49 | .uls-mobile .columns:last-child {
50 | float: none;
51 | }
52 |
53 | .uls-mobile [class*="column"] + [class*="column"]:last-child {
54 | float: none;
55 | }
56 |
57 | .uls-mobile .column:before,
58 | .uls-mobile .uls-mobile .columns:before,
59 | .uls-mobile .column:after,
60 | .columns:after {
61 | content: "";
62 | display: table;
63 | }
64 |
65 | .uls-mobile .column:after,
66 | .uls-mobile .columns:after {
67 | clear: both;
68 | }
69 |
70 | .uls-mobile .offset-by-one,
71 | .uls-mobile .offset-by-two,
72 | .uls-mobile .offset-by-three,
73 | .uls-mobile .offset-by-four,
74 | .uls-mobile .offset-by-five,
75 | .uls-mobile .offset-by-six,
76 | .uls-mobile .offset-by-seven,
77 | .uls-mobile .offset-by-eight,
78 | .uls-mobile .offset-by-nine,
79 | .uls-mobile .offset-by-ten {
80 | margin-left: 0 !important;
81 | }
82 |
83 | .uls-mobile .push-two,
84 | .uls-mobile .push-three,
85 | .uls-mobile .push-four,
86 | .uls-mobile .push-five,
87 | .uls-mobile .push-six,
88 | .uls-mobile .push-seven,
89 | .uls-mobile .push-eight,
90 | .uls-mobile .push-nine,
91 | .uls-mobile .push-ten {
92 | left: auto;
93 | }
94 |
95 | .uls-mobile .pull-two,
96 | .uls-mobile .pull-three,
97 | .uls-mobile .pull-four,
98 | .uls-mobile .pull-five,
99 | .uls-mobile .pull-six,
100 | .uls-mobile .pull-seven,
101 | .uls-mobile .pull-eight,
102 | .uls-mobile .pull-nine,
103 | .uls-mobile .pull-ten {
104 | right: auto;
105 | }
106 |
107 | /* Mobile 4-column Grid */
108 | .uls-mobile .row .mobile-one {
109 | width: 25% !important;
110 | float: left;
111 | padding: 0 4px;
112 | }
113 |
114 | .uls-mobile .row .mobile-one:last-child {
115 | float: right;
116 | }
117 |
118 | .uls-mobile .row.collapse .mobile-one {
119 | padding: 0;
120 | }
121 |
122 | .uls-mobile .row .mobile-two {
123 | width: 50% !important;
124 | float: left;
125 | padding: 0 4px;
126 | }
127 |
128 | .uls-mobile .row .mobile-two:last-child {
129 | float: right;
130 | }
131 |
132 | .uls-mobile .row.collapse .mobile-two {
133 | padding: 0;
134 | }
135 |
136 | .uls-mobile .row .mobile-three {
137 | width: 75% !important;
138 | float: left;
139 | padding: 0 4px;
140 | }
141 |
142 | .uls-mobile .row .mobile-three:last-child {
143 | float: right;
144 | }
145 |
146 | .uls-mobile .row.collapse .mobile-three {
147 | padding: 0;
148 | }
149 |
150 | .uls-mobile .row .mobile-four {
151 | width: 100% !important;
152 | float: left;
153 | padding: 0 4px;
154 | }
155 |
156 | .uls-mobile .row .mobile-four:last-child {
157 | float: right;
158 | }
159 |
160 | .uls-mobile .row.collapse .mobile-four {
161 | padding: 0;
162 | }
163 |
164 | .uls-mobile .push-one-mobile {
165 | left: 25%;
166 | }
167 |
168 | .uls-mobile .pull-one-mobile {
169 | right: 25%;
170 | }
171 |
172 | .uls-mobile .push-two-mobile {
173 | left: 50%;
174 | }
175 |
176 | .uls-mobile .pull-two-mobile {
177 | right: 50%;
178 | }
179 |
180 | .uls-mobile .push-three-mobile {
181 | left: 75%;
182 | }
183 |
184 | .uls-mobile .pull-three-mobile {
185 | right: 75%;
186 | }
187 | }
188 |
189 | /* Visibility Classes ---------------------- */
190 | /* Standard (large) display targeting */
191 | .uls-mobile .show-for-small,
192 | .uls-mobile .show-for-medium,
193 | .uls-mobile .show-for-medium-down,
194 | .uls-mobile .hide-for-large,
195 | .uls-mobile .hide-for-large-up,
196 | .uls-mobile .show-for-xlarge {
197 | display: none !important;
198 | }
199 |
200 | .uls-mobile .hide-for-xlarge,
201 | .uls-mobile .show-for-large,
202 | .uls-mobile .show-for-large-up,
203 | .uls-mobile .hide-for-small,
204 | .uls-mobile .hide-for-medium,
205 | .uls-mobile .hide-for-medium-down {
206 | display: block !important;
207 | }
208 |
209 | /* Very large display targeting */
210 | @media only screen and (min-width: 1441px) {
211 |
212 | .uls-mobile .hide-for-small,
213 | .uls-mobile .hide-for-medium,
214 | .uls-mobile .hide-for-medium-down,
215 | .hide-for-large, .show-for-large-up,
216 | .show-for-xlarge {
217 | display: block !important;
218 | }
219 |
220 | .show-for-small,
221 | .uls-mobile .show-for-medium,
222 | .uls-mobile .show-for-medium-down,
223 | .uls-mobile .show-for-large,
224 | .uls-mobile .hide-for-large-up,
225 | .uls-mobile .hide-for-xlarge {
226 | display: none !important;
227 | }
228 | }
229 | /* Medium display targeting */
230 | @media only screen and (max-width: 1279px) and (min-width: 768px) {
231 |
232 | .uls-mobile .hide-for-small,
233 | .uls-mobile .show-for-medium,
234 | .uls-mobile .show-for-medium-down,
235 | .uls-mobile .hide-for-large,
236 | .uls-mobile .hide-for-large-up,
237 | .uls-mobile .hide-for-xlarge {
238 | display: block !important;
239 | }
240 |
241 | .uls-mobile .show-for-small,
242 | .uls-mobile .hide-for-medium,
243 | .uls-mobile .hide-for-medium-down,
244 | .uls-mobile .show-for-large,
245 | .uls-mobile .show-for-large-up,
246 | .uls-mobile .show-for-xlarge {
247 | display: none !important;
248 | }
249 | }
250 | /* Small display targeting */
251 | @media only screen and (max-width: 767px) {
252 |
253 | .uls-mobile .show-for-small,
254 | .uls-mobile .hide-for-medium,
255 | .uls-mobile .show-for-medium-down,
256 | .uls-mobile .hide-for-large,
257 | .uls-mobile .hide-for-large-up,
258 | .uls-mobile .hide-for-xlarge {
259 | display: block !important;
260 | }
261 | .uls-mobile .hide-for-small,
262 | .uls-mobile .show-for-medium,
263 | .uls-mobile .hide-for-medium-down,
264 | .uls-mobile .show-for-large,
265 | .uls-mobile .show-for-large-up,
266 | .uls-mobile .show-for-xlarge {
267 | display: none !important;
268 | }
269 | }
270 |
271 | /* Orientation targeting */
272 | .uls-mobile .show-for-landscape,
273 | .uls-mobile .hide-for-portrait {
274 | display: block !important;
275 | }
276 |
277 | .uls-mobile .hide-for-landscape,
278 | .uls-mobile .show-for-portrait {
279 | display: none !important;
280 | }
281 |
282 | @media screen and (orientation: landscape) {
283 | .uls-mobile .show-for-landscape,
284 | .uls-mobile .hide-for-portrait {
285 | display: block !important;
286 | }
287 | .uls-mobile .hide-for-landscape,
288 | .uls-mobile .show-for-portrait {
289 | display: none !important;
290 | }
291 | }
292 |
293 | @media screen and (orientation: portrait) {
294 | .uls-mobile .show-for-portrait,
295 | .uls-mobile .hide-for-landscape {
296 | display: block !important;
297 | }
298 | .uls-mobile .hide-for-portrait,
299 | .uls-mobile .show-for-landscape {
300 | display: none !important;
301 | }
302 | }
303 |
304 | /* Touch-enabled device targeting */
305 | .uls-mobile .show-for-touch {
306 | display: none !important;
307 | }
308 |
309 | .uls-mobile .hide-for-touch {
310 | display: block !important;
311 | }
312 |
313 | .uls-mobile .touch .show-for-touch {
314 | display: block !important;
315 | }
316 |
317 | .uls-mobile .touch .hide-for-touch {
318 | display: none !important;
319 | }
320 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ${title}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | This page requires JavaScript
74 |
75 |
76 |
This page only works with JavaScript enabled.
77 |
If you have JavaScript disabled with a plugin like NoScript, please
78 | disable that plugin and reload the page. If you trust us, you
79 | might find it convenient to enable JavaScript just
80 | for this domain.
81 |
If you are opposed to JavaScript in principle, you're not left out!
82 | You can read the page source to get at all the data.
83 |
84 |
85 |
86 |
87 | <%def name="card(node, next, segue1=None, segue2=None, toplevel=False)">
88 |
89 |
90 | % if segue1:
91 |
${segue1}
92 | % endif
93 |
94 | % if segue2:
95 |
${segue2}
96 | % endif
97 |
98 |
99 |
100 | % if 'title' in node:
101 | ${node['title']}
102 | % endif
103 |
104 | % if 'subtitle' in node:
105 | ${node['subtitle']}
106 | % endif
107 |
108 | % if 'image' in node:
109 |
110 | % endif
111 |
112 | % if 'children' in node:
113 |
114 | ${node['affirmative']}
115 |
116 | % else:
117 |
118 | ${node['affirmative']}
119 |
120 | % endif:
121 |
122 | % if next != node['id']:
123 |
124 | ${node['negative']}
125 |
126 | % endif
127 | % if not toplevel:
128 |
129 | ${node['backlink']}
130 |
131 | % endif
132 |
133 |
134 | % if 'children' in node:
135 | % for i, child in enumerate(node['children']):
136 | ${card(child, node['children'][(i + 1) % len(node['children'])]['id'], segue1=node.get('segue1'), segue2=node.get('segue2'))}
137 | % endfor
138 | % endif
139 | %def>
140 |
141 | % for i, child in enumerate(tree['children']):
142 | ${card(child, tree['children'][(i + 1) % len(tree['children'])]['id'], segue1=tree.get('segue1'), segue2=tree.get('segue2'), toplevel=True)}
143 | % endfor
144 |
145 |
146 |
147 |
148 |
149 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/asknot_lib.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """ Utilities module used by the asknot-ng.py script. """
3 |
4 | import hashlib
5 | import os
6 | import random
7 | import subprocess as sp
8 | import sys
9 |
10 | import mako.template
11 | import pkg_resources
12 | import yaml
13 |
14 | # Lists of translatable strings so we know what to extract at extraction time
15 | # and so we know what to translate at render time.
16 | translatable_collections = ['negatives', 'affirmatives', 'backlinks']
17 | translatable_fields = ['title', 'description', 'segue1', 'segue2', 'subtitle']
18 |
19 | if sys.version_info[0] == 2:
20 | string_types = (basestring,)
21 | else:
22 | string_types = (str, bytes,)
23 |
24 |
25 | def asknot_version():
26 | try:
27 | return pkg_resources.get_distribution('asknot-ng').version
28 | except pkg_resources.DistributionNotFound:
29 | try:
30 | stdout = sp.check_output(['git', 'rev-parse', 'HEAD'])
31 | return stdout[:8] # Short hash
32 | except:
33 | return 'unknown'
34 |
35 |
36 | defaults = {
37 | 'title': 'asknot-ng',
38 | 'author': 'Ralph Bean',
39 | 'description': (
40 | 'Ask not what $ORG can do for you, '
41 | 'but what you can do for $ORG'
42 | ),
43 | 'asknot_version': asknot_version(),
44 | 'favicon': 'whatever',
45 | 'googlesiteverification': 'n/a',
46 | 'navlinks': [],
47 | 'negatives': ['No, thanks'],
48 | 'affirmatives': ['Yes, please'],
49 | 'backlinks': ['I was wrong, take me back'],
50 | 'SEP': '#', # Make this '/' for cool prod environments
51 | }
52 |
53 |
54 | def load_yaml(filename):
55 | """ Simply load our yaml file from disk. """
56 | with open(filename, 'r') as f:
57 | data = yaml.load(f.read(), Loader=yaml.BaseLoader)
58 |
59 | basedir = os.path.dirname(filename)
60 |
61 | try:
62 | validate_yaml(data, basedir)
63 | except:
64 | print("Problem with %r due to..." % filename)
65 | raise
66 |
67 | return data
68 |
69 |
70 | def validate_yaml(data, basedir):
71 | """ Sanity check used to make sure the root question file is valid. """
72 | assert 'tree' in data
73 | assert 'children' in data['tree']
74 | validate_tree(data['tree'], basedir)
75 |
76 |
77 | def validate_tree(node, basedir):
78 | """ Sanity check used to make sure the question tree is valid. """
79 | if not 'children' in node:
80 | if not 'link' in node:
81 | raise ValueError('%r must have either a "href" value or '
82 | 'a "children" list' % node)
83 | else:
84 | # Handle recursive includes in yaml files. The children of a node
85 | # may be defined in a separate file
86 | if isinstance(node['children'], string_types):
87 | include_file = node['children']
88 | if not os.path.isabs(include_file):
89 | include_file = os.path.join(basedir, include_file)
90 |
91 | node['children'] = load_yaml(include_file)['tree']['children']
92 |
93 | # Finally, validate all the children whether they are from a separately
94 | # included file, or not.
95 | for child in node['children']:
96 | validate_tree(child, basedir)
97 |
98 |
99 | def slugify(title, seen):
100 | """ Return a unique id for a node given its title. """
101 | idx = title.lower()
102 | replacements = {
103 | ' ': '-',
104 | '+': 'plus',
105 | '!': 'exclamation',
106 | ',': 'comma',
107 | '\'': 'apostrophe',
108 | }
109 | for left, right in replacements.items():
110 | idx = idx.replace(left, right)
111 | while idx in seen:
112 | idx = idx + hashlib.md5(idx.encode('utf-8')).hexdigest()[0]
113 | return idx
114 |
115 |
116 | def prepare_tree(data, node, parent=None, seen=None, _=lambda x: x):
117 | """ Utility method for "enhancing" the data in the question tree.
118 |
119 | This is called typically before rendering the mako template with data.
120 |
121 | A few things happen here:
122 | - Translatable strings are marked up so they can be translated.
123 | - Unique ids are assigned to each node in the tree for use by JS.
124 | - Texts for 'yes', 'no', and 'go back' are assigned at random per node.
125 | - For each node that doesn't have an image defined, propagate the image
126 | defined by its parent node.
127 |
128 | """
129 |
130 | # Markup strings for translation
131 | if node is data.get('tree'):
132 | for collection in translatable_collections:
133 | if collection in data:
134 | data[collection] = [_(s) for s in data[collection]]
135 |
136 | for field in translatable_fields:
137 | if field in node:
138 | node[field] = _(node[field])
139 |
140 | # Assign a unique id to this node.
141 | seen = seen or []
142 | node['id'] = slugify(node.get('title', 'foo'), seen)
143 | seen.append(node['id'])
144 |
145 | # Choose random text for our navigation buttons for this node.
146 | node['affirmative'] = random.choice(data['affirmatives'])
147 | node['negative'] = random.choice(data['negatives'])
148 | node['backlink'] = random.choice(data['backlinks'])
149 |
150 | # Propagate parent images to children unless otherwise specified.
151 | if parent and not 'image' in node and 'image' in parent:
152 | node['image'] = parent['image']
153 |
154 | # Recursively apply this logic to all children of this node.
155 | for i, child in enumerate(node.get('children', [])):
156 | node['children'][i] = prepare_tree(data, child, parent=node, seen=seen, _=_)
157 |
158 | return node
159 |
160 |
161 | def gather_ids(node):
162 | """ Yields all the unique ids in the question tree recursively. """
163 | yield node['id']
164 | for child in node.get('children', []):
165 | for idx in gather_ids(child):
166 | yield idx
167 |
168 |
169 | def produce_graph(tree, dot=None):
170 | """ Given a question tree, returns a pygraphviz object
171 | for later rendering.
172 | """
173 | import pygraphviz
174 | dot = dot or pygraphviz.AGraph(directed=True)
175 |
176 | idx = tree.get('id', 'root')
177 | dot.add_node(idx, label=tree.get('title', 'Root'))
178 |
179 | for child in tree.get('children', []):
180 | dot = produce_graph(child, dot)
181 | dot.add_edge(idx, child['id'])
182 |
183 | return dot
184 |
185 |
186 | def load_template(filename):
187 | """ Load a mako template and return it for later rendering. """
188 | return mako.template.Template(
189 | filename=filename,
190 | strict_undefined=True,
191 | output_encoding='utf-8',
192 | )
193 |
194 |
195 | def translatable_strings(data):
196 | """ A generator that yields tuples containing translatable strings from a
197 | question tree.
198 |
199 | The yielded tuples are of the form (linenumber, string, comment).
200 | """
201 | for key in translatable_fields:
202 | if key in data:
203 | yield data['__line__'], data[key], key
204 |
205 | for key in translatable_collections:
206 | if key in data:
207 | for string in data[key]:
208 | yield data['__line__'], string, key[:-1]
209 |
210 | for item in data.get('navlinks', []):
211 | yield data['__line__'], item['name'], 'navlink'
212 |
213 | if 'tree' in data:
214 | for items in translatable_strings(data['tree']):
215 | yield items
216 |
217 | children = data.get('children', [])
218 | if isinstance(children, str):
219 | pass
220 | else:
221 | for child in children:
222 | for items in translatable_strings(child):
223 | yield items
224 |
225 |
226 | def load_yaml_with_linenumbers(fileobj):
227 | """ Return yaml with line numbers included in the dict.
228 |
229 | This is similar to our mundane ``load_yaml`` function, except that it
230 | modifies the yaml loader to include line numbers in the data. Our babel
231 | extension which is used to extract translatable strings from our yaml files
232 | uses those line numbers to make things easier on translators.
233 | """
234 | loader = yaml.Loader(fileobj.read())
235 |
236 | def compose_node(parent, index):
237 | # the line number where the previous token has ended (plus empty lines)
238 | line = loader.line
239 | node = yaml.composer.Composer.compose_node(loader, parent, index)
240 | node.__line__ = line + 1
241 | return node
242 |
243 | def construct_mapping(node, deep=False):
244 | constructor = yaml.constructor.Constructor.construct_mapping
245 | mapping = constructor(loader, node, deep=deep)
246 | mapping['__line__'] = node.__line__
247 | return mapping
248 |
249 | loader.compose_node = compose_node
250 | loader.construct_mapping = construct_mapping
251 | return loader.get_single_data()
252 |
253 |
254 | def extract(fileobj, keywords, comment_tags, options):
255 | """ Babel entry-point for extracting translatable strings from our yaml.
256 |
257 | This gets called by 'python setup.py extract_messages' when it encounters a
258 | yaml file. (See setup.py for where we declare the existence of this
259 | function for bable using setuptools 'entry-points').
260 | """
261 | data = load_yaml_with_linenumbers(fileobj)
262 |
263 | for lineno, string, comment in translatable_strings(data):
264 | yield lineno, None, [string], [comment]
265 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.languagefilter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery language filter plugin.
3 | *
4 | * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
5 | * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
6 | * contributors. See CREDITS for a list.
7 | *
8 | * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
9 | * have to do anything special to choose one license or the other and you don't
10 | * have to notify anyone which license you are using. You are free to use
11 | * UniversalLanguageSelector in commercial projects as long as the copyright
12 | * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
13 | *
14 | * @file
15 | * @ingroup Extensions
16 | * @licence GNU General Public Licence 2.0 or later
17 | * @licence MIT License
18 | */
19 |
20 | /**
21 | * Usage: $( 'inputbox' ).languagefilter();
22 | * The values for autocompletion is from the options.languages.
23 | * The data is in the format of languagecode:languagename.
24 | */
25 | (function ( $ ) {
26 | 'use strict';
27 |
28 | var LanguageFilter, delay;
29 |
30 | LanguageFilter = function( element, options ) {
31 | this.$element = $( element );
32 | this.options = $.extend( {}, $.fn.regionselector.defaults, options );
33 | this.$element.addClass( 'languagefilter' );
34 | this.resultCount = 0;
35 | this.$suggestion = this.$element.parents().find( '#' + this.$element.data( 'suggestion' ) );
36 | this.$clear = this.$element.parents().find( '#' + this.$element.data( 'clear' ) );
37 | this.selectedLanguage = null;
38 |
39 | this.listen();
40 | };
41 |
42 | delay = ( function() {
43 | var timer = 0;
44 |
45 | return function( callback, milliseconds ) {
46 | clearTimeout( timer );
47 | timer = setTimeout( callback, milliseconds );
48 | };
49 | } () );
50 |
51 | LanguageFilter.prototype = {
52 | listen: function() {
53 | this.$element.on( 'keypress', $.proxy( this.keyup, this ) )
54 | .on( 'keyup', $.proxy( this.keyup, this ) );
55 |
56 | if ( this.eventSupported( 'keydown' ) ) {
57 | this.$element.on( 'keydown', $.proxy( this.keyup, this ) );
58 | }
59 |
60 | if ( this.$clear.length ) {
61 | this.$clear.on( 'click' , $.proxy( this.clear, this ) );
62 | }
63 |
64 | this.toggleClear();
65 | },
66 |
67 | keyup: function( e ) {
68 | var suggestion, query, languageFilter;
69 |
70 | switch( e.keyCode ) {
71 | case 9: // Tab -> Autocomplete
72 | suggestion = this.$suggestion.val();
73 |
74 | if ( suggestion && suggestion !== this.$element.val() ) {
75 | this.$element.val( suggestion );
76 | e.preventDefault();
77 | e.stopPropagation();
78 | }
79 | break;
80 | case 13: // Enter
81 | if ( !this.options.onSelect ) {
82 | break;
83 | }
84 |
85 | // Avoid bubbling this 'enter' to background page elements
86 | e.preventDefault();
87 | e.stopPropagation();
88 |
89 | query = $.trim( this.$element.val() ).toLowerCase();
90 |
91 | if ( this.selectedLanguage ) {
92 | // this.selectLanguage will be populated from a matching search
93 | this.options.onSelect( this.selectedLanguage );
94 | } else if ( this.options.languages[query] ) {
95 | // Search is yet to happen (in timeout delay),
96 | // but we have a matching language code.
97 | this.options.onSelect( query );
98 | }
99 |
100 | break;
101 | default:
102 | languageFilter = this;
103 |
104 | if ( e.which < 32 &&
105 | e.which !== 8 // Backspace
106 | ) {
107 | // ignore any ASCII control characters
108 | break;
109 | }
110 |
111 | this.selectedLanguage = null;
112 |
113 | delay( function() {
114 | if ( !languageFilter.$element.val() ) {
115 | languageFilter.clear();
116 | } else {
117 | languageFilter.options.$target.empty();
118 | languageFilter.search();
119 | }
120 | }, 300 );
121 |
122 | this.toggleClear();
123 | }
124 | },
125 |
126 | /**
127 | * Clears the current search removing
128 | * clear buttons and suggestions.
129 | */
130 | deactivate: function() {
131 | this.$element.val( '' );
132 |
133 | if ( !$.fn.uls.Constructor.prototype.isMobile() ) {
134 | this.$element.focus();
135 | }
136 |
137 | this.toggleClear();
138 | this.autofill();
139 | },
140 |
141 | /**
142 | * Clears the search and shows all languages
143 | */
144 | clear: function() {
145 | this.deactivate();
146 | this.$element.trigger( 'searchclear.uls' );
147 | },
148 |
149 | /**
150 | * Toggles the visibility of clear icon depending
151 | * on whether there is anything to clear.
152 | */
153 | toggleClear: function() {
154 | if ( !this.$clear.length ) {
155 | return;
156 | }
157 |
158 | if ( this.$element.val() ) {
159 | this.$clear.show();
160 | } else {
161 | this.$clear.hide();
162 | }
163 | },
164 |
165 | search: function() {
166 | var languagesInScript,
167 | query = $.trim( this.$element.val() ),
168 | languages = $.uls.data.getLanguagesByScriptGroup( this.options.languages ),
169 | scriptGroup, langNum, langCode;
170 |
171 | this.resultCount = 0;
172 |
173 | for ( scriptGroup in languages ) {
174 | languagesInScript = languages[scriptGroup];
175 |
176 | languagesInScript.sort( $.uls.data.sortByAutonym );
177 |
178 | for ( langNum = 0; langNum < languagesInScript.length; langNum++ ) {
179 | langCode = languagesInScript[langNum];
180 |
181 | if ( query === '' || this.filter( langCode, query ) ) {
182 | if ( this.resultCount === 0 ) {
183 | // Autofill the first result.
184 | this.autofill( langCode );
185 | }
186 |
187 | if ( query.toLowerCase() === langCode ) {
188 | this.selectedLanguage = langCode;
189 | }
190 |
191 | if ( this.render( langCode ) ) {
192 | this.resultCount++;
193 | }
194 | }
195 | }
196 | }
197 |
198 | // Also do a search by search API
199 | if( !this.resultCount && this.options.searchAPI && query ) {
200 | this.searchAPI( query );
201 | } else {
202 | this.resultHandler( query );
203 | }
204 | },
205 |
206 | searchAPI: function( query ) {
207 | var languageFilter = this;
208 |
209 | $.get( languageFilter.options.searchAPI, { search: query }, function( result ) {
210 | $.each( result.languagesearch, function( code, name ) {
211 | if ( languageFilter.resultCount === 0 ) {
212 | // Autofill the first result.
213 | languageFilter.autofill( code, name );
214 | }
215 |
216 | if ( languageFilter.render( code ) ) {
217 | languageFilter.resultCount++;
218 | }
219 | } );
220 |
221 | languageFilter.resultHandler( query );
222 | } );
223 | },
224 |
225 | /**
226 | * Handler method to be called once search is over.
227 | * Based on search result triggers resultsfound or noresults events
228 | * @param query string
229 | */
230 | resultHandler: function( query ) {
231 | if ( this.resultCount === 0 ) {
232 | this.$suggestion.val( '' );
233 | this.$element.trigger( 'noresults.uls', query );
234 | } else {
235 | this.$element.trigger( 'resultsfound.uls', [query, this.resultCount] );
236 | }
237 | },
238 |
239 | autofill: function( langCode, languageName ) {
240 | if ( !this.$suggestion.length ) {
241 | return;
242 | }
243 |
244 | if ( !this.$element.val() ) {
245 | this.$suggestion.val( '' );
246 | return;
247 | }
248 |
249 | this.selectedLanguage = langCode;
250 | languageName = languageName || this.options.languages[langCode];
251 |
252 | if ( !languageName ) {
253 | return;
254 | }
255 |
256 | var autonym,
257 | userInput = this.$element.val(),
258 | suggestion = userInput + languageName.substring( userInput.length, languageName.length );
259 |
260 | if ( suggestion.toLowerCase() !== languageName.toLowerCase() ) {
261 | // see if it was autonym match
262 | autonym = $.uls.data.getAutonym( langCode ) || '';
263 | suggestion = userInput + autonym.substring( userInput.length, autonym.length );
264 |
265 | if ( suggestion !== autonym ) {
266 | // Give up. It may be an ISO/script code match.
267 | suggestion = '';
268 | }
269 | }
270 |
271 | // Make sure that it is a visual prefix.
272 | if ( !isVisualPrefix( userInput, suggestion ) ) {
273 | suggestion = '';
274 | }
275 |
276 | this.$suggestion.val( suggestion );
277 | },
278 |
279 | render: function( langCode ) {
280 | var $target = this.options.$target;
281 |
282 | if ( !$target ) {
283 | return false;
284 | }
285 |
286 | return $target.append( langCode );
287 | },
288 |
289 | escapeRegex: function( value ) {
290 | return value.replace( /[\-\[\]{}()*+?.,\\\^$\|#\s]/g, '\\$&' );
291 | },
292 |
293 | /**
294 | * A search match happens if any of the following passes:
295 | * a) Language name in current user interface language
296 | * 'starts with' search string.
297 | * b) Language autonym 'starts with' search string.
298 | * c) ISO 639 code match with search string.
299 | * d) ISO 15924 code for the script match the search string.
300 | */
301 | filter: function( langCode, searchTerm ) {
302 | // FIXME script is ISO 15924 code. We might need actual name of script.
303 | var matcher = new RegExp( '^' + this.escapeRegex( searchTerm ), 'i' ),
304 | languageName = this.options.languages[langCode];
305 |
306 | return matcher.test( languageName ) ||
307 | matcher.test( $.uls.data.getAutonym( langCode ) ) ||
308 | matcher.test( langCode ) ||
309 | matcher.test( $.uls.data.getScript( langCode ) );
310 | },
311 |
312 | eventSupported: function ( eventName ) {
313 | var isSupported = eventName in this.$element;
314 |
315 | if ( !isSupported ) {
316 | this.$element.setAttribute( eventName, 'return;' );
317 | isSupported = typeof this.$element[eventName] === 'function';
318 | }
319 |
320 | return isSupported;
321 | }
322 | };
323 |
324 | $.fn.languagefilter = function( option ) {
325 | return this.each( function() {
326 | var $this = $( this ),
327 | data = $this.data( 'languagefilter' ),
328 | options = typeof option === 'object' && option;
329 |
330 | if ( !data ) {
331 | $this.data( 'languagefilter', ( data = new LanguageFilter( this, options ) ) );
332 | }
333 |
334 | if ( typeof option === 'string' ) {
335 | data[option]();
336 | }
337 | } );
338 | };
339 |
340 | $.fn.languagefilter.defaults = {
341 | $target: null, // Where to append the results
342 | searchAPI: null,
343 | languages: null, // Languages as code:name format.
344 | onSelect: null // Language select handler - like enter in filter textbox.
345 | };
346 |
347 | $.fn.languagefilter.Constructor = LanguageFilter;
348 |
349 | /**
350 | * Check if a prefix is visually prefix of a string
351 | * @param prefix string
352 | * @param string string
353 | */
354 | function isVisualPrefix( prefix, string ) {
355 | // Pre-base vowel signs of Indic languages. A vowel sign is called pre-base if
356 | // consonant + vowel becomes [vowel][consonant] when rendered. Eg: ക + െ => കെ
357 | var prebases = 'െേൈൊോൌெேைொோௌେୈୋୌિਿिিেৈোৌෙේෛොෝෞ';
358 | return prebases.indexOf( string[prefix.length] ) <= 0;
359 | }
360 | } ( jQuery ) );
361 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.lcd.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Universal Language Selector
3 | * Language category display component - Used for showing the search results,
4 | * grouped by regions, scripts
5 | *
6 | * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
7 | * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
8 | * contributors. See CREDITS for a list.
9 | *
10 | * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
11 | * have to do anything special to choose one license or the other and you don't
12 | * have to notify anyone which license you are using. You are free to use
13 | * UniversalLanguageSelector in commercial projects as long as the copyright
14 | * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
15 | *
16 | * @file
17 | * @ingroup Extensions
18 | * @licence GNU General Public Licence 2.0 or later
19 | * @licence MIT License
20 | */
21 |
22 | ( function ( $ ) {
23 | 'use strict';
24 |
25 | var noResultsTemplate, LanguageCategoryDisplay;
26 |
27 | /*jshint multistr:true */
28 | noResultsTemplate = '\
29 |
\
30 | No results found\
31 | \
32 |
\
48 |
';
49 | /*jshint multistr:false */
50 |
51 | LanguageCategoryDisplay = function ( element, options ) {
52 | this.$element = $( element );
53 | this.options = $.extend( {}, $.fn.lcd.defaults, options );
54 | this.$element.addClass( 'lcd' );
55 | this.regionLanguages = {};
56 | this.renderTimeout = null;
57 | this.cachedQuicklist = null;
58 |
59 | this.$element.append( $( noResultsTemplate ) );
60 | this.$noResults = this.$element.children( '.uls-no-results-view' );
61 |
62 | this.render();
63 | this.listen();
64 | };
65 |
66 | LanguageCategoryDisplay.prototype = {
67 | constructor: LanguageCategoryDisplay,
68 |
69 | /**
70 | * Adds language to the language list.
71 | * @param {string} langCode
72 | * @param {string} [regionCode]
73 | * @return {bool} Whether the language was added.
74 | */
75 | append: function ( langCode, regionCode ) {
76 | var lcd = this, i, regions;
77 |
78 | if ( !this.options.languages[langCode] ) {
79 | // Language is unknown or not in the list of languages for this context.
80 | return false;
81 | }
82 |
83 | if ( regionCode ) {
84 | regions = [regionCode];
85 | } else {
86 | regions = $.uls.data.getRegions( langCode );
87 | }
88 |
89 | // Worldwides only displayed once
90 | if ( $.inArray( 'WW', regions ) > -1 ) {
91 | regions = ['WW'];
92 | }
93 |
94 | for ( i = 0; i < regions.length; i++ ) {
95 | this.regionLanguages[regions[i]].push( langCode );
96 | }
97 |
98 | // Work around the bad interface, delay rendering until we have got
99 | // all the languages to speed up performance.
100 | window.clearTimeout( this.renderTimeout );
101 | this.renderTimeout = window.setTimeout( function () {
102 | lcd.renderRegions();
103 | }, 50 );
104 |
105 | return true;
106 | },
107 |
108 | render: function () {
109 | var $section,
110 | lcd = this,
111 | regions = [],
112 | regionNames = {
113 | // These are fallback text when i18n library not present
114 | WW: 'Worldwide',
115 | SP: 'Special',
116 | AM: 'America',
117 | EU: 'Europe',
118 | ME: 'Middle East',
119 | AS: 'Asia',
120 | AF: 'Africa',
121 | PA: 'Pacific'
122 | };
123 |
124 | regions.push( this.buildQuicklist() );
125 |
126 | $.each( $.uls.data.regiongroups, function ( regionCode ) {
127 | lcd.regionLanguages[regionCode] = [];
128 | // Don't show the region unless it was enabled
129 | if ( $.inArray( regionCode, lcd.options.showRegions ) === -1 ) {
130 | return;
131 | }
132 |
133 | $section = $( '' )
134 | .addClass( 'eleven columns offset-by-one uls-lcd-region-section hide' )
135 | .attr( 'id', regionCode )
136 | .append(
137 | $( '
' )
138 | .attr( 'data-i18n', 'uls-region-' + regionCode )
139 | .addClass( 'eleven columns uls-lcd-region-title' )
140 | .text( regionNames[regionCode] )
141 | );
142 |
143 | regions.push( $section );
144 | } );
145 |
146 | lcd.$element.append( regions );
147 |
148 | this.i18n();
149 | },
150 |
151 | /**
152 | * Renders a region and displays it if it has content.
153 | */
154 | renderRegions: function () {
155 | var lcd = this, languages,
156 | items = lcd.options.itemsPerColumn,
157 | columns = 4;
158 |
159 | this.$noResults.addClass( 'hide' );
160 | this.$element.find( '.uls-lcd-region-section' ).each( function () {
161 | var $region = $( this ),
162 | regionCode = $region.attr( 'id' );
163 |
164 | if ( $region.is( '#uls-lcd-quicklist' ) ) {
165 | return;
166 | }
167 |
168 | $region.children( '.uls-language-block' ).remove();
169 |
170 | languages = lcd.regionLanguages[regionCode];
171 | if ( !languages || languages.length === 0 ) {
172 | $region.addClass( 'hide' );
173 | return;
174 | }
175 |
176 | lcd.renderRegion( $region, languages, items, columns );
177 | $region.removeClass( 'hide' );
178 |
179 | lcd.regionLanguages[regionCode] = [];
180 | } );
181 |
182 | },
183 |
184 | /**
185 | * Adds given languages sorted into rows and columns into given element.
186 | * @param {jQuery} $region Element to add language list.
187 | * @param {array} languages List of language codes.
188 | * @param {number} itemsPerColumn How many languages fit in a column.
189 | * @param {number} columnsPerRow How many columns fit in a row.
190 | */
191 | renderRegion: function( $region, languages, itemsPerColumn, columnsPerRow ) {
192 | var i, lastItem, currentScript, nextScript, force,
193 | len = languages.length,
194 | items = [],
195 | columns = [],
196 | rows = [];
197 |
198 | for ( i = 0; i < len; i++ ) {
199 | force = false;
200 | nextScript = $.uls.data.getScriptGroupOfLanguage( languages[i+1] );
201 |
202 | lastItem = len - i === 1;
203 | // Force column break if script changes and column has more than one row already
204 | if ( i === 0 ) {
205 | currentScript = $.uls.data.getScriptGroupOfLanguage( languages[i] );
206 | } else if ( currentScript !== nextScript && items.length > 1 ) {
207 | force = true;
208 | }
209 | currentScript = nextScript;
210 |
211 | items.push( this.renderItem( languages[i] ) );
212 |
213 | if ( items.length >= itemsPerColumn || lastItem || force ) {
214 | columns.push( $( '' ).addClass( 'three columns' ).append( items ) );
215 | items = [];
216 | if ( columns.length >= columnsPerRow || lastItem ) {
217 | rows.push( $( '' ).addClass( 'row uls-language-block' ).append( columns ) );
218 | columns = [];
219 | }
220 | }
221 | }
222 |
223 | $region.append( rows );
224 | },
225 |
226 | /**
227 | * Creates dom node representing one item in language list.
228 | * @param {string} code Language code
229 | * @return {Element}
230 | */
231 | renderItem: function( code ) {
232 | var a, name, autonym, li;
233 |
234 | name = this.options.languages[code];
235 | autonym = $.uls.data.getAutonym( code ) || name || code;
236 |
237 | // Not using jQuery as this is performance hotspot
238 | li = document.createElement( 'li' );
239 | li.title = name;
240 | li.lang = code;
241 | li.dir = $.uls.data.getDir( code );
242 | li.setAttribute( 'data-code', code );
243 |
244 | a = document.createElement( 'a' );
245 | a.appendChild( document.createTextNode( autonym ) );
246 | a.className = 'autonym';
247 |
248 | li.appendChild( a );
249 | if ( this.options.languageDecorator ) {
250 | this.options.languageDecorator( $( a ), code );
251 | }
252 | return li;
253 | },
254 |
255 | i18n: function ( ) {
256 | this.$element.find( '[data-i18n]' ).i18n();
257 | },
258 |
259 | /**
260 | * Adds quicklist as a region.
261 | */
262 | quicklist: function () {
263 | this.$element.find( '#uls-lcd-quicklist' ).removeClass( 'hide' );
264 | },
265 |
266 | buildQuicklist: function () {
267 | var quickList, $quickListSection, $quickListSectionTitle;
268 |
269 | if ( this.cachedQuicklist !== null ) {
270 | return this.cachedQuicklist;
271 | }
272 |
273 | if ( $.isFunction( this.options.quickList ) ) {
274 | this.options.quickList = this.options.quickList();
275 | }
276 |
277 | if ( !this.options.quickList ) {
278 | this.cachedQuicklist = $( [] );
279 | return this.cachedQuicklist;
280 | }
281 |
282 | // Pick only the first elements, because we don't have room for more
283 | quickList = this.options.quickList;
284 | quickList = quickList.slice( 0, 16 );
285 | quickList.sort( $.uls.data.sortByAutonym );
286 |
287 | $quickListSection = $( '
' )
288 | .addClass( 'eleven columns offset-by-one uls-lcd-region-section' )
289 | .attr( 'id', 'uls-lcd-quicklist' );
290 |
291 | $quickListSectionTitle = $( '
' )
292 | .attr( 'data-i18n', 'uls-common-languages' )
293 | .addClass( 'eleven columns uls-lcd-region-title' )
294 | .text( 'Common languages' ); // This is placeholder text if jquery.i18n not present
295 | $quickListSection.append( $quickListSectionTitle );
296 |
297 | this.renderRegion( $quickListSection, quickList, 4, 4 );
298 |
299 | $quickListSectionTitle.i18n();
300 |
301 | this.cachedQuicklist = $quickListSection;
302 | return this.cachedQuicklist;
303 | },
304 |
305 | show: function () {
306 | if ( !this.regionDivs ) {
307 | this.render();
308 | }
309 | },
310 |
311 | empty: function () {
312 | this.$element.find( '#uls-lcd-quicklist' ).addClass( 'hide' );
313 | },
314 |
315 | focus: function () {
316 | this.$element.focus();
317 | },
318 |
319 | noResults: function () {
320 | this.$noResults.removeClass( 'hide' );
321 | if ( this.$noResults.find( '.uls-lcd-region-title' ).length ) {
322 | return;
323 | }
324 |
325 | var $suggestions = this.buildQuicklist().clone();
326 | $suggestions.find( 'h3' )
327 | .data( 'i18n', 'uls-no-results-suggestion-title' )
328 | .text( 'You may be interested in:' )
329 | .i18n();
330 | this.$noResults.find( 'h2' ).after( $suggestions );
331 | },
332 |
333 | listen: function () {
334 | var lcd = this;
335 |
336 | if ( this.options.clickhandler ) {
337 | this.$element.on( 'click', '.row li', function () {
338 | lcd.options.clickhandler.call( this, $( this ).data( 'code' ) );
339 | } );
340 | }
341 |
342 | // The region section need to be in sync with the map filter.
343 | lcd.$element.scroll( function () {
344 | var inview, inviewRegion,
345 | $ulsLanguageList = $( this ),
346 | scrollTop = $ulsLanguageList.position().top,
347 | scrollBottom = $ulsLanguageList.height();
348 |
349 | // The region section need to be in sync with the map filter.
350 | inviewRegion = 'WW';
351 | lcd.$element.find( '.uls-lcd-region-section' ).each( function () {
352 | var $lcdRegionSection = $( this ),
353 | top = $lcdRegionSection.position().top,
354 | height = $lcdRegionSection.height(),
355 | padding = 10;
356 |
357 | if ( top - padding <= scrollTop && height > scrollBottom ) {
358 | inviewRegion = $lcdRegionSection.attr( 'id' );
359 | }
360 | } );
361 |
362 | // highlight the region visible while scrolling in the map.
363 | inview = $.uls.data.regiongroups[inviewRegion];
364 | if ( !$( '#uls-region-' + inview ).hasClass( 'active' ) ) {
365 | $( '.regionselector' ).removeClass( 'active' );
366 | $( '#uls-region-' + inview ).addClass( 'active' );
367 | }
368 | } );
369 | }
370 | };
371 |
372 | $.fn.lcd = function ( option ) {
373 | return this.each( function () {
374 | var $this = $( this ),
375 | data = $this.data( 'lcd' ),
376 | options = typeof option === 'object' && option;
377 |
378 | if ( !data ) {
379 | $this.data( 'lcd', ( data = new LanguageCategoryDisplay( this, options ) ) );
380 | }
381 |
382 | if ( typeof option === 'string') {
383 | data[option]();
384 | }
385 | } );
386 | };
387 |
388 | $.fn.lcd.defaults = {
389 | languages: null,
390 | showRegions: ['WW', 'AM', 'EU', 'ME', 'AF', 'AS', 'PA'],
391 | itemsPerColumn: 8,
392 | languageDecorator: null
393 | };
394 |
395 | $.fn.lcd.Constructor = LanguageCategoryDisplay;
396 | } ( jQuery ) );
397 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.core.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Universal Language Selector
3 | * ULS core component.
4 | *
5 | * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
6 | * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
7 | * contributors. See CREDITS for a list.
8 | *
9 | * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
10 | * have to do anything special to choose one license or the other and you don't
11 | * have to notify anyone which license you are using. You are free to use
12 | * UniversalLanguageSelector in commercial projects as long as the copyright
13 | * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
14 | *
15 | * @file
16 | * @ingroup Extensions
17 | * @licence GNU General Public Licence 2.0 or later
18 | * @licence MIT License
19 | */
20 |
21 | ( function ( $ ) {
22 | 'use strict';
23 |
24 | var template, ULS;
25 |
26 | // Region numbers in id attributes also appear in the langdb.
27 | /*jshint multistr:true */
28 | template = '';
79 | /*jshint multistr:false */
80 |
81 | /**
82 | * ULS Public class definition
83 | */
84 | ULS = function ( element, options ) {
85 | this.$element = $( element );
86 | this.options = $.extend( {}, $.fn.uls.defaults, options );
87 | this.$menu = $( template );
88 | this.languages = this.options.languages;
89 |
90 | for ( var code in this.languages ) {
91 | if ( $.uls.data.languages[code] === undefined ) {
92 | // Language is unknown to ULS.
93 | delete this.languages[code];
94 | }
95 | }
96 |
97 | this.left = this.options.left;
98 | this.top = this.options.top;
99 | this.shown = false;
100 | this.initialized = false;
101 |
102 | this.$languageFilter = this.$menu.find( '#uls-languagefilter' );
103 | this.$regionFilters = this.$menu.find( '.uls-region' );
104 | this.$resultsView = this.$menu.find( 'div.uls-language-list' );
105 |
106 | this.render();
107 | this.listen();
108 | this.ready();
109 | };
110 |
111 | ULS.prototype = {
112 | constructor: ULS,
113 |
114 | /**
115 | * A "hook" that runs after the ULS constructor.
116 | * At this point it is not guaranteed that the ULS has its dimensions
117 | * and that the languages lists are initialized.
118 | *
119 | * To use it, pass a function as the onReady parameter
120 | * in the options when initializing ULS.
121 | */
122 | ready: function () {
123 | if ( this.options.onReady ) {
124 | this.options.onReady.call( this );
125 | }
126 | },
127 |
128 | /**
129 | * A "hook" that runs after the ULS panel becomes visible
130 | * by using the show method.
131 | *
132 | * To use it, pass a function as the onVisible parameter
133 | * in the options when initializing ULS.
134 | */
135 | visible: function () {
136 | if ( this.options.onVisible ) {
137 | this.options.onVisible.call( this );
138 | }
139 | },
140 |
141 | /**
142 | * Calculate the position of ULS
143 | * Returns an object with top and left properties.
144 | * @returns {Object}
145 | * position is set by setting also window height and margin
146 | */
147 | position: function () {
148 | var pos = $.extend( {}, this.$element.offset(), {
149 | height: this.$element[0].offsetHeight
150 | } );
151 | return {
152 | top: this.top !== undefined ? this.top : pos.top - (447+10),
153 | left: this.left !== undefined ? this.left : '25%'
154 | };
155 | },
156 |
157 | /**
158 | * Show the ULS window
159 | */
160 | show: function () {
161 | this.$menu.css( this.position() );
162 |
163 | if ( this.options.compact ) {
164 | this.$menu.addClass( 'uls-compact' );
165 | }
166 |
167 | if ( !this.initialized ) {
168 | $( 'body' ).prepend( this.$menu );
169 | this.i18n();
170 |
171 | // Initialize with a full search.
172 | // This happens on first time click of uls trigger.
173 | this.defaultSearch();
174 |
175 | this.initialized = true;
176 | }
177 |
178 | // hide any other visible ULS
179 | $( '.uls-menu' ).hide();
180 |
181 | this.$menu.show();
182 | this.$menu.scrollIntoView();
183 | this.shown = true;
184 |
185 | if ( !this.isMobile() ) {
186 | this.$languageFilter.focus();
187 | }
188 |
189 | this.visible();
190 | },
191 |
192 | i18n: function () {
193 | if ( $.i18n ) {
194 | this.$menu.find( '[data-i18n]' ).i18n();
195 | this.$languageFilter.prop( 'placeholder', $.i18n( 'uls-search-placeholder' ) );
196 | }
197 | },
198 |
199 | defaultSearch: function () {
200 | this.$resultsView.lcd( 'empty' );
201 |
202 | this.$regionFilters.regionselector( 'show' );
203 | },
204 |
205 | /**
206 | * Hide the ULS window
207 | */
208 | hide: function () {
209 | this.$menu.hide();
210 | this.shown = false;
211 | },
212 |
213 | /**
214 | * Render the UI elements.
215 | * Does nothing by default. Can be used for customization.
216 | */
217 | render: function () {
218 | // Rendering stuff here
219 | },
220 |
221 | /**
222 | * Callback for no results found context.
223 | */
224 | noresults: function () {
225 | $( '.regionselector' ).removeClass( 'active' );
226 | this.$resultsView.lcd( 'noResults' );
227 | },
228 |
229 | /**
230 | * callback for results found context.
231 | */
232 | success: function () {
233 | $( '.regionselector' ).removeClass( 'active' );
234 | this.$resultsView.show();
235 | },
236 |
237 | /**
238 | * Bind the UI elements with their event listeners
239 | */
240 | listen: function () {
241 | var lcd,
242 | uls = this;
243 |
244 | // Register all event listeners to the ULS here.
245 | this.$element.on( 'click', $.proxy( this.click, this ) );
246 |
247 | this.$languageFilter.on( 'searchclear.uls', $.proxy( this.defaultSearch, this ) );
248 | this.$languageFilter.on( 'noresults.uls', $.proxy( this.noresults, this ) );
249 | this.$languageFilter.on( 'resultsfound.uls', $.proxy( this.success, this ) );
250 |
251 | // Close when clicking on the close button
252 | this.$menu.find( '#uls-close' ).on( 'click', $.proxy( this.cancel, this ) );
253 | // Don't do anything if pressing on empty space in the ULS
254 | this.$menu.on( 'click', function ( e ) {
255 | e.stopPropagation();
256 | } );
257 |
258 | // Handle key press events on the menu
259 | this.$menu.on( 'keypress', $.proxy( this.keypress, this ) )
260 | .on( 'keyup', $.proxy( this.keyup, this ) );
261 |
262 | if ( this.eventSupported( 'keydown' ) ) {
263 | this.$menu.on( 'keydown', $.proxy( this.keypress, this ) );
264 | }
265 |
266 | lcd = this.$resultsView.lcd( {
267 | languages: this.languages,
268 | quickList: this.options.quickList,
269 | clickhandler: $.proxy( this.select, this ),
270 | source: this.$languageFilter,
271 | showRegions: this.options.showRegions,
272 | languageDecorator: this.options.languageDecorator
273 | } ).data( 'lcd' );
274 |
275 | this.$languageFilter.languagefilter( {
276 | $target: lcd,
277 | languages: this.languages,
278 | searchAPI: this.options.searchAPI,
279 | onSelect: $.proxy( this.select, this )
280 | } );
281 |
282 | // Create region selectors, one per region
283 | this.$menu.find( '.uls-region, .uls-region-link' ).regionselector( {
284 | $target: lcd,
285 | languages: this.languages,
286 | success: function ( regionfilter ) {
287 | // Deactivate search filtering
288 | uls.$languageFilter.languagefilter( 'deactivate' );
289 |
290 | // If it is the WW region, show the quicklist
291 | if ( regionfilter.regionGroup === 1 ) {
292 | lcd.quicklist();
293 | }
294 |
295 | // Show 'results view' if we are in no results mode
296 | uls.success();
297 | },
298 | noresults: function () {
299 | uls.$languageFilter.languagefilter( 'clear' );
300 | }
301 | } );
302 |
303 | $( 'html' ).click( $.proxy( this.cancel, this ) );
304 | },
305 |
306 | /**
307 | * On select handler for search results
308 | * @param langCode
309 | */
310 | select: function ( langCode ) {
311 | this.hide();
312 | this.$languageFilter.trigger( 'searchclear' );
313 | if ( this.options.onSelect ) {
314 | this.options.onSelect.call( this, langCode );
315 | }
316 | },
317 |
318 | /**
319 | * On cancel handler for the uls menu
320 | */
321 | cancel: function () {
322 | this.hide();
323 |
324 | if ( this.options.onCancel ) {
325 | this.options.onCancel.call( this );
326 | }
327 | },
328 |
329 | keyup: function ( e ) {
330 | if ( !this.shown ) {
331 | return;
332 | }
333 |
334 | if ( e.keyCode === 27 ) { // escape
335 | this.cancel();
336 | e.preventDefault();
337 | e.stopPropagation();
338 | }
339 | },
340 |
341 | keypress: function ( e ) {
342 | if ( !this.shown ) {
343 | return;
344 | }
345 |
346 | if ( e.keyCode === 27 ) { // escape
347 | this.cancel();
348 | e.preventDefault();
349 | e.stopPropagation();
350 | }
351 | },
352 |
353 | click: function ( e ) {
354 | e.stopPropagation();
355 | e.preventDefault();
356 |
357 | if ( this.shown ) {
358 | this.hide();
359 | } else {
360 | this.show();
361 | }
362 | },
363 |
364 | eventSupported: function ( eventName ) {
365 | var isSupported = eventName in this.$menu;
366 |
367 | if ( !isSupported ) {
368 | this.$element.setAttribute( eventName, 'return;' );
369 | isSupported = typeof this.$element[eventName] === 'function';
370 | }
371 |
372 | return isSupported;
373 | },
374 |
375 | isMobile: function () {
376 | return navigator.userAgent.match( /(iPhone|iPod|iPad|Android|BlackBerry)/ );
377 | }
378 | };
379 |
380 | /* ULS PLUGIN DEFINITION
381 | * =========================== */
382 |
383 | $.fn.uls = function ( option ) {
384 | return this.each( function () {
385 | var $this = $( this ),
386 | data = $this.data( 'uls' ),
387 | options = typeof option === 'object' && option;
388 |
389 | if ( !data ) {
390 | $this.data( 'uls', ( data = new ULS( this, options ) ) );
391 | }
392 |
393 | if ( typeof option === 'string' ) {
394 | data[option]();
395 | }
396 | } );
397 | };
398 |
399 | $.fn.uls.defaults = {
400 | onSelect: null, // Callback function to be called when a language is selected
401 | searchAPI: null, // Language search API
402 | languages: $.uls.data.getAutonyms(), // Languages to be used for ULS, default is all languages
403 | quickList: null, // Array of language codes or function that returns such
404 | compact: false, // Show ULS in compact mode
405 | showRegions: [ 'WW', 'AM', 'EU', 'ME', 'AF', 'AS', 'PA' ],
406 | languageDecorator: null // Callback function to be called when a language link is prepared - for custom decoration.
407 | };
408 |
409 | // Define a dummy i18n function, if jquery.i18n not integrated.
410 | if ( !$.fn.i18n ) {
411 | $.fn.i18n = function () {};
412 | }
413 |
414 | /*
415 | * Simple scrollIntoView plugin.
416 | * Scrolls the element to the viewport smoothly if it is not already.
417 | */
418 | $.fn.scrollIntoView = function () {
419 | return this.each( function () {
420 | var scrollPosition,
421 | $window = $( window ),
422 | windowHeight = $window.height(),
423 | windowTop = $window.scrollTop(),
424 | windowBottom = windowTop + windowHeight,
425 | $element = $( this ),
426 | panelHeight = $element.height(),
427 | panelTop = $element.offset().top,
428 | panelBottom = panelTop + panelHeight;
429 |
430 | if ( ( panelTop < windowTop ) || ( panelBottom > windowBottom ) ) {
431 | if ( windowTop > panelTop ) {
432 | scrollPosition = panelTop;
433 | } else {
434 | scrollPosition = panelBottom - windowHeight;
435 | }
436 | $( 'html, body' ).stop().animate( {
437 | scrollTop: scrollPosition
438 | }, 500 );
439 | }
440 | } );
441 | };
442 |
443 | $.fn.uls.Constructor = ULS;
444 | }( jQuery ) );
445 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.data.utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Utility functions for querying language data.
3 | *
4 | * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
5 | * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
6 | * contributors. See CREDITS for a list.
7 | *
8 | * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
9 | * have to do anything special to choose one license or the other and you don't
10 | * have to notify anyone which license you are using. You are free to use
11 | * UniversalLanguageSelector in commercial projects as long as the copyright
12 | * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
13 | *
14 | * @file
15 | * @ingroup Extensions
16 | * @licence GNU General Public Licence 2.0 or later
17 | * @licence MIT License
18 | */
19 |
20 | ( function ( $ ) {
21 | 'use strict';
22 |
23 | /**
24 | * Is this language a redirect to another language?
25 | * @param language string Language code
26 | * @return Target language code if it's a redirect or false if it's not
27 | */
28 | $.uls.data.isRedirect = function ( language ) {
29 | return ( $.uls.data.languages[language] !== undefined &&
30 | $.uls.data.languages[language].length === 1 ) ? $.uls.data.languages[language][0] : false;
31 | };
32 |
33 | /**
34 | * Returns the script of the language.
35 | * @param language string Language code
36 | * @return string
37 | */
38 | $.uls.data.getScript = function ( language ) {
39 | var target = $.uls.data.isRedirect( language );
40 |
41 | if ( target ) {
42 | return $.uls.data.getScript( target );
43 | }
44 |
45 | if ( !$.uls.data.languages[language] ) {
46 | // Undetermined
47 | return 'Zyyy';
48 | }
49 |
50 | return $.uls.data.languages[language][0];
51 | };
52 |
53 | /**
54 | * Returns the regions in which a language is spoken.
55 | * @param language string Language code
56 | * @return array|string 'UNKNOWN'
57 | */
58 | $.uls.data.getRegions = function ( language ) {
59 | var target = $.uls.data.isRedirect( language );
60 |
61 | if ( target ) {
62 | return $.uls.data.getRegions( target );
63 | }
64 |
65 | return ( $.uls.data.languages[language] && $.uls.data.languages[language][1] ) || 'UNKNOWN';
66 | };
67 |
68 | /**
69 | * Returns the autonym of the language.
70 | * @param language string Language code
71 | * @return string
72 | */
73 | $.uls.data.getAutonym = function ( language ) {
74 | var target = $.uls.data.isRedirect( language );
75 |
76 | if ( target ) {
77 | return $.uls.data.getAutonym( target );
78 | }
79 |
80 | return ( $.uls.data.languages[language] && $.uls.data.languages[language][2] ) || language;
81 | };
82 |
83 | /**
84 | * Returns all language codes and corresponding autonyms
85 | * @return array
86 | */
87 | $.uls.data.getAutonyms = function () {
88 | var language,
89 | autonymsByCode = {};
90 |
91 | for ( language in $.uls.data.languages ) {
92 | if ( $.uls.data.isRedirect( language ) ) {
93 | continue;
94 | }
95 |
96 | autonymsByCode[language] = $.uls.data.getAutonym( language );
97 | }
98 |
99 | return autonymsByCode;
100 | };
101 |
102 | /**
103 | * Returns an array of all region codes.
104 | * @return array
105 | */
106 | $.uls.data.getAllRegions = function () {
107 | var region,
108 | allRegions = [];
109 |
110 | for ( region in $.uls.data.regiongroups ) {
111 | allRegions.push( region );
112 | }
113 |
114 | return allRegions;
115 | };
116 |
117 | /**
118 | * Returns all languages written in script.
119 | * @param script string
120 | * @return array of strings (languages codes)
121 | */
122 | $.uls.data.getLanguagesInScript = function ( script ) {
123 | return $.uls.data.getLanguagesInScripts( [ script ] );
124 | };
125 |
126 | /**
127 | * Returns all languages written in the given scripts.
128 | * @param scripts array of strings
129 | * @return array of strings (languages codes)
130 | */
131 | $.uls.data.getLanguagesInScripts = function ( scripts ) {
132 | var language, i,
133 | languagesInScripts = [];
134 |
135 | for ( language in $.uls.data.languages ) {
136 | if ( $.uls.data.isRedirect( language ) ) {
137 | continue;
138 | }
139 |
140 | for ( i = 0; i < scripts.length; i++ ) {
141 | if ( scripts[i] === $.uls.data.getScript( language ) ) {
142 | languagesInScripts.push( language );
143 | break;
144 | }
145 | }
146 | }
147 |
148 | return languagesInScripts;
149 | };
150 |
151 | /**
152 | * Returns all languages in a given region.
153 | * @param region string
154 | * @return array of strings (languages codes)
155 | */
156 | $.uls.data.getLanguagesInRegion = function ( region ) {
157 | return $.uls.data.getLanguagesInRegions( [ region ] );
158 | };
159 |
160 | /**
161 | * Returns all languages in given regions.
162 | * @param regions array of strings.
163 | * @return array of strings (languages codes)
164 | */
165 | $.uls.data.getLanguagesInRegions = function ( regions ) {
166 | var language, i,
167 | languagesInRegions = [];
168 |
169 | for ( language in $.uls.data.languages ) {
170 | if ( $.uls.data.isRedirect( language ) ) {
171 | continue;
172 | }
173 |
174 | for ( i = 0; i < regions.length; i++ ) {
175 | if ( $.inArray( regions[i], $.uls.data.getRegions( language ) ) !== -1 ) {
176 | languagesInRegions.push( language );
177 | break;
178 | }
179 | }
180 | }
181 |
182 | return languagesInRegions;
183 | };
184 |
185 | /**
186 | * Returns all languages in a region group.
187 | * @param groupNum number.
188 | * @return array of strings (languages codes)
189 | */
190 | $.uls.data.getLanguagesInRegionGroup = function ( groupNum ) {
191 | return $.uls.data.getLanguagesInRegions( $.uls.data.getRegionsInGroup( groupNum ) );
192 | };
193 |
194 | /**
195 | * Returns an associative array of languages in a region,
196 | * grouped by script.
197 | * @param region string Region code
198 | * @return associative array
199 | */
200 | $.uls.data.getLanguagesByScriptInRegion = function ( region ) {
201 | var language, script,
202 | languagesByScriptInRegion = {};
203 |
204 | for ( language in $.uls.data.languages ) {
205 | if ( $.uls.data.isRedirect( language ) ) {
206 | continue;
207 | }
208 |
209 | if ( $.inArray( region, $.uls.data.getRegions( language ) ) !== -1 ) {
210 | script = $.uls.data.getScript( language );
211 |
212 | if ( languagesByScriptInRegion[script] === undefined ) {
213 | languagesByScriptInRegion[script] = [];
214 | }
215 | languagesByScriptInRegion[script].push( language );
216 | }
217 | }
218 |
219 | return languagesByScriptInRegion;
220 | };
221 |
222 | /**
223 | * Returns an associative array of languages in a region,
224 | * grouped by script group.
225 | * @param region string Region code
226 | * @return associative array
227 | */
228 | $.uls.data.getLanguagesByScriptGroupInRegion = function ( region ) {
229 | return $.uls.data.getLanguagesByScriptGroupInRegions( [ region ] );
230 | };
231 |
232 | /**
233 | * Returns an associative array of all languages,
234 | * grouped by script group.
235 | * @return associative array
236 | */
237 | $.uls.data.getAllLanguagesByScriptGroup = function () {
238 | return $.uls.data.getLanguagesByScriptGroupInRegions( $.uls.data.getAllRegions() );
239 | };
240 |
241 | /**
242 | * Get the given list of languages grouped by script.
243 | * @param languages Array of language codes
244 | * @return {Object} Array of languages indexed by script codes
245 | */
246 | $.uls.data.getLanguagesByScriptGroup = function ( languages ) {
247 | var languagesByScriptGroup = {},
248 | language, codeToAdd, langScriptGroup;
249 |
250 | for ( language in languages ) {
251 | codeToAdd = $.uls.data.isRedirect( language ) || language;
252 |
253 | langScriptGroup = $.uls.data.getScriptGroupOfLanguage( codeToAdd );
254 |
255 | if ( !languagesByScriptGroup[langScriptGroup] ) {
256 | languagesByScriptGroup[langScriptGroup] = [];
257 | }
258 |
259 | // Prevent duplicate adding of redirects
260 | if ( $.inArray( codeToAdd, languagesByScriptGroup[langScriptGroup] ) === -1 ) {
261 | languagesByScriptGroup[langScriptGroup].push( codeToAdd );
262 | }
263 | }
264 |
265 | return languagesByScriptGroup;
266 | };
267 |
268 | /**
269 | * Returns an associative array of languages in several regions,
270 | * grouped by script group.
271 | * @param regions array of strings - region codes
272 | * @return associative array
273 | */
274 | $.uls.data.getLanguagesByScriptGroupInRegions = function ( regions ) {
275 | var language, i, scriptGroup,
276 | languagesByScriptGroupInRegions = {};
277 |
278 | for ( language in $.uls.data.languages ) {
279 | if ( $.uls.data.isRedirect( language ) ) {
280 | continue;
281 | }
282 |
283 | for ( i = 0; i < regions.length; i++ ) {
284 | if ( $.inArray( regions[i], $.uls.data.getRegions( language ) ) !== -1 ) {
285 | scriptGroup = $.uls.data.getScriptGroupOfLanguage( language );
286 |
287 | if ( languagesByScriptGroupInRegions[scriptGroup] === undefined ) {
288 | languagesByScriptGroupInRegions[scriptGroup] = [];
289 | }
290 |
291 | languagesByScriptGroupInRegions[scriptGroup].push( language );
292 | break;
293 | }
294 | }
295 | }
296 |
297 | return languagesByScriptGroupInRegions;
298 | };
299 |
300 | /**
301 | * Returns an array of languages grouped by region group,
302 | * region, script group and script.
303 | * @return associative array
304 | */
305 | $.uls.data.getAllLanguagesByRegionAndScript = function () {
306 | var region, regionGroup, language,
307 | script, scriptGroup, regions, regionNum,
308 | allLanguagesByRegionAndScript = {};
309 |
310 | for ( region in $.uls.data.regiongroups ) {
311 | regionGroup = $.uls.data.regiongroups[region];
312 |
313 | if ( allLanguagesByRegionAndScript[regionGroup] === undefined ) {
314 | allLanguagesByRegionAndScript[regionGroup] = {};
315 | }
316 |
317 | allLanguagesByRegionAndScript[regionGroup][region] = {};
318 | }
319 |
320 | for ( language in $.uls.data.languages ) {
321 | if ( $.uls.data.isRedirect( language ) ) {
322 | continue;
323 | }
324 |
325 | script = $.uls.data.getScript( language );
326 | scriptGroup = $.uls.data.getGroupOfScript( script );
327 | regions = $.uls.data.getRegions( language );
328 |
329 | for ( regionNum = 0; regionNum < regions.length; regionNum++ ) {
330 | region = regions[regionNum];
331 | regionGroup = $.uls.data.regiongroups[region];
332 |
333 | if ( allLanguagesByRegionAndScript[regionGroup][region][scriptGroup] === undefined ) {
334 | allLanguagesByRegionAndScript[regionGroup][region][scriptGroup] = {};
335 | }
336 |
337 | if ( allLanguagesByRegionAndScript[regionGroup][region][scriptGroup][script] === undefined ) {
338 | allLanguagesByRegionAndScript[regionGroup][region][scriptGroup][script] = [];
339 | }
340 |
341 | allLanguagesByRegionAndScript[regionGroup][region][scriptGroup][script].push( language );
342 | }
343 | }
344 |
345 | return allLanguagesByRegionAndScript;
346 | };
347 |
348 | /**
349 | * Returns all regions in a region group.
350 | * @param groupNum int
351 | * @return array of strings
352 | */
353 | $.uls.data.getRegionsInGroup = function ( groupNum ) {
354 | var region,
355 | regionsInGroup = [];
356 |
357 | for ( region in $.uls.data.regiongroups ) {
358 | if ( $.uls.data.regiongroups[region] === groupNum ) {
359 | regionsInGroup.push( region );
360 | }
361 | }
362 |
363 | return regionsInGroup;
364 | };
365 |
366 | /**
367 | * Returns the script group of a script or 'Other' if it doesn't
368 | * belong to any group.
369 | * @param script string Script code
370 | * @return string script group name
371 | */
372 | $.uls.data.getGroupOfScript = function ( script ) {
373 | var scriptGroup;
374 |
375 | for ( scriptGroup in $.uls.data.scriptgroups ) {
376 | if ( $.inArray( script, $.uls.data.scriptgroups[scriptGroup] ) !== -1 ) {
377 | return scriptGroup;
378 | }
379 | }
380 |
381 | return 'Other';
382 | };
383 |
384 | /**
385 | * Returns the script group of a language.
386 | * @param language string Language code
387 | * @return string script group name
388 | */
389 | $.uls.data.getScriptGroupOfLanguage = function ( language ) {
390 | return $.uls.data.getGroupOfScript( $.uls.data.getScript( language ) );
391 | };
392 |
393 | /**
394 | * A callback for sorting languages by autonym.
395 | * Can be used as an argument to a sort function.
396 | * @param a string Language code
397 | * @param b string Language code
398 | */
399 | $.uls.data.sortByAutonym = function ( a, b ) {
400 | var autonymA = $.uls.data.getAutonym( a ) || a,
401 | autonymB = $.uls.data.getAutonym( b ) || b;
402 |
403 | return ( autonymA.toLowerCase() < autonymB.toLowerCase() ) ? -1 : 1;
404 | };
405 |
406 | /**
407 | * Check if a language is right-to-left.
408 | * @param language string Language code
409 | * @return boolean
410 | */
411 | $.uls.data.isRtl = function ( language ) {
412 | return $.inArray( $.uls.data.getScript( language ), $.uls.data.rtlscripts ) !== -1;
413 | };
414 |
415 | /**
416 | * Return the direction of the language
417 | * @param language string Language code
418 | * @return string
419 | */
420 | $.uls.data.getDir = function ( language ) {
421 | return $.uls.data.isRtl( language ) ? 'rtl' : 'ltr';
422 | };
423 |
424 | /**
425 | * Returns the languages spoken in a territory.
426 | * @param territory string Territory code
427 | * @return list of language codes
428 | */
429 | $.uls.data.getLanguagesInTerritory = function ( territory ) {
430 | return $.uls.data.territories[territory];
431 | };
432 |
433 | /**
434 | * Adds a language in run time and sets its options as provided.
435 | * If the target option is provided, the language is defined as a redirect.
436 | * Other possible options are script, regions and autonym.
437 | *
438 | * @param code string New language code.
439 | * @param options Object Language properties.
440 | * @return list of language codes
441 | */
442 | $.uls.data.addLanguage = function( code, options ) {
443 | if ( options.target ) {
444 | $.uls.data.languages[code] = [options.target];
445 | } else {
446 | $.uls.data.languages[code] = [options.script, options.regions, options.autonym];
447 | }
448 | };
449 |
450 | /**
451 | * Removes a language from the langdb in run time.
452 | *
453 | * @param code string Language code to delete.
454 | * @return true if the language was removed, false otherwise.
455 | */
456 | $.uls.data.deleteLanguage = function( code ) {
457 | if ( $.uls.data.languages[code] ) {
458 | delete $.uls.data.languages[code];
459 |
460 | return true;
461 | }
462 |
463 | return false;
464 | };
465 | } ( jQuery ) );
466 |
--------------------------------------------------------------------------------
/static/jquery.uls/img/world_map.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/jquery.uls/js/jquery.uls.data.js:
--------------------------------------------------------------------------------
1 | // Please do not edit. This file is generated from data/langdb.yaml by ulsdata2json.php
2 | ( function ( $ ) {
3 | 'use strict';
4 | $.uls = $.uls || {};
5 | //noinspection JSHint
6 | $.uls.data = {"languages":{"aa":["Latn",["AF"],"Qafár af"],"ab":["Cyrl",["EU"],"Аҧсшәа"],"ace":["Latn",["AS","PA"],"Acèh"],"ady":["Cyrl",["EU","ME"],"Адыгэбзэ"],"ady-cyrl":["ady"],"ady-latn":["Latn",["EU","ME"],"Adygabze"],"aeb":["Arab",["AF"],"زَوُن"],"af":["Latn",["AF"],"Afrikaans"],"ahr":["Deva",["AS"],"अहिराणी"],"ak":["Latn",["AF"],"Akan"],"akz":["Latn",["AM"],"Albaamo innaaɬiilka"],"aln":["Latn",["EU"],"Gegë"],"am":["Ethi",["AF"],"አማርኛ"],"an":["Latn",["EU"],"aragonés"],"ang":["Latn",["EU"],"Ænglisc"],"anp":["Deva",["AS"],"अङ्गिका"],"ar":["Arab",["ME"],"العربية"],"arc":["Syrc",["ME"],"ܐܪܡܝܐ"],"arn":["Latn",["AM"],"mapudungun"],"aro":["Latn",["AM"],"Araona"],"arq":["Arab",["AF"],"جازايرية"],"ary":["Latn",["ME"],"Maġribi"],"arz":["Arab",["ME"],"مصرى"],"as":["Beng",["AS"],"অসমীয়া"],"ase":["Sgnw",["AM"],"American sign language"],"ast":["Latn",["EU"],"asturianu"],"av":["Cyrl",["EU"],"авар"],"avk":["Latn",["WW"],"Kotava"],"ay":["Latn",["AM"],"Aymar aru"],"az":["az-latn"],"az-latn":["Latn",["EU","ME"],"azərbaycanca"],"az-arab":["Arab",["EU","ME"],"آذربايجانجا"],"az-cyrl":["Latn",["EU","ME"],"азәрбајҹанҹа"],"azb":["az-arab"],"ba":["Cyrl",["EU"],"башҡортса"],"bar":["Latn",["EU"],"Boarisch"],"bat-smg":["sgs"],"bbc-latn":["Latn",["AS"],"Batak Toba"],"bbc-batk":["Batk",["AS"],"Batak Toba"],"bbc":["Latn",["AS"],"Batak Toba"],"bcc":["Arab",["AS","ME"],"بلوچی مکرانی"],"bcl":["Latn",["AS"],"Bikol Central"],"be-tarask":["Cyrl",["EU"],"беларуская (тарашкевіца)"],"be-x-old":["be-tarask"],"be":["Cyrl",["EU"],"беларуская"],"bew":["Latn",["AS"],"Bahasa Betawi"],"bfq":["Taml",["AS"],"படகா"],"bg":["Cyrl",["EU"],"български"],"bh":["Deva",["AS"],"भोजपुरी"],"bho":["Deva",["AS"],"भोजपुरी"],"bi":["Latn",["PA"],"Bislama"],"bjn":["Latn",["AS"],"Bahasa Banjar"],"bm":["Latn",["AF"],"bamanankan"],"bn":["Beng",["AS"],"বাংলা"],"bo":["Tibt",["AS"],"བོད་ཡིག"],"bpy":["Beng",["AS"],"বিষ্ণুপ্রিয়া মণিপুরী"],"bqi":["Arab",["ME"],"بختياري"],"br":["Latn",["EU"],"brezhoneg"],"brh":["Latn",["ME","AS"],"Bráhuí"],"brx":["Deva",["AS"],"बड़ो"],"bs":["Latn",["EU"],"bosanski"],"bto":["Latn",["AS"],"Iriga Bicolano"],"bug":["Bugi",["AS"],"ᨅᨔ ᨕᨘᨁᨗ"],"bxr":["Cyrl",["AS"],"буряад"],"ca":["Latn",["EU"],"català"],"cbk-zam":["Latn",["AS"],"Chavacano de Zamboanga"],"cdo":["Latn",["AS"],"Mìng-dĕ̤ng-ngṳ̄"],"ce":["Cyrl",["EU"],"нохчийн"],"ceb":["Latn",["AS"],"Cebuano"],"ch":["Latn",["PA"],"Chamoru"],"cho":["Latn",["AM"],"Choctaw"],"chr":["Cher",["AM"],"ᏣᎳᎩ"],"chy":["Latn",["AM"],"Tsetsêhestâhese"],"ckb":["Arab",["ME"],"کوردی"],"co":["Latn",["EU"],"corsu"],"cps":["Latn",["AS"],"Capiceño"],"cr":["Cans",["AM"],"ᓀᐦᐃᔭᐍᐏᐣ"],"cr-cans":["cr"],"cr-latn":["Latn",["AM"],"Nēhiyawēwin"],"crh":["Latn",["EU"],"qırımtatarca"],"crh-cyrl":["Cyrl",["EU"],"къырымтатарджа"],"crh-latn":["crh"],"cs":["Latn",["EU"],"česky"],"csb":["Latn",["EU"],"kaszëbsczi"],"cu":["Cyrl",["EU"],"словѣньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ"],"cv":["Cyrl",["EU"],"Чӑвашла"],"cy":["Latn",["EU"],"Cymraeg"],"da":["Latn",["EU"],"dansk"],"de-at":["Latn",["EU"],"Österreichisches Deutsch"],"de-ch":["Latn",["EU"],"Schweizer Hochdeutsch"],"de-formal":["Latn",["EU"],"Deutsch (Sie-Form)"],"de":["Latn",["EU"],"Deutsch"],"diq":["Latn",["EU","AS"],"Zazaki"],"dsb":["Latn",["EU"],"dolnoserbski"],"dtp":["Latn",["AS"],"Dusun Bundu-liwan"],"dv":["Thaa",["AS"],"ދިވެހިބަސް"],"dz":["Tibt",["AS"],"ཇོང་ཁ"],"ee":["Latn",["AF"],"eʋegbe"],"egl":["Latn",["EU"],"Emiliàn"],"el":["Grek",["EU"],"Ελληνικά"],"eml":["Latn",["EU"],"emiliàn e rumagnòl"],"en-ca":["Latn",["AM"],"Canadian English"],"en-gb":["Latn",["EU","AS","PA"],"British English"],"en":["Latn",["EU","AM","AF","ME","AS","PA","WW"],"English"],"eo":["Latn",["WW"],"Esperanto"],"es-419":["Latn",["AM"],"español de America Latina"],"es-formal":["Latn",["EU","AM","AF","WW"],"español (formal)"],"es":["Latn",["EU","AM","AF","WW"],"español"],"esu":["Latn",["AM"],"Yup'ik"],"et":["Latn",["EU"],"eesti"],"eu":["Latn",["EU"],"euskara"],"ext":["Latn",["EU"],"estremeñu"],"fa":["Arab",["ME"],"فارسی"],"ff":["Latn",["AF"],"Fulfulde"],"fi":["Latn",["EU"],"suomi"],"fil":["tl"],"fit":["Latn",["EU"],"meänkieli"],"fiu-vro":["vro"],"fj":["Latn",["PA"],"Na Vosa Vakaviti"],"fo":["Latn",["EU"],"føroyskt"],"fr":["Latn",["EU","AM","WW"],"français"],"frc":["Latn",["AM"],"français cadien"],"frp":["Latn",["EU"],"arpetan"],"frr":["Latn",["EU"],"Nordfriisk"],"fur":["Latn",["EU"],"furlan"],"fy":["Latn",["EU"],"Frysk"],"ga":["Latn",["EU"],"Gaeilge"],"gag":["Latn",["EU"],"Gagauz"],"gah":["Latn",["AS"],"Alekano"],"gan-hans":["Hans",["AS"],"赣语(简体)"],"gan-hant":["gan"],"gan":["Hant",["AS"],"贛語"],"gbz":["Latn",["AS"],"Dari"],"gcf":["Latn",["AM"],"Guadeloupean Creole French"],"gd":["Latn",["EU"],"Gàidhlig"],"gl":["Latn",["EU"],"galego"],"glk":["Arab",["ME"],"گیلکی"],"gn":["Latn",["AM"],"Avañe'ẽ"],"gom":["Deva",["AS"],"कोंकणी"],"gom-deva":["gom"],"gom-latn":["Latn",["AS"],"Konknni"],"got":["Goth",["EU"],"𐌲𐌿𐍄𐌹𐍃𐌺"],"grc":["Grek",["EU"],"Ἀρχαία ἑλληνικὴ"],"gsw":["Latn",["EU"],"Alemannisch"],"gu":["Gujr",["AS"],"ગુજરાતી"],"guc":["Latn",["AM"],"Wayúu"],"gur":["Latn",["AF"],"Gurenɛ"],"gv":["Latn",["EU"],"Gaelg"],"ha-arab":["Arab",["AF"],"هَوُسَ"],"ha-latn":["Latn",["AF"],"Hausa"],"ha":["ha-latn"],"hak":["Latn",["AS"],"Hak-kâ-fa"],"haw":["Latn",["AM","PA"],"Hawai`i"],"he":["Hebr",["ME"],"עברית"],"hi":["Deva",["AS"],"हिन्दी"],"hif":["Latn",["PA","AS"],"Fiji Hindi"],"hif-deva":["Deva",["AS"],"फ़ीजी हिन्दी"],"hif-latn":["hif"],"hil":["Latn",["AS"],"Ilonggo"],"hne":["Deva",["AS"],"छत्तीसगढ़ी"],"ho":["Latn",["PA"],"Hiri Motu"],"hr":["Latn",["EU"],"hrvatski"],"hsb":["Latn",["EU"],"hornjoserbsce"],"hsn":["Hans",["AS"],"湘语"],"ht":["Latn",["AM"],"Kreyòl ayisyen"],"hu-formal":["Latn",["EU"],"Magyar (magázó)"],"hu":["Latn",["EU"],"magyar"],"hy":["Armn",["EU","ME"],"Հայերեն"],"hz":["Latn",["AF"],"Otsiherero"],"ia":["Latn",["WW"],"interlingua"],"id":["Latn",["AS"],"Bahasa Indonesia"],"ie":["Latn",["WW"],"Interlingue"],"ig":["Latn",["AF"],"Igbo"],"ii":["Yiii",["AS"],"ꆇꉙ"],"ik":["Latn",["AM"],"Iñupiak"],"ike-cans":["Cans",["AM"],"ᐃᓄᒃᑎᑐᑦ"],"ike-latn":["Latn",["AM"],"inuktitut"],"ilo":["Latn",["AS"],"Ilokano"],"inh":["Cyrl",["EU"],"ГӀалгӀай"],"io":["Latn",["WW"],"Ido"],"is":["Latn",["EU"],"íslenska"],"it":["Latn",["EU"],"italiano"],"iu":["Cans",["AM"],"ᐃᓄᒃᑎᑐᑦ"],"ja":["Jpan",["AS"],"日本語"],"jam":["Latn",["AM"],"Patois"],"jbo":["Latn",["WW"],"lojban"],"jut":["Latn",["EU"],"jysk"],"jv":["Latn",["AS","PA"],"Basa Jawa"],"jv-java":["Java",["AS","PA"],"ꦧꦱꦗꦮ"],"ka":["Geor",["EU"],"ქართული"],"kaa":["Latn",["AS"],"Qaraqalpaqsha"],"kab":["Latn",["AF","EU"],"Taqbaylit"],"kbd-cyrl":["kbd"],"kbd-latn":["Latn",["EU"],"Qabardjajəbza"],"kbd":["Cyrl",["EU","ME"],"Адыгэбзэ"],"kea":["Latn",["AF"],"Kabuverdianu"],"kg":["Latn",["AF"],"Kongo"],"kgp":["Latn",["AM"],"Kaingáng"],"khw":["Arab",["ME","AS"],"کھوار"],"ki":["Latn",["AF"],"Gĩkũyũ"],"kiu":["Latn",["EU","ME"],"Kırmancki"],"kj":["Latn",["AF"],"Kwanyama"],"kjh":["Cyrl",["AS"],"хакас"],"kk":["kk-cyrl"],"kk-arab":["Arab",["EU","AS"],"قازاقشا (تٶتە)"],"kk-cn":["kk-arab"],"kk-cyrl":["Cyrl",["EU","AS"],"қазақша"],"kk-kz":["kk-cyrl"],"kk-latn":["Latn",["EU","AS","ME"],"qazaqşa"],"kk-tr":["kk-latn"],"kl":["Latn",["AM","EU"],"kalaallisut"],"km":["Khmr",["AS"],"ភាសាខ្មែរ"],"kn":["Knda",["AS"],"ಕನ್ನಡ"],"ko-kp":["Kore",["AS"],"한국어 (조선)"],"ko":["Kore",["AS"],"한국어"],"koi":["Cyrl",["EU"],"Перем Коми"],"kr":["Latn",["AF"],"Kanuri"],"krc":["Cyrl",["EU"],"къарачай-малкъар"],"kri":["Latn",["AF"],"Krio"],"krj":["Latn",["ME","EU"],"Kinaray-a"],"krl":["Latn",["EU"],"Karjala"],"ks-arab":["Arab",["AS"],"کٲشُر"],"ks-deva":["Deva",["AS"],"कॉशुर"],"ks":["Arab",["AS"],"کٲشُر"],"ksf":["Latn",["AF"],"Bafia"],"ksh":["Latn",["EU"],"Ripoarisch"],"ku":["ku-latn"],"ku-arab":["Arab",["EU","ME"],"كوردي"],"ku-latn":["Latn",["EU","ME"],"Kurdî"],"kv":["Cyrl",["EU"],"коми"],"kw":["Latn",["EU"],"kernowek"],"ky":["Cyrl",["AS"],"Кыргызча"],"la":["Latn",["EU"],"Latina"],"lad":["lad-latn"],"lad-latn":["Latn",["ME","EU","AM"],"Ladino"],"lad-hebr":["Hebr",["ME","EU","AM"],"לאדינו"],"lb":["Latn",["EU"],"Lëtzebuergesch"],"lbe":["Cyrl",["EU"],"лакку"],"lez":["Cyrl",["EU"],"лезги"],"lfn":["Latn",["WW"],"Lingua Franca Nova"],"lg":["Latn",["AF"],"Luganda"],"li":["Latn",["EU"],"Limburgs"],"lij":["Latn",["EU"],"Ligure"],"liv":["Latn",["EU"],"Līvõ kēļ"],"lld":["Latn",["EU"],"Ladin"],"lmo":["Latn",["EU"],"lumbaart"],"ln":["Latn",["AF"],"lingála"],"lo":["Laoo",["AS"],"ລາວ"],"loz":["Latn",["AF"],"Silozi"],"lt":["Latn",["EU"],"lietuvių"],"lrc":["Arab",["AS"],"لوری"],"ltg":["Latn",["EU"],"latgaļu"],"lud":["Latn",["EU"],"lüüdi"],"lus":["Latn",["AS"],"Mizo ţawng"],"lut":["Latn",["AM"],"dxʷləšucid"],"lv":["Latn",["EU"],"latviešu"],"lzh":["Hant",["AS"],"文言"],"lzz":["Latn",["EU","ME"],"Lazuri"],"mai":["Deva",["AS"],"मैथिली"],"map-bms":["Latn",["AS"],"Basa Banyumasan"],"mdf":["Cyrl",["EU"],"мокшень"],"mfe":["Latn",["AM"],"Morisyen"],"mg":["Latn",["AF"],"Malagasy"],"mh":["Latn",["PA"],"Ebon"],"mhr":["Cyrl",["EU"],"олык марий"],"mi":["Latn",["PA"],"Māori"],"mic":["Latn",["AM"],"Mi'kmaq"],"min":["Latn",["AS"],"Baso Minangkabau"],"mk":["Cyrl",["EU"],"македонски"],"ml":["Mlym",["AS","ME"],"മലയാളം"],"mn":["Cyrl",["AS"],"монгол"],"mnc":["Mong",["AS"],"ᠮᠠᠨᠵᡠ ᡤᡳᠰᡠᠨ"],"mni":["Beng",["AS"],"মেইতেই লোন্"],"mnw":["Mymr",["AS"],"ဘာသာ မန်"],"mo":["Cyrl",["EU"],"молдовеняскэ"],"mr":["Deva",["AS","ME"],"मराठी"],"mrj":["Cyrl",["EU"],"кырык мары"],"ms":["Latn",["AS"],"Bahasa Melayu"],"mt":["Latn",["EU"],"Malti"],"mui":["Latn",["AS"],"Musi"],"mus":["Latn",["AM"],"Mvskoke"],"mwl":["Latn",["EU"],"Mirandés"],"mwv":["Latn",["AS"],"Behase Mentawei"],"my":["Mymr",["AS"],"မြန်မာဘာသာ"],"myv":["Cyrl",["EU"],"эрзянь"],"mzn":["Arab",["ME","AS"],"مازِرونی"],"na":["Latn",["PA"],"Dorerin Naoero"],"nah":["Latn",["AM"],"Nāhuatl"],"nan":["Latn",["AS"],"Bân-lâm-gú"],"nap":["Latn",["EU"],"Nnapulitano"],"nb":["Latn",["EU"],"norsk (bokmål)"],"nds-nl":["Latn",["EU"],"Nedersaksisch"],"nds":["Latn",["EU"],"Plattdüütsch"],"ne":["Deva",["AS"],"नेपाली"],"new":["Deva",["AS"],"नेपाल भाषा"],"ng":["Latn",["AF"],"Oshiwambo"],"niu":["Latn",["PA"],"ko e vagahau Niuē"],"njo":["Latn",["AS"],"Ao"],"nl-informal":["Latn",["EU","AM"],"Nederlands (informeel)"],"nl":["Latn",["EU","AM"],"Nederlands"],"nn":["Latn",["EU"],"norsk (nynorsk)"],"no":["Latn",["EU"],"norsk"],"nov":["Latn",["WW"],"Novial"],"nqo":["Nkoo",["AF"],"ߒߞߏ"],"nrm":["Latn",["EU"],"Nouormand"],"nso":["Latn",["AF"],"Sesotho sa Leboa"],"nv":["Latn",["AM"],"Diné bizaad"],"ny":["Latn",["AF"],"Chi-Chewa"],"oc":["Latn",["EU"],"occitan"],"om":["Latn",["AF"],"Oromoo"],"or":["Orya",["AS"],"ଓଡ଼ିଆ"],"os":["Cyrl",["EU"],"Ирон"],"ota":["Arab",["AS","EU"],"لسان عثمانى"],"pa":["pa-guru"],"pa-guru":["Guru",["AS"],"ਪੰਜਾਬੀ"],"pag":["Latn",["AS"],"Pangasinan"],"pam":["Latn",["AS"],"Kapampangan"],"pap":["Latn",["AM"],"Papiamentu"],"pcd":["Latn",["EU"],"Picard"],"pdc":["Latn",["EU","AM"],"Deitsch"],"pdt":["Latn",["EU","AM"],"Plautdietsch"],"pfl":["Latn",["EU"],"Pälzisch"],"pi":["Deva",["AS"],"पालि"],"pih":["Latn",["PA"],"Norfuk \/ Pitkern"],"pis":["Latn",["PA"],"Pijin"],"pko":["Latn",["AF"],"Pökoot"],"pl":["Latn",["EU"],"polski"],"pms":["Latn",["EU"],"Piemontèis"],"pnb":["Arab",["AS","ME"],"پنجابی"],"pnt":["Grek",["EU"],"Ποντιακά"],"ppl":["Latn",["AM"],"Nawat"],"prg":["Latn",["EU"],"Prūsiskan"],"ps":["Arab",["AS","ME"],"پښتو"],"pt-br":["Latn",["AM"],"português do Brasil"],"pt":["Latn",["EU","AM","AS","PA","AF","WW"],"português"],"qu":["Latn",["AM"],"Runa Simi"],"qug":["Latn",["AM"],"Runa shimi"],"rap":["Latn",["AM"],"arero rapa nui"],"rgn":["Latn",["EU"],"Rumagnôl"],"rif":["Latn",["AF"],"Tarifit"],"rki":["Mymr",["AS"],"ရခိုင်"],"rm":["Latn",["EU"],"rumantsch"],"rmf":["Latn",["EU"],"kaalengo tšimb"],"rmy":["Latn",["EU"],"Romani"],"rn":["Latn",["AF"],"Kirundi"],"ro":["Latn",["EU"],"română"],"roa-rup":["rup"],"roa-tara":["Latn",["EU"],"tarandíne"],"rtm":["Latn",["PA"],"Faeag Rotuma"],"ru":["Cyrl",["EU","AS","ME"],"русский"],"rue":["Cyrl",["EU"],"русиньскый"],"rup":["Latn",["EU"],"Armãneashce"],"ruq":["Cyrl",["EU"],"Влахесте"],"ruq-cyrl":["ruq"],"ruq-grek":["Grek",["EU"],"Megleno-Romanian (Greek script)"],"ruq-latn":["Latn",["EU"],"Vlăheşte"],"rut":["Cyrl",["EU"],"мыхаӀбишды"],"rw":["Latn",["AF"],"Kinyarwanda"],"rwr":["Deva",["AS"],"मारवाड़ी"],"ryu":["Kana",["AS"],"ʔucināguci"],"sa":["Deva",["AS"],"संस्कृतम्"],"sah":["Cyrl",["EU","AS"],"саха тыла"],"sat":["Latn",["AS"],"Santali"],"saz":["Saur",["AS"],"ꢱꣃꢬꢵꢯ꣄ꢡ꣄ꢬꢵ"],"sc":["Latn",["EU"],"sardu"],"scn":["Latn",["EU"],"sicilianu"],"sco":["Latn",["EU"],"Scots"],"sd":["Arab",["AS"],"سنڌي"],"sdc":["Latn",["EU"],"Sassaresu"],"se":["Latn",["EU"],"sámegiella"],"ses":["Latn",["AF"],"Koyraboro Senni"],"sei":["Latn",["AM"],"Cmique Itom"],"sg":["Latn",["AF"],"Sängö"],"sgs":["Latn",["EU"],"žemaitėška"],"sh":["Latn",["EU"],"srpskohrvatski"],"shi-latn":["Latn",["AF"],"Tašlḥiyt"],"shi-tfng":["Tfng",["AF"],"ⵜⴰⵛⵍⵃⵉⵜ"],"shi":["shi-latn"],"shn":["Mymr",["AS"],"လိၵ်ႈတႆး"],"si":["Sinh",["AS"],"සිංහල"],"simple":["Latn",["WW"],"Simple English"],"sk":["Latn",["EU"],"slovenčina"],"sl":["Latn",["EU"],"slovenščina"],"sli":["Latn",["EU"],"Schläsch"],"slr":["Latn",["AS"],"Salırça"],"sly":["Latn",["AS"],"Bahasa Selayar"],"syc":["Syrc",["ME"],"ܣܘܪܝܝܐ"],"sm":["Latn",["PA"],"Gagana Samoa"],"sma":["Latn",["EU"],"åarjelsaemien"],"smj":["Latn",["EU"],"julevsámegiella"],"smn":["Latn",["EU"],"anarâškielâ"],"sms":["Latn",["EU"],"sää´mǩiõll"],"sn":["Latn",["AF"],"chiShona"],"so":["Latn",["AF"],"Soomaaliga"],"sq":["Latn",["EU"],"shqip"],"sr":["Cyrl",["EU"],"српски"],"sr-ec":["sr-cyrl"],"sr-cyrl":["Cyrl",["EU"],"српски"],"sr-el":["sr-latn"],"sr-latn":["Latn",["EU"],"srpski"],"srn":["Latn",["AM","EU"],"Sranantongo"],"ss":["Latn",["AF"],"SiSwati"],"st":["Latn",["AF"],"Sesotho"],"stq":["Latn",["EU"],"Seeltersk"],"su":["Latn",["AS"],"Basa Sunda"],"sv":["Latn",["EU"],"svenska"],"sw":["Latn",["AF"],"Kiswahili"],"swb":["Latn",["AF"],"Shikomoro"],"sxu":["Latn",["EU"],"Säggssch"],"szl":["Latn",["EU"],"ślůnski"],"ta":["Taml",["AS"],"தமிழ்"],"tcy":["Knda",["AS"],"ತುಳು"],"te":["Telu",["AS"],"తెలుగు"],"tet":["Latn",["AS","PA"],"tetun"],"tg-cyrl":["Cyrl",["AS"],"тоҷикӣ"],"tg-latn":["Latn",["AS"],"tojikī"],"tg":["Cyrl",["AS"],"тоҷикӣ"],"th":["Thai",["AS"],"ไทย"],"ti":["Ethi",["AF"],"ትግርኛ"],"tk":["Latn",["AS"],"Türkmençe"],"tkr":["Cyrl",["AS"],"ЦӀаьхна миз"],"tl":["Latn",["AS"],"Tagalog"],"tly":["Cyrl",["EU","AS","ME"],"толышә зывон"],"tn":["Latn",["AF"],"Setswana"],"to":["Latn",["PA"],"lea faka-Tonga"],"tokipona":["Latn",["WW"],"Toki Pona"],"tpi":["Latn",["PA","AS"],"Tok Pisin"],"tr":["Latn",["EU","ME"],"Türkçe"],"trp":["Latn",["AS"],"Kokborok (Tripuri)"],"tru":["Latn",["AS"],"Ṫuroyo"],"ts":["Latn",["AF"],"Xitsonga"],"tsd":["Grek",["EU"],"Τσακωνικά"],"tt":["Cyrl",["EU"],"татарча"],"tt-cyrl":["tt"],"tt-latn":["Latn",["EU"],"tatarça"],"ttt":["Cyrl",["AS"],"Tati"],"tum":["Latn",["AF"],"chiTumbuka"],"tw":["Latn",["AF"],"Twi"],"twd":["Latn",["EU"],"Tweants"],"ty":["Latn",["PA"],"Reo Mā`ohi"],"tyv":["Cyrl",["AS"],"тыва дыл"],"tzm":["Tfng",["AF"],"ⵜⴰⵎⴰⵣⵉⵖⵜ"],"udm":["Cyrl",["EU"],"удмурт"],"ug":["ug-arab"],"ug-arab":["Arab",["AS"],"ئۇيغۇرچە"],"ug-latn":["Latn",["AS"],"uyghurche"],"ug-cyrl":["Cyrl",["AS"],"уйғурчә"],"uk":["Cyrl",["EU"],"українська"],"ur":["Arab",["AS","ME"],"اردو"],"uz":["Latn",["AS"],"oʻzbekcha"],"ve":["Latn",["AF"],"Tshivenda"],"vec":["Latn",["EU"],"vèneto"],"vep":["Latn",["EU"],"vepsän kel’"],"vi":["Latn",["AS"],"Tiếng Việt"],"vls":["Latn",["EU"],"West-Vlams"],"vmf":["Latn",["EU"],"Mainfränkisch"],"vo":["Latn",["WW"],"Volapük"],"vot":["Latn",["EU"],"Vaďďa"],"vro":["Latn",["EU"],"Võro"],"wa":["Latn",["EU"],"walon"],"war":["Latn",["AS"],"Winaray"],"wls":["Latn",["PA"],"Faka'uvea"],"wo":["Latn",["AF"],"Wolof"],"wuu":["Hans",["AS"],"吴语"],"xal":["Cyrl",["EU"],"хальмг"],"xh":["Latn",["AF"],"isiXhosa"],"xmf":["Geor",["EU"],"მარგალური"],"ydd":["Hebr",["AS","EU"],"Eastern Yiddish"],"yi":["Hebr",["ME","EU","AM"],"ייִדיש"],"yo":["Latn",["AF"],"Yorùbá"],"yrk":["Cyrl",["AS"],"Ненэцяʼ вада"],"yrl":["Latn",["AM"],"ñe'engatú"],"yua":["Latn",["AM"],"Maaya T'aan"],"yue":["Hant",["AS"],"粵語"],"za":["Latn",["AS"],"Vahcuengh"],"zea":["Latn",["EU"],"Zeêuws"],"zh":["Hans",["AS"],"中文"],"zh-classical":["Hant",["AS"],"文言"],"zh_CN":["Hans",["AS"],"中文(中国大陆)"],"zh-hans":["Hans",["AS"],"中文(简体)"],"zh-hant":["Hant",["AS"],"中文(繁體)"],"zh-hk":["Hant",["AS"],"中文(香港)"],"zh-min-nan":["nan"],"zh-mo":["Hant",["AS"],"中文(澳門)"],"zh-my":["Hans",["AS"],"中文(马来西亚)"],"zh-sg":["Hans",["AS"],"中文(新加坡)"],"zh_TW":["Hant",["AS"],"中文(台灣)"],"zh-yue":["yue"],"zu":["Latn",["AF"],"isiZulu"]},"scriptgroups":{"Latin":["Latn","Goth"],"Greek":["Grek"],"WestCaucasian":["Armn","Geor"],"Arabic":["Arab"],"MiddleEastern":["Hebr","Syrc"],"African":["Ethi","Nkoo","Tfng"],"SouthAsian":["Beng","Deva","Gujr","Guru","Knda","Mlym","Orya","Saur","Sinh","Taml","Telu","Tibt","Thaa"],"Cyrillic":["Cyrl"],"CJK":["Hans","Hant","Kana","Kore","Jpan","Yiii"],"SouthEastAsian":["Batk","Bugi","Java","Khmr","Laoo","Mymr","Thai"],"Mongolian":["Mong"],"SignWriting":["Sgnw"],"NativeAmerican":["Cher","Cans"],"Special":["Zyyy"]},"rtlscripts":["Arab","Hebr","Syrc","Nkoo","Thaa"],"regiongroups":{"WW":1,"SP":1,"AM":2,"EU":3,"ME":3,"AF":3,"AS":4,"PA":4},"territories":{"AC":["en"],"AD":["ca","es","fr"],"AE":["ar","ml","ps","bal","fa"],"AF":["fa","ps","haz","uz-arab","tk-latn","prd","bal","ug-arab","kk-arab"],"AG":["en","pt"],"AI":["en"],"AL":["sq","el","mk"],"AM":["hy","ku-latn","az-latn"],"AO":["pt","umb","kmb","ln"],"AQ":["und"],"AR":["es","cy","gn"],"AS":["sm","en"],"AT":["de","bar","hr","sl","hu"],"AU":["en","zh-hant","it"],"AW":["nl","pap","en"],"AX":["sv"],"AZ":["az-latn","az-cyrl","tly-latn","ku-latn","ttt-latn","tkr-latn"],"BA":["bs-cyrl","bs-latn","hr","sr-cyrl","sr-latn"],"BB":["en"],"BD":["bn","rkt","syl","ccp","my","grt","mni"],"BE":["nl","en","fr","vls","wa","de"],"BF":["mos","dyu","fr"],"BG":["bg","tr"],"BH":["ar","ml"],"BI":["rn","fr","sw"],"BJ":["fr","fon","yo"],"BL":["fr"],"BM":["en"],"BN":["ms-latn","zh-hant","ms-arab","en"],"BO":["es","qu","ay","gn","aro"],"BQ":["pap","nl"],"BR":["pt","de","it","ja","ko","kgp","gub","yrl","xav"],"BS":["en"],"BT":["dz","ne","tsj","lep"],"BV":["und"],"BW":["en","tn","af"],"BY":["be","ru"],"BZ":["en","es"],"CA":["en","fr","it","de","pdt","cr-cans","crk","yi","iu-cans","iu-latn","moe","crj","atj","crl","csw","crm","ikt","moh","dgr","den","scs","nsk","chp","gwi"],"CC":["ms-arab","en"],"CD":["sw","lua","swc","fr","ln","lu","kg","lol","rw"],"CF":["fr","sg","ln"],"CG":["fr","ln"],"CH":["de","fr","gsw","it","lmo","rm","rmo","wae"],"CI":["fr","bci","sef","dnj","kfo","bqv"],"CK":["en"],"CL":["es","arn"],"CM":["fr","en","bum","ff","ewo","ybb","bbj","nnh","bkm","bas","bax","byv","mua","maf","bfd","bss","kkj","dua","mgo","ar","jgo","ksf","agq","ha-arab","nmg","yav"],"CN":["zh-hans","wuu","hsn","hak","nan","gan","ii","ug-arab","za","mn-mong","bo","ko","kk-arab","lis","ky-arab","nxq","khb","tdd","lcp","en","ru","vi","uz-cyrl","lzh"],"CO":["es","guc"],"CP":["und"],"CR":["es"],"CU":["es"],"CV":["kea","pt"],"CW":["pap","nl","es"],"CX":["en"],"CY":["el","tr","hy","ar"],"CZ":["cs","de","pl"],"DE":["de","en","nds","vmf","tr","hr","it","ku-latn","ru","el","ksh","pl","es","nl","da","hsb","frr","dsb","frs","stq","pfl"],"DG":["en"],"DJ":["aa","so","ar","fr"],"DK":["da","de","kl","jut"],"DM":["en"],"DO":["es","en"],"DZ":["arq","ar","fr","kab"],"EA":["es"],"EC":["es","qu","qug"],"EE":["et","ru","vro"],"EG":["ar","arz","el"],"EH":["ar"],"ER":["ti","en","tig","ar","aa","ssy","byn"],"ES":["es","en","ca","gl","eu","ast","ext"],"ET":["en","am","om","so","ti","sid","wal","aa"],"FI":["fi","sv","ru","en","et","rmf","se","smn","sms"],"FJ":["en","hi","hif-deva","fj","rtm"],"FK":["en"],"FM":["chk","pon","kos","yap","en","uli"],"FO":["fo"],"FR":["fr","en","oc","it","pt","pcd","gsw","br","co","ca","nl","eu","frp","ia"],"GA":["fr","puu"],"GB":["en","sco","pa-guru","cy","bn","zh-hant","syl","el","it","ks-arab","gd","yi","ml","ga","fr","kw"],"GD":["en"],"GE":["ka","xmf","ru","hy","ab","os","ku-latn"],"GF":["fr","gcr","zh-hant"],"GG":["en"],"GH":["ak","en","ee","abr","gur","gaa","ha-latn","saf"],"GI":["en"],"GL":["kl","da"],"GM":["en","man-latn"],"GN":["fr","ff","man-nkoo","sus","nqo","kpe"],"GP":["fr"],"GQ":["es","fan","fr","bvb"],"GR":["el","pnt-grek","mk","tr","bg","sq","tsd"],"GS":["und"],"GT":["es","quc"],"GU":["en","ch"],"GW":["pt"],"GY":["en"],"HK":["zh-hant","en","zh-hans"],"HM":["und"],"HN":["es","en"],"HR":["hr","it"],"HT":["ht","fr"],"HU":["hu","de","ro","hr","sk","sl"],"IC":["es"],"ID":["id","jv","su","mad","ms-arab","min","bew","ban","bug","bjn","ace","sas","bbc","zh-hant","mak","ljp","rej","gor","nij","kge","aoz","kvr","lbw","rob","mdr","sxn","sly","mwv"],"IE":["en","ga"],"IL":["he","ar","ru","ro","yi","en","pl","lad","hu","am","ti","ml"],"IM":["en","gv"],"IN":["hi","en","bn","te","mr","ta","ur","gu","kn","ml","or","pa-guru","bho","awa","as","bgc","mag","mwr","mai","hne","dcc","bjj","ne","sat","wtm","rkt","ks-arab","kok","gom","swv","gbm","lmn","sd-arab","gon-telu","kfy","doi","kru","sck","wbq","xnr","tcy","wbr","khn","brx","noe","bhb","mni","raj","hoc","mtr","unr-beng","bhi","hoj","kha","kfr","grt","unx-beng","bfy","srx","saz","ccp","sd-deva","bfq","njo","ria","bo","bpy","bft","bra","lep","btv","lif-deva","lah","sa","kht","dv","dz"],"IO":["en"],"IQ":["ar","ckb","fa","syr"],"IR":["fa","az-arab","azb","mzn","glk","ckb","tk-latn","lrc","ar","bal","rmt","bqi","luz","lki","prd","hy","ps","ka","gbz","kk-arab"],"IS":["is","da"],"IT":["it","en","fr","lmo","pms","sc","de","vec","nap","lij","scn","sl","sdc","fur","egl","ca","el","hr","rgn"],"JE":["en"],"JM":["en","jam"],"JO":["ar"],"JP":["ja","ryu","ko"],"KE":["en","sw","ki","luy","luo","kam","kln","guz","mer","mas","ebu","so","dav","teo","pko","om","saq","ar","pa-guru","gu"],"KG":["ky-cyrl","ru"],"KH":["km","cja","kdt"],"KI":["en","gil"],"KM":["ar","fr","zdj"],"KN":["en"],"KP":["ko"],"KR":["ko"],"KW":["ar"],"KY":["en"],"KZ":["ru","kk-cyrl","de","ug-cyrl"],"LA":["lo","kjg","kdt"],"LB":["ar","hy","ku-arab","fr","en"],"LC":["en"],"LI":["de","gsw","wae"],"LK":["si","ta","en"],"LR":["en","kpe","vai-vaii","men","vai-latn"],"LS":["st","zu","ss","en","xh"],"LT":["lt","ru","sgs"],"LU":["fr","lb","de"],"LV":["lv","ru","ltg"],"LY":["ar"],"MA":["ary","ar","zgh","fr","tzm-latn","shi-latn","shi-tfng","rif-latn","rif-tfng","es"],"MC":["fr"],"MD":["ro","uk","bg","gag","ru"],"ME":["sr-latn","sq","sr-cyrl"],"MF":["fr"],"MG":["mg","fr","en"],"MH":["en","mh"],"MK":["mk","sq","tr"],"ML":["bm-latn","fr","ffm","snk","mwk","ses","tmh","bm-nkoo","khq","dtm","kao","ar","bmq","bze"],"MM":["my","shn","mnw","kht"],"MN":["mn-cyrl","kk-arab","zh-hans","ru","ug-cyrl"],"MO":["zh-hant","pt","zh-hans","en"],"MP":["en","ch"],"MQ":["fr"],"MR":["ar","fr","ff","wo"],"MS":["en"],"MT":["mt","en"],"MU":["mfe","en","bho","ur","fr","ta"],"MV":["dv"],"MW":["en","ny","tum","zu"],"MX":["es","yua","nhe","nhw","maz","nch","sei"],"MY":["ms-latn","en","zh-hant","ta","jv","zmi","dtp","ml","bug","bjn"],"MZ":["pt","vmw","ndc","ts","ngl","seh","mgh","rng","ny","yao","sw","zu"],"NA":["af","kj","ng","naq","en","de","tn"],"NC":["fr"],"NE":["ha-latn","fr","dje","fuq","tmh","ar","twq"],"NF":["en"],"NG":["en","pcm","ha-latn","ig","yo","fuv","tiv","efi","ibb","ha-arab","bin","kaj","kcg","ar","cch","amo"],"NI":["es"],"NL":["nl","en","li","fy","gos","id","zea","rif-latn","tr"],"NO":["nb","nn","se"],"NP":["ne","mai","bho","new","jml","taj","awa","thl","bap","tdg","thr","mgp","lif-deva","thq","mrd","bfy","xsr","rjs","tsf","hi","ggn","gvr","bo","tkt","tdh","bn","unr-deva","lep"],"NR":["en","na"],"NU":["en","niu"],"NZ":["en","mi"],"OM":["ar","bal","fa"],"PA":["es","en","zh-hant"],"PE":["es","qu","ay"],"PF":["fr","ty","zh-hant"],"PG":["tpi","en","ho"],"PH":["en","fil","es","ceb","ilo","hil","bik","war","bhk","pam","pag","mdh","tsg","zh-hant","cps","krj","bto","hnn","tbw","bku"],"PK":["ur","pa-arab","en","lah","ps","sd-arab","skr","bal","brh","hno","fa","hnd","tg-arab","gju","bft","kvx","khw","mvy","kxp","gjk","ks-arab","btv"],"PL":["pl","szl","be","uk","csb","de","sli","lt"],"PM":["fr","en"],"PN":["en"],"PR":["es","en"],"PS":["ar"],"PT":["pt","gl"],"PW":["pau","en"],"PY":["gn","es","de"],"QA":["ar","fa","ml"],"RE":["fr","rcf","ta"],"RO":["ro","hu","de","tr","sr-latn","bg","el","pl"],"RS":["sr-cyrl","sr-latn","sq","hu","ro","hr","sk","uk"],"RU":["ru","tt","ba","cv","hy","ce","av","udm","chm","sah","os","kbd","myv","dar","bua","mdf","kum","kv","lez","krc","inh","tyv","az-cyrl","ady","krl","lbe","koi","mrj","alt","fi","sr-latn","vep","mn-cyrl","izh","cu"],"RW":["rw","fr","en"],"SA":["ar"],"SB":["en","rug"],"SC":["crs","fr","en"],"SD":["ar","en","nus","ha-arab"],"SE":["sv","fi","fit","se","rmu","yi","smj","sma","ia"],"SG":["en","zh-hans","ms-latn","ta","ml","pa-guru"],"SH":["en"],"SI":["sl","hu","it"],"SJ":["nb","ru"],"SK":["sk","hu","uk","pl","de"],"SL":["kri","en","men","tem"],"SM":["it","eo"],"SN":["wo","fr","ff","srr","dyo"],"SO":["so","ar","sw","om"],"SR":["nl","srn","zh-hant"],"SS":["ar","en"],"ST":["pt"],"SV":["es"],"SX":["en","es","vic","nl"],"SY":["ar","ku-latn","fr","hy","syr"],"SZ":["en","ss","zu","ts"],"TA":["en"],"TC":["en"],"TD":["fr","ar"],"TF":["fr"],"TG":["fr","ee"],"TH":["th","tts","nod","sou","mfa","zh-hant","kxm","kdt","mnw","shn","lcp","lwl"],"TJ":["tg-cyrl","ru","fa","ar"],"TK":["en","tkl"],"TL":["pt","tet"],"TM":["tk-latn","ru","uz-latn","ku-latn"],"TN":["aeb","ar","fr"],"TO":["to","en"],"TR":["tr","ku-latn","zza","kbd","az-latn","ar","bgx","bg","ady","kiu","hy","ka","sr-latn","lzz-latn","sq","ab","el","tru","uz-latn","ky-latn","kk-cyrl"],"TT":["en","es"],"TV":["tvl","en"],"TW":["zh-hant","trv"],"TZ":["sw","en","suk","nym","kde","bez","ksb","mas","mgy","asa","lag","jmc","rof","vun","rwk","sbp"],"UA":["uk","ru","pl","yi","rue","be","ro","bg","tr","hu","el"],"UG":["sw","lg","nyn","cgg","xog","en","teo","laj","ach","myx","rw","ttj","hi"],"UM":["en"],"US":["en","es","zh-hant","fr","de","fil","it","vi","ko","ru","nv","yi","pdc","haw","frc","chr","esu","lkt","ik"],"UY":["es"],"UZ":["uz-latn","uz-cyrl","ru","kaa","tr"],"VA":["it","la"],"VC":["en"],"VE":["es"],"VG":["en"],"VI":["en"],"VN":["vi","zh-hant","cjm"],"VU":["bi","en","fr"],"WF":["wls","fr","fud"],"WS":["sm","en"],"XK":["sq","aln","sr-cyrl","sr-latn"],"YE":["ar"],"YT":["swb","fr","buc","sw"],"ZA":["en","zu","xh","af","nso","tn","st","ts","ss","ve","hi","nr","sw"],"ZM":["en","bem","ny","loz"],"ZW":["en","sn","nd","mxc","ndc","kck","ny","ve","tn"],"ZZ":[]}};
7 | } ( jQuery ) );
8 |
--------------------------------------------------------------------------------