Full Code of ldidry/lstu for AI

master d9ca70e87797 cached
134 files
787.2 KB
249.0k tokens
13 symbols
1 requests
Download .txt
Showing preview only (832K chars total). Download the full file or copy to clipboard to get everything.
Repository: ldidry/lstu
Branch: master
Commit: d9ca70e87797
Files: 134
Total size: 787.2 KB

Directory structure:
gitextract_qiht013d/

├── .dockerignore
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── .provision/
│   ├── README.md
│   ├── ansible-role-lstu/
│   │   ├── README.md
│   │   ├── handlers/
│   │   │   └── main.yml
│   │   ├── tasks/
│   │   │   ├── apprun.yaml
│   │   │   ├── dependencies.yaml
│   │   │   ├── gitclone.yaml
│   │   │   └── main.yml
│   │   ├── templates/
│   │   │   ├── app.conf
│   │   │   └── lstu.conf.j2
│   │   └── vars/
│   │       └── main.yml
│   └── terraform-aws-lstu/
│       ├── README.md
│       ├── lstu_startup.sh
│       ├── main.tf
│       ├── output.tf
│       ├── provider.tf
│       └── vars.tf
├── .weblate
├── AUTHORS.md
├── CHANGELOG
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cpanfile
├── cpanfile.snapshot
├── docker/
│   └── entrypoint.sh
├── docker-compose.dev.yml
├── docker-compose.yml
├── docker-stack.yml
├── hooks/
│   └── build
├── lib/
│   ├── Lstu/
│   │   ├── Command/
│   │   │   ├── ban.pm
│   │   │   ├── safebrowsingcheck.pm
│   │   │   ├── theme.pm
│   │   │   └── url.pm
│   │   ├── Controller/
│   │   │   ├── Admin.pm
│   │   │   ├── Authent.pm
│   │   │   ├── Stats.pm
│   │   │   └── URL.pm
│   │   ├── DB/
│   │   │   ├── Ban/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   ├── Ban.pm
│   │   │   ├── Session/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   ├── Session.pm
│   │   │   ├── URL/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   └── URL.pm
│   │   ├── DefaultConfig.pm
│   │   └── Plugin/
│   │       ├── Headers.pm
│   │       └── Helpers.pm
│   ├── Lstu.pm
│   └── Mounter.pm
├── lstu.conf.template
├── script/
│   ├── application
│   └── lstu
├── t/
│   ├── lstu.passwd
│   ├── mysql1.conf
│   ├── mysql2.conf
│   ├── mysql3.conf
│   ├── postgresql1.conf
│   ├── postgresql2.conf
│   ├── postgresql3.conf
│   ├── sqlite1.conf
│   ├── sqlite2.conf
│   ├── sqlite3.conf
│   └── test.t
├── themes/
│   ├── default/
│   │   ├── lib/
│   │   │   └── Lstu/
│   │   │       ├── I18N/
│   │   │       │   ├── br.po
│   │   │       │   ├── de.po
│   │   │       │   ├── en.po
│   │   │       │   ├── es.po
│   │   │       │   ├── fr.po
│   │   │       │   ├── fr_FR.po
│   │   │       │   ├── hr.po
│   │   │       │   ├── lstu.pot
│   │   │       │   ├── oc.po
│   │   │       │   ├── pt_BR.po
│   │   │       │   └── sv.po
│   │   │       └── I18N.pm
│   │   ├── public/
│   │   │   ├── browserconfig.xml
│   │   │   ├── css/
│   │   │   │   ├── animation.css
│   │   │   │   ├── bootstrap-lstu.min.css
│   │   │   │   ├── bootstrap.min.css
│   │   │   │   ├── fontelico-codes.css
│   │   │   │   ├── fontelico-embedded.css
│   │   │   │   ├── fontelico-ie7-codes.css
│   │   │   │   ├── fontelico-ie7.css
│   │   │   │   ├── fontelico.css
│   │   │   │   ├── fontelico.min.css
│   │   │   │   └── lstu.css
│   │   │   ├── font/
│   │   │   │   └── licenses/
│   │   │   │       ├── Apache License.txt
│   │   │   │       └── SIL Open Font License.txt
│   │   │   ├── fontello.json
│   │   │   └── manifest.json
│   │   └── templates/
│   │       ├── api.html.ep
│   │       ├── index.html.ep
│   │       ├── layouts/
│   │       │   └── default.html.ep
│   │       ├── login.html.ep
│   │       ├── logout.html.ep
│   │       ├── partial/
│   │       │   └── lstu.js.ep
│   │       └── stats.html.ep
│   └── milligram/
│       ├── Makefile
│       ├── lib/
│       │   └── Lstu/
│       │       ├── I18N/
│       │       │   ├── en.po
│       │       │   ├── fr.po
│       │       │   ├── milligram.pot
│       │       │   └── oc.po
│       │       └── I18N.pm
│       ├── public/
│       │   └── css/
│       │       ├── lstu.css
│       │       ├── lstu.min.css
│       │       ├── milli-lstu.min.css
│       │       ├── milligram.min.css
│       │       └── milligram.min.css.map
│       └── templates/
│           ├── index.html.ep
│           ├── layouts/
│           │   └── default.html.ep
│           └── stats.html.ep
└── utilities/
    ├── bootstrap.json
    ├── lstu-minion@.service
    ├── lstu.apache
    ├── lstu.default
    ├── lstu.init
    ├── lstu.nginx
    ├── lstu.service
    ├── lstu_upstart.conf
    ├── migrations/
    │   ├── mysql.sql
    │   ├── postgresql.sql
    │   └── sqlite.sql
    └── read_conf.pl

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
.cpan
.cpanm
.git
docker-compose.yml
local
log/*
lstu.conf
lstu.db

================================================
FILE: .gitattributes
================================================
zanata.xml merge=ours


================================================
FILE: .gitignore
================================================
.cpan
.cpanm
.*_history
local/*
cover_db/*
safebrowsing_db/*
.tx/*
*.db
*.db-shm
*.db-wal
*.db-journal
lstu.conf
*.swp
script/hypnotoad.pid
.zanata-cache/*
themes/*
themes/default/public/robots.txt
themes/milligram/public/robots.txt
!themes/default
!themes/default/*
!themes/milligram
!themes/milligram/*


================================================
FILE: .gitlab-ci.yml
================================================
image: hatsoftwares/lstu-test-ci:latest
stages:
  - tags
  - carton
  - carton_bdd
  - tests

variables:
  POSTGRES_DB: lstu_db
  POSTGRES_USER: lstu
  POSTGRES_PASSWORD: lstu_pwd
  MYSQL_DATABASE: lstu_db
  MYSQL_USER: lstu
  MYSQL_PASSWORD: lstu_pwd
  MYSQL_ROOT_PASSWORD: root

before_script:
  - if [[ $CI_JOB_NAME == "postgresql 3/3" ]]; then export PGPASSWORD=lstu_pwd; echo 'CREATE DATABASE lstu_minion WITH OWNER lstu;' | psql -h postgres -U lstu lstu_db; fi
  - if [[ $CI_JOB_NAME == "mysql 3/3" ]]; then echo "CREATE DATABASE lstu_minion; GRANT ALL ON lstu_minion.* TO lstu@'%'; FLUSH PRIVILEGES;" | mysql -h mariadb -u root -proot; fi

### Jobs templates
##
#
.retry: &retry
  retry: 2
  except:
    - tags
.carton_bdd_template: &carton_bdd_definition
  <<: *retry
  stage: carton_bdd
  needs:
    - carton
  cache:
    key: "$CI_COMMIT_REF_NAME"
    paths:
      - local/
    policy: pull
  artifacts:
    paths:
      - local.tar
    expire_in: 3 hours
  after_script:
    - tar cf local.tar local/

.tests_template: &tests_definition
  <<: *retry
  stage: tests
  parallel: 3
  script:
    - tar xf local.tar && rm local.tar
    - export CI_JOB_NAME=$(echo $CI_JOB_NAME | sed -e 's@ .*@@')
    - echo "Database $CI_JOB_NAME test $CI_NODE_INDEX on $CI_NODE_TOTAL"
    - MOJO_CONFIG="t/${CI_JOB_NAME}${CI_NODE_INDEX}.conf" make test
    - MOJO_CONFIG="t/${CI_JOB_NAME}${CI_NODE_INDEX}.conf" make cover
    - MOJO_CONFIG="t/${CI_JOB_NAME}${CI_NODE_INDEX}.conf" make test-junit-output
  coverage: '/Total.* (\d+\.\d+)$/'
  artifacts:
    reports:
      junit: tap.xml

.sqlite_template: &sqlite_definition
  <<: *tests_definition
  needs:
    - carton_sqlite
  services:
    - name: rroemhild/test-openldap
      alias: rroemhild-test-openldap

.pg_template: &pg_definition
  <<: *tests_definition
  needs:
    - carton_postgresql
  services:
    - name: rroemhild/test-openldap
      alias: rroemhild-test-openldap
    - name: postgres:9.6
      alias: postgres

.mysql_template: &mysql_definition
  <<: *tests_definition
  needs:
    - carton_mysql
  services:
    - name: rroemhild/test-openldap
      alias: rroemhild-test-openldap
    - name: mariadb:10.1
      alias: mariadb

### Publish tag changelog
##
#
publish_changelog:
  image: hatsoftwares/curl-jq:latest
  stage: tags
  script:
    - export PROJECT_API_URL="https://framagit.org/api/v4/projects/${CI_PROJECT_ID}"
    - export DESCRIPTION_URL="${PROJECT_API_URL}/repository/tags/${CI_COMMIT_TAG}/release"
    - 'export HEADER="Private-Token: ${GITLAB_API_TOKEN}"'
    - sed -n '/^'$CI_COMMIT_TAG'[[:space:]]/,/^[^\t]/p' CHANGELOG | sed -e 's/^[^\t].*//' -e 's/\t//g' | sed '/^[[:space:]]*$/d' > /tmp/text
    - if [[ ! -z $GITLAB_API_TOKEN ]]; then curl -s --request POST --data-urlencode "description@/tmp/text" --header "${HEADER}" "${DESCRIPTION_URL}"; fi
  only:
    - tags

### Toot tag
##
#
pouet-it:
  image: hatsoftwares/pouet-it-from-ci:latest
  stage: tags
  script:
    - cd /opt/pouet-it-from-ci
    - export project="$(echo $CI_PROJECT_NAME | perl -p -e 's/(?:^(.)|-(.))/\U$1\U$2/g')"
    - export MESSAGE=$(echo -e "Je viens de sortir "'#'"${project} en version ${CI_COMMIT_TAG} !""\n${CI_PROJECT_URL}/tags/${CI_COMMIT_TAG}")
    - carton exec ./pouet-it-from-ci.pl
  only:
    - tags

### Podcheck
##
#
podcheck:
  <<: *retry
  stage: carton
  script:
    - make podcheck

### Install common dependencies
##
#
carton:
  <<: *retry
  stage: carton
  cache:
    key: "$CI_COMMIT_REF_NAME"
    paths:
      - local/
  script:
    - carton install --deployment --without=sqlite --without=postgresql --without=mysql

### Install DB related dependencies
##
#
carton_sqlite:
  <<: *carton_bdd_definition
  script:
    - carton install --deployment --without=postgresql --without=mysql
carton_postgresql:
  <<: *carton_bdd_definition
  script:
    - carton install --deployment --without=sqlite --without=mysql
carton_mysql:
  <<: *carton_bdd_definition
  script:
    - carton install --deployment --without=sqlite --without=postgresql

### Tests
##
#
sqlite:
  <<: *sqlite_definition
postgresql:
  <<: *pg_definition
mysql:
  <<: *mysql_definition


================================================
FILE: .provision/README.md
================================================
## ansible-role-lstu

An ansible role deploy the application on host machine(Ubuntu 20.04)

## terraform-aws-lstu

A terraform plan creates necessary AWS infrastructure and deploy the lstu. This terraform plan uses the `lstu_startup.sh` script to deploy application on AWS and also uses above ansible roles `ansible-role-lstu` to configure the application on AWS.

================================================
FILE: .provision/ansible-role-lstu/README.md
================================================
Ansible-Role-Lstu
=========
This role installs the and configures lstu on Debian/Ubuntu servers with nginx web server configuration.

Role Variables
-------------- 
| Variable name | Value | Description |
| ------------- | ----- | ----------- |
| `app_dir` | /var/www/lstu | Set the application directory for the best practice |
| `lstu_owner` | www-data | Set the application user for the best practice |
| `lstu_group` | www-data | Set the application group for the best practice |
| `_contact` | contact.example.com | contact option (mandatory), where you have to put some way for the users to contact you. |
| `_secret` | IWIWojnokd | secret  option (mandatory) array of random strings used to encrypt cookies |
| `_project_version` | master | We can chose the project version either Master branch, Dev branch or tag based |
| `_server_name` | IP address (or) CNAME/FQDN | Mention the Server Name for the Nginx configurations |

Sample example of use in a playbook
--------------

The following code has been tested with Ubuntu 20.04

```yaml
 
- name: "install lstu"
  hosts: enter your hosts file
  become: yes
  role:
    - ansible-role-lstu
  vars:
    lstu_owner: "www-data"
    lstu_group: "www-data"
    app_dir: "/var/www/lstu"
    _contact: "contact.example.com"
    _report: "report@example.com"
    _project_version: "master"
    _server_name: "IP address (or) CNAME/FQDN"
```   

Contributing
------------
Don’t hesitate to create a pull request











================================================
FILE: .provision/ansible-role-lstu/handlers/main.yml
================================================
---
# handlers file for ansible-role-lstu
- name: restart nginx
  service: name=nginx state=restarted


================================================
FILE: .provision/ansible-role-lstu/tasks/apprun.yaml
================================================
#apprun.yml
---
- name: This command will install the postgress module
  ansible.builtin.shell:
    cmd: carton install --deployment --without=test --without=sqlite --without=mysql
    chdir: "{{ app_dir }}"   

- name: Upload application file
  template:
    src: ../templates/lstu.conf.j2
    dest: "{{ app_dir }}/lstu.conf"

- name: Run the command for app_executes
  ansible.builtin.shell:
    cmd: carton exec hypnotoad script/lstu
    chdir: "{{ app_dir }}" 

- name: Nginx configuration file add
  template:
    src: ../templates/app.conf
    dest: /etc/nginx/conf.d/
    mode: '0644'
  notify: restart nginx

================================================
FILE: .provision/ansible-role-lstu/tasks/dependencies.yaml
================================================
#dependencies.yaml
---
- name: Lstu | Update apt cache
  ansible.builtin.apt: update_cache=yes 
  changed_when: no

- name: Install Dependencies
  ansible.builtin.apt:
   name:
     - nginx
     - carton
     - build-essential
     - libpng-dev
     - libssl-dev 
     - libpq-dev 
     - zlib1g-dev
     - libmojo-sqlite-perl  
   state: present
   

================================================
FILE: .provision/ansible-role-lstu/tasks/gitclone.yaml
================================================
#gitclone
---
- name: Clone the repository
  ansible.builtin.git:
    repo: 'https://framagit.org/luc/lstu.git'
    dest: "{{ app_dir }}"
    clone: yes
    update: yes
    version: "{{ _project_version }}"
    
- name: Change the owner 
  ansible.builtin.file:
    path: "{{ app_dir }}"
    owner: "{{ lstu_owner }}"
    group: "{{ lstu_group }}"
    state: directory
    recurse: yes





      




================================================
FILE: .provision/ansible-role-lstu/tasks/main.yml
================================================
---
# tasks file for ansible-role-lstu
- include: dependencies.yaml
- include: gitclone.yaml
- include: apprun.yaml

================================================
FILE: .provision/ansible-role-lstu/templates/app.conf
================================================
upstream lstu {
    server 127.0.0.1:8080;
}

server {
    listen 80; 
    listen [::]:80;

    server_name {{ _server_name }};

    access_log  /var/log/nginx/lstu.access.log;
    error_log   /var/log/nginx/lstu.error.log;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Remote-Port $remote_port;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://lstu;
        proxy_redirect http://lstu https://lstu.example.org;
    }
}


================================================
FILE: .provision/ansible-role-lstu/templates/lstu.conf.j2
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
{
    ####################
    # Hypnotoad settings
    ####################
    # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings
    hypnotoad => {
        # array of IP addresses and ports you want to listen to
        listen => ['http://0.0.0.0:8080'],
        # if you use Lstu behind a reverse proxy like Nginx, you want to set proxy to 1
        # if you use Lstu directly, let it commented
        #proxy  => 1,
    },

    # put a way to contact you here and uncomment it
    # MANDATORY
    contact       => '{{ _contact }}',

    # array of random strings used to encrypt cookies
    # optional, default is ['fdjsofjoihrei'], PLEASE, CHANGE IT
    secret        => ['{{ _secret }}'],

    # secret passphrase to access some admin features
    # If you don't want to have a plain text password in configuration,
    # use hashed_adminpwd instead
    # optional, but you won't have access to admin /stats if not set and if hashed_adminpwd is not set either
    #adminpwd      => 's3cr3T',

    # secret hashed passphrase to access some admin features
    # Hash your password by issuing `echo -n s3cr3T | sha256sum` on your terminal
    # optional, but you won't have access to admin /stats if not set and if adminpwd is not set either
    #hashed_adminpwd => '94b2feede6ea5e2eec62f457ecb7d3f719b24d19c29d4e5466246a31908fc23b',

    # choose a theme. See the available themes in `themes` directory
    # optional, default is 'default'
    #theme         => 'default',

    # number of URLs to be displayed per page in /stats
    # optional, default is 10
    #page_offset   => 10,

    # length of the random URL
    # optional, default is 8
    #length            => 8,

    # how many URLs will be provisioned in a batch ?
    # optional, default is 5
    #provis_step       => 5,

    # max number of URLs to be provisioned
    # optional, default is 100
    #provisioning      => 100,

    # URL sub-directory in which you want Lstu to be accessible
    # example: you want to have Lstu under https://example.org/lstu/
    # => set prefix to '/lstu' or to '/lstu/', it doesn't matter
    # optional, defaut is /
    #prefix        => '/',

    # array of authorized domains for API calls.
    # if you want to authorize everyone to use the API: ['*']
    # optional, no domains allowed by default
    #allowed_domains   => ['http://1.example.com', 'http://2.example.com'],

    # if set, the shortened URLs will use this domain
    # optional
    #fixed_domain => 'example.org',

    # choose what database you want to use
    # valid choices are sqlite, postgresql and mysql (all lowercase)
    # optional, default is sqlite
    #dbtype => 'sqlite',

    # SQLite ONLY - only used if dbtype is set to sqlite
    # define a path to the SQLite database
    # you can define it relative to lstu directory or set an absolute path
    # remember that it has to be in a directory writable by Lstu user
    # optional, default is lstu.db
    #db_path           => 'lstu.db',

    # PostgreSQL ONLY - only used if dbtype is set to postgresql
    # these are the credentials to access the PostgreSQL database
    # mandatory if you choosed postgresql as dbtype
    pgdb => {
        database => 'lstu',
        host     => 'localhost',
        # optional, default is 5432
        port     => 5432,
        user     => 'DBUSER',
        pwd      => 'DBPASSWORD',
        # optional, default is 1
        #max_connections => 1,
    },

    # MySQL ONLY - only used if dbtype is set to mysql
    # these are the credentials to access the MySQL database
    # mandatory if you choosed mysql as dbtype
    #mysqldb => {
    #    database => 'lstu',
    #    host     => 'localhost',
    #    # optional, default is 3306
    #    #port     => 3306,
    #    user     => 'DBUSER',
    #    pwd      => 'DBPASSWORD',
    #    # optional, default is 5 (set to 0 to disable persistent connections)
    #    #max_connections => 5,
    #},

    # Rate-limiting for the API
    # After ban_min_strike requests in a second, the IP address will be
    # banned for one hour.
    # If it continues to query the API during this ban time at least
    # ban_min_strike times, it will be banned for a month.
    # optional, default is 3
    #ban_min_strike    => 3,

    # Ban whitelist
    # You can whitelist IP addresses to prevent you from being banned
    # Be careful, the IP addresses are compared as string, not as IP addresses
    # a network range will not work
    # Example of valid input: ban_whitelist => ['198.51.100.42', '2001:0DB8::42'],¬
    # optional, default is an empty array
    #ban_whitelist => [],

    # Ban blacklist
    # You can blacklist IP addresses to always ban those IP addresses
    # Be careful, the IP addresses are compared as string, not as IP addresses
    # a network range will not work
    # Example of valid input: ban_blacklist => ['198.51.100.42', '2001:0DB8::42'],¬
    # optional, default is an empty array
    #ban_blacklist => [],

    # define an URL to the Piwik instance and the ID of a website to track
    # set if you want to track views in Piwik
    # optional, Piwik tracking is disabled by default
    #piwik => {
    #    url    => 'http://piwik.example.com',
    #    idsite => '1',
    #},

    # use Minion instead of directly increase counters
    # need to launch a minion worker service if enabled
    # optional, Minion is disabled by default
    # It will use the same DB type as Lstu: sqlite if you choose sqlite for `dbtype`,
    # postgresql for postgresql, etc.
    #minion => {
    #    enabled => 0,
    #    # SQLite ONLY - only used if if you choose sqlite as DB type,
    #    # define the path to the minion database
    #    # you can define it relative to lstu directory or set an absolute path
    #    # remember that it has to be in a directory writable by Lutim user
    #    # optional, default is minion.db
    #    db_path => 'minion.db',
    #    # PostgreSQL ONLY - only used if you choose postgresql as DB type
    #    # these are the credentials to access the Minion's PostgreSQL database
    #    # mandatory if you choosed postgresql as DB type, no default
    #    pgdb => {
    #        database => 'lstu_minion',
    #        host     => 'localhost',
    #        # optional, default is 5432
    #        port     => 5432,
    #        user     => 'DBUSER',
    #        pwd      => 'DBPASSWORD'
    #    },
    #    # MySQL ONLY - only used if you choose mysql as DB type
    #    # these are the credentials to access the Minion's MySQL database
    #    # mandatory if you choosed mysql as DB type, no default
    #    mysqldb => {
    #        database => 'lstu_minion',
    #        host     => 'localhost',
    #        # optional, default is 3306
    #        #port     => 3306,
    #        user     => 'DBUSER',
    #        pwd      => 'DBPASSWORD',
    #    },
    #},

    # set `ldap` if you want that only authenticated users can shorten URLs
    # please note that everybody can still use shortend URLs
    # optional, no default
    #ldap => {
    #    uri         => 'ldaps://ldap.example.org',                 # server URI
    #    user_tree   => 'ou=users,dc=example,dc=org',               # search base DN
    #    bind_dn     => 'uid=ldap_user,ou=users,dc=example,dc=org', # search bind DN
    #    bind_pwd    => 'secr3t',                                   # search bind password
    #    user_attr   => 'uid',                                      # user attribute (uid, mail, sAMAccountName, etc.)
    #    user_filter => '(!(uid=ldap_user))',                       # user filter (to exclude some users, etc.)
    #},

    # set `htpasswd` if you want to use an htpasswd file instead of ldap
    # create the file with `htpasswd -c lstu.passwd user`, update it with `htpasswd lstu.passwd user2`
    # make sure that lstu can read the file!
    # optional, no default
    #htpasswd => 'lstu.passwd',

    # if you've set ldap or htpasswd above, the session will last `session_duration` seconds before
    # the user needs to reauthenticate
    # optional, default is 3600
    #session_duration => 3600,

    # how many redirections are allowed for the shortened URL before considering it as a spam?
    # optional, default is 2. Set to -1 to allow infinite redirections (not recommended)
    #max_redir => 2,

    # spam blacklist regex. All URLs (or redirection) whose host part matches this regex are considered as spam
    # optional, no default
    #spam_blacklist_regex => 'foo|bar',

    # spam path blacklist regex. All URLs (or redirection) whose path part matches this regex are considered as spam
    # optional, no default
    #spam_path_blacklist_regex => 'foo|bar',

    # spam whitelist regex. All URLs (or redirection) whose host part matches this regex will never be considered as spam
    # optional, no default
    #spam_whitelist_regex => 'foo|bar',

    # set to 1 to skip SpamHaus check (not recommended)
    # optional, default is 0
    #skip_spamhaus => 0,

    # put your Google API key to enable Google safebrowsing check
    # This will allow Lstu to download the Google safebrowsing database and use a local copy to check the URLs.
    # Google does not get the URLs that are checked.
    # Instructions to get a key: https://developers.google.com/safe-browsing/v4/get-started
    # TL;DR: https://console.developers.google.com/projectselector/apis/library
    # optional, no default
    #safebrowsing_api_key => '',

    # array of memcached servers to cache URL in order to accelerate responses to often-viewed URL.
    # If set to [], the cache is disabled
    # optional, default is []
    #memcached_servers => [],

    # Content-Security-Policy header that will be sent by Lstu
    # Set to '' to disable CSP header
    # https://content-security-policy.com/ provides a good documentation about CSP.
    # https://report-uri.com/home/generate provides a tool to generate a CSP header.
    # optional, default is "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; form-action 'self'; base-uri 'self'"
    # the default value is good for `default` and `milligram` themes
    #csp => "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; form-action 'self'; base-uri 'self'",

    # X-Frame-Options header that will be sent by Lstu
    # Valid values are: 'DENY', 'SAMEORIGIN', 'ALLOW-FROM https://example.com/'
    # Set to '' to disable X-Frame-Options header
    # See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
    # Please note that this will add a "frame-ancestors" directive to the CSP header (see above) accordingly
    # to the chosen setting (See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors)
    # optional, default is 'DENY'
    #x_frame_options => 'DENY',

    # X-Content-Type-Options that will be sent by Lstu
    # See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
    # Set to '' to disable X-Content-Type-Options header
    # optional, default is 'nosniff'
    #x_content_type_options => 'nosniff',

    # X-XSS-Protection that will be sent by Lstu
    # See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
    # Set to '' to disable X-XSS-Protection header
    # optional, default is '1; mode=block'
    #x_xss_protection => '1; mode=block',

    # Log creator's IP address
    # Set to 1 if you want to register the IP addresses of URL creators
    # optional, default is 0
    #log_creator_ip => 0,
};


================================================
FILE: .provision/ansible-role-lstu/vars/main.yml
================================================
---
# vars file for ansible-role-lstu

lstu_owner: "www-data"

lstu_group: "www-data"

app_dir: "/var/www/lstu"

_contact: ""

_secret: ""

_project_version: ""

_server_name: ""


================================================
FILE: .provision/terraform-aws-lstu/README.md
================================================
# Terraform-AWS-Deploy

 This terraform plan create the resourcess of EC2 instance

## Terraform Variables
 Edit the `vars.tf` file to add the variables as per your need.

| Variable name | Value | Description |
| ------------- | ----- | ----------- |
| `aws_region` | us-east-1 | Set the region  |
| `vpc_cidr` | 10.0.0.0/16 | Set the cidr value for the vpc |
| `public_subnet_cidr` | 10.0.2.0/24 | Set the cidr value for the public subnet |
| `user` | ubuntu | Set the EC2 instance user name |
| `public_key` | /home/user_name/.ssh/id_rsa_pub | Set the publickey value for the ec2 instance from the host machine |
| `private_key` | /home/user_name/.ssh/id_rsa | Set the private key value for the ec2 instance from the hostmachine |
| `aws_access_key` | AWSACCESSKEY | Enter your aws access key |
| `aws_secrete_key` | AWSSECRETEKEY | Enter your aws secrete key |
| `instance_name` | lstu_app_instance | Set the name for instance |
| `app_dir` | /var/www/lstu | Set the application directory for the best practice |
| `lstu_owner` | www-data | Set the application user for the best practice |
| `lstu_group` | www-data | Set the application group for the best practice |
| `contact` | contact.example.com | contact option (mandatory), where you have to put some way for the users to contact you. |
| `secret` | IWIWojnokd | secret  option (mandatory) array of random strings used to encrypt cookies |
| `project_version` | master | We can chose the project version either Master branch, Dev branch or tag based |

## Usage of terraform plan with lstu deploy script

```sh 
git clone https://github.com/ldidry/lstu

cd lstu/.provision/terraform-aws-lstu

terraform init
terraform plan
terraform apply
```
## Usage of terraform plan with ansible role

- Comment out the below `data template` and `user_data` source in __main.tf__ file

```sh
data "template_file" "init" {
  template = file("./lstu_startup.sh")
  vars = {
    user = var.lstu_owner
    group = var.lstu_group
    directory = var.app_dir
    git_branch = var.project_version
    contact_lstu = var.contact
    secret_lstu = var.secret

  }
}
```
```sh
  user_data          = data.template_file.init.rendered
```

- Add the below provisioner data in __main.tf__ file at the `aws_instance` resource

```sh
  connection          {
    agent            = false
    type             = "ssh"
    host             = aws_instance.ec2_instance.public_dns 
    private_key      = "${file(var.private_key)}"
    user             = "${var.user}"
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt update -y",
      "sudo apt install python3.9 -y",
      ]
  }

  provisioner "local-exec" {
    command = <<EOT
      sleep 120 && \
      > hosts && \
      echo "[lstu]" | tee -a hosts && \
      echo "${aws_instance.ec2_instance.public_ip} ansible_user=${var.user} ansible_ssh_private_key_file=${var.private_key}" | tee -a hosts && \
      export ANSIBLE_HOST_KEY_CHECKING=False && \
      ansible-playbook -u ${var.user} --private-key ${var.private_key} -i hosts site.yaml
    EOT
  } 
 ``` 

================================================
FILE: .provision/terraform-aws-lstu/lstu_startup.sh
================================================
#!/bin/bash

echo "**********************************************************************"
echo "                                                                     *"
echo "Install dependencies                                                 *"
echo "                                                                     *"
echo "**********************************************************************"

SUDO=sudo
$SUDO apt update
$SUDO apt install jq -y
$SUDO apt install wget -y
$SUDO apt install unzip -y
$SUDO apt install carton -y
$SUDO apt install build-essential -y
$SUDO apt install nginx -y
$SUDO apt install libssl-dev -y
$SUDO apt install libpng-dev -y
$SUDO apt install libio-socket-ssl-perl -y
$SUDO apt install liblwp-protocol-https-perl -y
$SUDO apt install zlib1g-dev -y
$SUDO apt install libmojo-sqlite-perl -y
$SUDO apt install libpq-dev -y

echo "**********************************************************************"
echo "                                                                     *"
echo "Configuring the Application                                          *"
echo "                                                                     *"
echo "**********************************************************************"

sleep 10;
version=$(curl -s https://framagit.org/api/v4/projects/5/releases | jq '.[]' | jq -r '.name' | head -1)
echo $version
pushd ${directory} 
$SUDO wget https://framagit.org/fiat-tux/hat-softwares/lstu/-/archive/$version/lstu-$version.zip
$SUDO unzip lstu-$version.zip
$SUDO chown ${user} lstu-$version
$SUDO chgrp ${group} lstu-$version
pushd lstu-$version


echo "**********************************************************************"
echo "                                                                     *"
echo "Install Carton Packages                                              *"
echo "                                                                     *"
echo "**********************************************************************"

$SUDO carton install --deployment --without=test --without=sqlite --without=mysql

sleep 10;

$SUDO cp lstu.conf.template lstu.conf
$SUDO sed -i 's/127.0.0.1/0.0.0.0/'  lstu.conf
$SUDO sed -i 's/#contact/contact/g' lstu.conf
$SUDO sed -i "s/admin\[at]\example.com/${contact_lstu}/g" lstu.conf
$SUDO sed -i 's/#secret/secret/' -i lstu.conf
$SUDO sed -i "s/fdjsofjoihrei/${secret_lstu}/g" lstu.conf
$SUDO sed -i '89 , 91 s/#/ /g' lstu.conf
$SUDO sed -i '94 , 95 s/#/ /g' lstu.conf
$SUDO sed -i '98 s/#/ /g' lstu.conf




echo "**********************************************************************"
echo "                                                                     *"
echo "Run the Application                                                  *"
echo "                                                                     *"
echo "**********************************************************************"

$SUDO carton exec hypnotoad script/lstu



================================================
FILE: .provision/terraform-aws-lstu/main.tf
================================================
locals {
  user_data_vars = {
    user = var.lstu_owner
    group = var.lstu_group
    directory = var.app_dir
    contact_lstu = var.contact
    secret_lstu = var.secret 
  }
}

#Create the VPC 
resource "aws_vpc" "vpc" {
  cidr_block           = "${var.vpc_cidr}"
  enable_dns_hostnames = true 
  enable_dns_support   = true
  instance_tenancy     = "default"
  tags                 = {
      Name             = "lstu-master-vpc"
  }
}

# Create InternetGateWay and attach to VPC

resource "aws_internet_gateway" "IGW" {
  vpc_id           = "${aws_vpc.vpc.id}"
  tags = {
    "Name"         = "lstu-master-igw"
  } 
}

# Create a public subnet

resource "aws_subnet" "publicsubnet" {
  vpc_id                  = "${aws_vpc.vpc.id}" 
  cidr_block              = "${var.public_subnet_cidr}"
  map_public_ip_on_launch = true
  tags                    = {
      Name                = "lstu-master-us-east-1-public"
  }  
}

# Create routeTable
resource "aws_route_table" "publicroute" {
    vpc_id         = "${aws_vpc.vpc.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.IGW.id}"
    }
             
    tags           = {
      Name         = "lstu-master-us-east-1-public-rt"
 }
}

resource "aws_main_route_table_association" "mainRTB" {
  vpc_id         = "${aws_vpc.vpc.id}"
  route_table_id = "${aws_route_table.publicroute.id}"
}

## Create security group
resource "aws_security_group" "security" {
  name             = "lstu-master-sg"  
  description      = "allow all traffic"
  vpc_id           = "${aws_vpc.vpc.id}"

  ingress  {
    description    =  "allow all traffic"
    from_port      = "0"
    to_port        = "65535"  
    protocol       = "tcp"
    cidr_blocks    = ["0.0.0.0/0"]
  }
  ingress  {
    description    = "allow port SSH"
    from_port      = "22"
    to_port        = "22"
    protocol       = "tcp"
    cidr_blocks    = ["0.0.0.0/0"]
  }
  egress  {
    from_port      = 0
    to_port        = 0
    protocol       = "-1"
    cidr_blocks    = ["0.0.0.0/0"]
  }
  
}

# Add ubuntu AMI
data "aws_ami" "ubuntu" {
  most_recent = true
  owners = ["099720109477"]

    filter {
        name   = "name"
        values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
    }
}

#Create key_pair for the instance

resource "aws_key_pair" "genkey" {
  key_name           = "lstu.webapp"
  public_key         = "${file(var.public_key)}"
}

# Craete ec2 instance
resource "aws_instance" "ec2_instance" {
  ami                = "${data.aws_ami.ubuntu.id}"   
  instance_type      = "t2.medium"
  associate_public_ip_address = "true"
  subnet_id          = "${aws_subnet.publicsubnet.id}"
  vpc_security_group_ids = ["${aws_security_group.security.id}"]
  user_data          = templatefile("${path.module}/lstu_startup.sh", local.user_data_vars)
  key_name           = "lstu.webapp"
  
  tags               = {
    Name             = "${var.instance_name}"
  }
}

 




================================================
FILE: .provision/terraform-aws-lstu/output.tf
================================================
output "public_ip" {
  value = "${aws_instance.ec2_instance.public_ip}"
}

output "App_running_at" {
  value = "http://${aws_instance.ec2_instance.public_ip}:8080"
}


================================================
FILE: .provision/terraform-aws-lstu/provider.tf
================================================
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region     = "${var.aws_region}" 
}

================================================
FILE: .provision/terraform-aws-lstu/vars.tf
================================================
variable "aws_region" {
    default = "aws_region"
}
variable "vpc_cidr" {
    default = "cidr_value"
}
variable "public_subnet_cidr" {
    default = "cidr_value"
}
variable "public_subnet1_cidr" {
    default = "cidr_value"
}

variable "user" {
    default = "user_of_instance" 
}

variable "public_key" {
    default = "$PWD_publickey"
}
variable "private_key" {
    default = "$PWD_privatekey"
}
variable "aws_access_key" {
    default = "aws_access_key"
}

variable "aws_secret_key" {
    default = "aws_secret_key"
}

variable "instance_name" {
    default = "lstu"  
}

variable "lstu_owner" {
    default = ""  
}

variable "lstu_group" {
    default = ""  
}

variable "app_dir" {
    default = ""  
}

variable "project_version" {
    default = ""  
}

variable "contact" {
    default = ""  
}

variable "secret" {
    default = ""  
}




================================================
FILE: .weblate
================================================
[weblate]
url = https://weblate.framasoft.org/api/
translation = lstu


================================================
FILE: AUTHORS.md
================================================
# Lstu's authors

## Main developer

* Luc Didry, aka Sky (<https://fiat-tux.fr>), core developer, framasky@framasphere.org on [Diaspora*](https://framasphere.org/public/framasky)

## Contributors

* Benjamin Bouvier
* Armando Lüscher
* Quentin Pagès (occitan translation)
* Phyks (Lucas Verney)
* Pierre Rudloff
* Belvar (Gwenn M) (breton translation)
* Ira W. Snyder
* Arnaud de Mouhy (docker port)
* Mathieu Aubin
* frju365 (Julien Gomes Dias)
* Arunodhayam Sam (IaC and ConfigManagement)

================================================
FILE: CHANGELOG
================================================
Revision history for Perl application Lstu

0.29-0 ????-??-??

0.28-0 2023-12-17
	- ⬆️ Update dependencies
	- 💥 BREAKING CHANGE: Use `?_format=json` instead of `?format=json`
	- 💥 BREAKING CHANGE: Use `?_format=json` instead of terminating the URL with `.json`

0.27-0 2023-01-11
	- 🐛 Fix length of ip column for MySQL (#64)
	- 🔥 Remove everything about browser extensions (#98)
	- 🌐 Update translations

0.26-0 2022-05-23
	- ✨ Add a config setting to change QR code size

0.25-0 2022-05-09
	- ✨ Add a config flag to disable API
	- ⚡ Use a HEAD request instead of a GET when checking for redirections
	- 🐛 Handle disabled URLs in `url` CLI command

0.24-0 2022-04-26
	- ✨ Allow to sort results in admin stats page (#91)
	- Fix disabled URLs still showing in admin interface (#79)
	- Make a distinction between inexistant and disabled URLs

0.23-0 2021-04-26
	- Update translations
	- Improve tests
	- Improve CI
	- Upgrade some dependencies

0.22-0 2019-11-08
	- Disable URLs instead of removing them (prevents spammers to reuse a
	  deleted shortened URL)
	- Slugify custom URLs and add a suffix (-2, -3…) if the custom URL is
	  already taken
	- Allow to search several IP addresses at once
	- New logo and update theme!
	- Now use https://weblate.framasoft.org/projects/lstu for translations

0.21-4 2018-12-17
	- Add a lockfile to GSB database update to prevent concurrent updates

0.21-3 2018-11-19
	- Fix Pg sessions and urls delete fonctions

0.21-2 2018-11-19
	- Fix URL removal in memcached from safebrowsingcheck and url commands

0.21-1 2018-10-17
	- Fix URL removal in memcached from safebrowsingcheck command

0.21-0 2018-10-17
	- Allow to delete URLs and ban IPs from safebrowsingcheck
	- Add ban CLI tool for banning and unbanning IP addresses

0.20-2 2018-10-07
	- Handle very long URLs

0.20-1 2018-09-20
	- Fix safebrowsingcheck CLI help message

0.20-0 2018-09-20
	- Docker port, thanks to Arnaud de Mouhy
	- Improve safebrowsingcheck CLI:
	  - displays creators' IP addresses + other URLs from thoses IPs
	  - allow to specify URLs to check
	  - allow to check URLs created <argument> seconds ago

0.19-3 2018-09-08
	- Update translations

0.19-2 2018-09-08
	- Improve GSB object creation and GSB DB update

0.19-1 2018-09-08
	- Update translations

0.19-0 2018-09-08
	- Allow to use Google Safe Browsing database to check if the URLs are harmless
	  It uses a local copy of the GSB DB, so Google won't see the URLs to shorten
	- safebrowsingcheck CLI to check all the URLs in the database against GSB DB.
	  usage: carton exec script/lstu safebrowsingcheck
	- Fix bugs (#45)

0.18-1 2018-08-21
	- Update url CLI help message

0.18-0 2018-08-20
	- Add option to store IP address of URL creator
	- Add command to search URL with the IP address of its creator
	- Add option to blacklist IP address
	- Allow to remove multiple URLs at once with the CLI

0.17-3 2018-08-20
	- Fix missing default db_path

0.17-2 2018-05-15
	- Add ability to respond to /robots.txt either by sending the file if it exists or by answering 404

0.17-1 2018-04-28
	- Fix bug in making LDAP and Htpasswd dependencies optional

0.17 2018-04-28
	- Import URL into cookie by JSON upload
	- Add X-Content-Type-Options, X-XSS-Protection and X-Frame-Options headers
	- More dependencies become optional to install
	- Some refactoring
	- Add LDAP tests to test suite

0.16-1 2018-04-27
	- Fix bug in LDAP authentication

0.16 2018-04-24
	- Add Content-Security-Policy header
	- Use Memcached for cache system (previous cache was unstable)

0.15-2 2018-04-23
	- Update Mojolicious::Plugin::GzipStatic

0.15-1 2018-04-23
	- Fix url command help function

0.15 2018-04-23
	- Add CLI command to search and delete url
	- Fix CI

0.14-1 2018-04-23
	- Fix for PostgreSQL and MySQL connections

0.14 2018-04-22
	- Use same DB backend for Minion than db_type

0.13-1 2018-04-22
	- Better CSS minification

0.13 2018-04-22
	- Gzip static assets with Mojolicious::Plugin::GzipStatic (increase page load speed)
	- Other page load speed improvements

0.12-1 2018-04-22
	- Force Mojo::SQLite version

0.12 2018-04-22
	- Improve LDAP User Authentication Support (beware of configuration changes!) <Ira W.  Snyder>
	- Allow users to configure maximum number of database connections <Ira W.  Snyder>
	- Use CHI for cache system
	- Move some tasks to recurring instead of being in after_dispatch hook
	- Allow to install only deps related to one DB instead of all supported DBs
	- Use Mojo::SQLite instead of ORLite
	- Better CI
	- Put documentation on the wiki (https://framagit.org/luc/lstu/wikis/home)
	- Update dependencies
	- Fix bugs

0.11-2 2018-03-22
	- Update packages dependencies in README
	- Fix CI

0.11-1 2018-03-22
	- Update dependencies

0.11 2018-03-22
	- Add home link to stats page
	- Fix copy-to-clipboard button
	- Option to blacklist URLs whose path part matches the configured regex

0.10 2018-02-22
	- Performance improvments (cache + assets minification)
	- Add /stats/:short API endpoint
	- Update API page
	- Zanata integration (https://trad.framasoft.org)

0.09-2 2017-09-05
	- Handle redirections without host

0.09-1 2017-09-05
	- Handle redirections without host

0.09 2017-09-05
	- Add QRcode generation
	- Option to disable the spamhaus check (#29)
	- Option to blacklist and/or whitelist domains (#30)
	- Option to set the maximum number of redirections (#31)
	- Instance statistics available at /fullstats URL
	- Now return 404 status for non-existent URLs

0.08 2017-02-08
	- Add Piwik tracking option
	- Add Minion option for async counters increasing
	- Add LDAP and Htpasswd authentication (#8)
	- Add Database abstraction layer
	- Add PostgreSQL (#21)
	- Allow to run several Lstu's instances from the same code but with
	  different configuration files (#23)
	- Cache dependencies for the different stages of the CI
	- Allow whitelisted IPs to bypass anti-spam/anti-bruteforce systems (#24)
	- Add breton translation

0.07 2016-12-20
	- Add logo
	- Add theme system
	- Better Spamhaus checking
	- Add ban system
	- Add occitan translation
	- Add Milligram theme
	- Add cache system
	- Add hashed_adminpwd option

0.06 2015-09-04
	- Add Spamhaus checking before accepting the URL
	- Fix small bug

0.05 2015-07-31
	- Add copy-to-clipboard button (#1)
	- Add test suite
	- Add Net::Domain::TLD >= 1.73 as dependancy

0.04 2015-06-10
	- Change internationalization system (.po files now)
	- Fixed domain for shortened URLs system (#12)
	- Fix XSS vulnerability (#15)
	- Subdirectory mounting system (#16)
	- Show your URLs ("stats") page
	- Show all URLs page for admin (#11)
	- API description page
	- API change
	- Self-documented configuration template
	- add doc and templates for systemd and sysVinit
	- add template for nginx

0.03 2013-09-25
	- FIX #5 again by using transactions

0.02 2013-09-24
	- use of morbo or hypnotoad servers availables
	- use of config file
	- FIX #1 : GET parameters deleted when using /a/*url route
	- FIX #2 : Can't use morbo or hypnotoad
	- FIX #3 : Internationalization
	- FIX #5 : Scalability issues

0.01 2013-09-21
	- original version;


================================================
FILE: CONTRIBUTING.md
================================================
# How to contribute?

The official git repository is <https://framagit.org/fiat-tux/hat-softwares/lstu>.

You can create an account on Framagit with your Github/Gitlab/Bitbucket account.

## Issues

Please, post any issue on <https://framagit.org/fiat-tux/hat-softwares/lstu/issues>.

## Merge requests

Please, post any merge request on <https://framagit.org/fiat-tux/hat-softwares/lstu/merge_requests>.

For your merge request to be accepted, please:
- use 4 spaces for indentation
- add yourself to [AUTHORS.md](AUTHORS.md)
- be sure that it passed the automated tests before submitting the MR
- [squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)


================================================
FILE: Dockerfile
================================================
FROM alpine:3.19

ARG BUILD_DATE
ARG VCS_REF
ARG VERSION
LABEL org.label-schema.build-date=$BUILD_DATE \
      org.label-schema.name="Let's Shorten That URL" \
      org.label-schema.url="https://lstu.fr/" \
      org.label-schema.vcs-ref=$VCS_REF \
      org.label-schema.vcs-url="https://framagit.org/fiat-tux/hat-softwares/lstu" \
      org.label-schema.vendor="Luc Didry" \
      org.label-schema.version=$VERSION \
      org.label-schema.schema-version="1.0"

RUN adduser -D lstu
COPY --chown=lstu:lstu . /home/lstu
WORKDIR /home/lstu
RUN apk --update add ca-certificates perl perl-netaddr-ip perl-io-socket-ssl perl-dbd-pg mariadb-connector-c-dev libpng zlib openssl perl-dbd-mysql
RUN apk add --virtual .build-deps build-base perl-utils perl-dev make sudo zlib-dev libpng-dev postgresql-dev mariadb-dev openssl-dev
RUN cpan -T Carton
RUN sudo -u lstu carton install --deployment --without=test --without=cache
RUN perl -MCPAN -e 'install inc::latest'
RUN perl -MCPAN -e 'install Config::FromHash'
RUN apk del .build-deps
RUN rm -rf /var/cache/apk/*
USER lstu

ENTRYPOINT ["/bin/sh", "/home/lstu/docker/entrypoint.sh"]


================================================
FILE: LICENSE
================================================
        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
                    Version 2, December 2004 

 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 

 Everyone is permitted to copy and distribute verbatim or modified 
 copies of this license document, and changing it is allowed as long 
 as the name is changed. 

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 

  0. You just DO WHAT THE FUCK YOU WANT TO.


================================================
FILE: Makefile
================================================
EXTRACTDIR=-D lib -D themes/default/templates
POT=themes/default/lib/Lstu/I18N/lstu.pot
XGETTEXT=carton exec local/bin/xgettext.pl
CARTON=carton exec
REAL_LSTU=script/application
LSTU=script/lstu
HARNESS_PERL_SWITCHES=-MDevel::Cover=+ignore,local

minify:
	@echo "CSS concatenation"
	@cd ./themes/default/public/css/   && cat bootstrap.min.css lstu.css fontelico.css | csso > bootstrap-lstu.min.css
	@cd ./themes/milligram/public/css/ && cat milligram.min.css lstu.css ../../../default/public/css/fontelico.css | csso > milli-lstu.min.css

locales:
	$(XGETTEXT) $(EXTRACTDIR) -o $(POT) 2>/dev/null
	cd ./themes/milligram && make locales

podcheck:
	podchecker lib/Lstu/DB/*pm lib/Lstu/Command/*pm

check-syntax:
	find lib/ themes/ -name \*.pm -exec carton exec perl -Ilib -c {} \;
	find t/ -name \*.t -exec carton exec perl -Ilib -c {} \;

cover:
	PERL5OPT='-Ilib/' $(CARTON) cover --ignore_re '^local'

test:
	@PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' $(CARTON) prove --comments --failures

test-junit-output:
	@PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' $(CARTON) prove --comments --failures --formatter TAP::Formatter::JUnit > tap.xml

test-sqlite:
	@rm -rf test1.db test1.db-journal cover_db/
	@echo 'MOJO_CONFIG=t/sqlite1.conf'
	@PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' MOJO_CONFIG=t/sqlite1.conf $(CARTON) prove --comments --failures
	@PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' $(CARTON) cover --ignore_re '^local'

run-ldap-container:
	podman run -d --name rroemhild-test-openldap -p 127.0.0.1:10389:10389 docker.io/rroemhild/test-openldap

dev: minify
	$(CARTON) morbo $(LSTU) --listen http://0.0.0.0:3000 --watch lib/ --watch script/ --watch themes/ --watch lstu.conf

devlog:
	multitail log/development.log

minion:
	$(CARTON) $(REAL_LSTU) minion worker

installdeps:
	carton install

updatedeps:
	carton update


================================================
FILE: README.md
================================================
# Lstu

## What does Lstu mean?

It means Let's Shorten That Url.

## License

Lstu is licensed under the terms of the WTFPL. See the LICENSE file.

## Installation

Please, see the [wiki](https://framagit.org/fiat-tux/hat-softwares/lstu/wikis/home).

Or you can see [usage with Docker](https://framagit.org/fiat-tux/hat-softwares/lstu/wikis/usage-with-docker).

## How many URLs can it handle ?

By default, there are 8 361 453 672 available combinations.

I think the sqlite db will explode before you reach this limit, but you can use PostgreSQL or MySQL as database instead of SQLite.

If you want more shortened URLs than that, open `lstu.conf` and change the `length` setting.

Every time somebody uses Lstu, it will create 'waiting' shortened URLs codes in order to be quick to shorten the URLs.

Accordingly to the `lstu.conf` configuration file, it will create `provisioning` waiting URLs, adding them `provis_step` by `provis_step`.

## Official instance

You can see it working and use it at <https://lstu.fr>.

## API

See <https://lstu.fr/api>.
Your instance will provide the same page with your URL.

## Contributing

See the [contributing guidelines](CONTRIBUTING.md).

## Other projects dependencies

Lstu is written in Perl with the Mojolicious framework and uses [Milligram](https://milligram.io/) CSS framework to look not too ugly.

## Authors

See the [AUTHORS.md](AUTHORS.md) file.

## Deploy Lstu

An ansible role and a terraform plan reside under the `.provision` directory. An user could utilize the terraform plan if they chose to deploy lstu on AWS, if that's not the goal, they could simply execute the ansible role in part. Usage docs for both are present in their respective directories.


================================================
FILE: cpanfile
================================================
requires 'inc::Module::Install::DSL';
requires 'Mojolicious', '>= 8.09';
requires 'Data::Validate::URI';
requires 'Net::Domain::TLD', '>= 1.74';
requires 'Mojolicious::Plugin::I18N';
requires 'Mojolicious::Plugin::DebugDumperHelper';
requires 'Mojolicious::Plugin::Piwik';
requires 'Mojolicious::Plugin::StaticCache';
requires 'Mojolicious::Plugin::GzipStatic';
requires 'Mojolicious::Plugin::CSPHeader', '>= 0.03';
requires 'Minion';
requires 'Locale::Maketext';
requires 'Locale::Maketext::Extract';
requires 'Net::Abuse::Utils::Spamhaus';
requires 'Net::DNS', '>= 1.12';
requires 'Net::SSLeay', '>= 1.81';
requires 'IO::Socket::SSL';
requires 'Image::PNG::QRCode';
requires 'Cpanel::JSON::XS';

feature 'ldap', 'LDAP authentication support' => sub {
    requires 'Net::LDAP';
    requires 'Mojolicious::Plugin::Authentication';
};
feature 'htpasswd', 'Htpasswd authentication support' => sub {
    requires 'Apache::Htpasswd';
    requires 'Mojolicious::Plugin::Authentication';
};
feature 'cache', 'URL cache system' => sub {
    requires 'Mojolicious::Plugin::CHI';
    requires 'CHI::Driver::Memcached';
    requires 'Cache::Memcached';
};
feature 'test' => sub {
    requires 'Devel::Cover', '>= 1.36';
};
feature 'sqlite', 'SQLite support' => sub {
    requires 'Mojo::SQLite', '>= 3.000';
    requires 'Minion::Backend::SQLite', '>= 4.001';
};
feature 'postgresql', 'PostgreSQL support' => sub {
    requires 'Mojo::Pg';
    requires 'Mojolicious::Plugin::PgURLHelper';
};
feature 'mysql', 'MySQL support' => sub {
    requires 'Mojo::mysql', '>= 1.22';
    requires 'Minion::Backend::mysql';
    requires 'Mojolicious::Plugin::PgURLHelper';
};

feature 'safebrowsing', 'Check URLs against Google safebrowsing database' => sub {
    requires 'Net::Google::SafeBrowsing4', '>= 0.8';
    requires 'Term::ProgressBar::Quiet';
};


================================================
FILE: cpanfile.snapshot
================================================
# carton snapshot format: version 1.0
DISTRIBUTIONS
  Apache-Htpasswd-1.9
    pathname: K/KM/KMELTZ/Apache-Htpasswd-1.9.tar.gz
    provides:
      Apache::Htpasswd 1.9
    requirements:
      Crypt::PasswdMD5 0
      Digest::SHA 2
      ExtUtils::MakeMaker 0
      MIME::Base64 0
  Authen-SASL-2.1700
    pathname: E/EH/EHUELS/Authen-SASL-2.1700.tar.gz
    provides:
      Authen::SASL 2.1700
      Authen::SASL::CRAM_MD5 2.1700
      Authen::SASL::EXTERNAL 2.1700
      Authen::SASL::Perl 2.1700
      Authen::SASL::Perl::ANONYMOUS 2.1700
      Authen::SASL::Perl::CRAM_MD5 2.1700
      Authen::SASL::Perl::DIGEST_MD5 2.1700
      Authen::SASL::Perl::EXTERNAL 2.1700
      Authen::SASL::Perl::GSSAPI 2.1700
      Authen::SASL::Perl::LOGIN 2.1700
      Authen::SASL::Perl::PLAIN 2.1700
    requirements:
      Digest::HMAC_MD5 0
      Digest::MD5 0
      ExtUtils::MakeMaker 0
      perl 5.006000
  B-Hooks-EndOfScope-0.26
    pathname: E/ET/ETHER/B-Hooks-EndOfScope-0.26.tar.gz
    provides:
      B::Hooks::EndOfScope 0.26
      B::Hooks::EndOfScope::PP 0.26
      B::Hooks::EndOfScope::XS 0.26
    requirements:
      ExtUtils::MakeMaker 0
      Hash::Util::FieldHash 0
      Module::Implementation 0.05
      Scalar::Util 0
      Sub::Exporter::Progressive 0.001006
      Text::ParseWords 0
      Tie::Hash 0
      Variable::Magic 0.48
      perl 5.006001
      strict 0
      warnings 0
  CHI-0.61
    pathname: A/AS/ASB/CHI-0.61.tar.gz
    provides:
      CHI 0.61
      CHI::CacheObject 0.61
      CHI::Driver 0.61
      CHI::Driver::Base::CacheContainer 0.61
      CHI::Driver::CacheCache 0.61
      CHI::Driver::FastMmap 0.61
      CHI::Driver::File 0.61
      CHI::Driver::Memory 0.61
      CHI::Driver::Metacache 0.61
      CHI::Driver::Null 0.61
      CHI::Driver::RawMemory 0.61
      CHI::Driver::Role::HasSubcaches 0.61
      CHI::Driver::Role::IsSizeAware 0.61
      CHI::Driver::Role::IsSubcache 0.61
      CHI::Stats 0.61
    requirements:
      Carp::Assert 0.20
      Class::Load 0
      Data::UUID 0
      Digest::JHash 0
      Digest::MD5 0
      ExtUtils::MakeMaker 0
      File::Spec 0.80
      Hash::MoreUtils 0
      JSON::MaybeXS 1.003003
      List::MoreUtils 0.13
      Log::Any 0.08
      Moo 1.003
      MooX::Types::MooseLike 0.23
      MooX::Types::MooseLike::Base 0
      MooX::Types::MooseLike::Numeric 0
      Storable 0
      String::RewritePrefix 0
      Task::Weaken 0
      Time::Duration 1.06
      Time::Duration::Parse 0.03
      Time::HiRes 1.30
      Try::Tiny 0.05
  CHI-Driver-Memcached-0.16
    pathname: J/JS/JSWARTZ/CHI-Driver-Memcached-0.16.tar.gz
    provides:
      CHI::Driver::Memcached 0.16
      CHI::Driver::Memcached::Base 0.16
      CHI::Driver::Memcached::Fast 0.16
      CHI::Driver::Memcached::libmemcached 0.16
    requirements:
      CHI 0.33
      ExtUtils::MakeMaker 0
      Moose 0.66
  Cache-Memcached-1.30
    pathname: D/DO/DORMANDO/Cache-Memcached-1.30.tar.gz
    provides:
      Cache::Memcached 1.30
      Cache::Memcached::GetParser undef
    requirements:
      Encode 0
      ExtUtils::MakeMaker 0
      Storable 0
      String::CRC32 0
      Time::HiRes 0
  Canary-Stability-2013
    pathname: M/ML/MLEHMANN/Canary-Stability-2013.tar.gz
    provides:
      Canary::Stability 2013
    requirements:
      ExtUtils::MakeMaker 0
  Capture-Tiny-0.48
    pathname: D/DA/DAGOLDEN/Capture-Tiny-0.48.tar.gz
    provides:
      Capture::Tiny 0.48
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 6.17
      File::Spec 0
      File::Temp 0
      IO::Handle 0
      Scalar::Util 0
      perl 5.006
      strict 0
      warnings 0
  Carp-Assert-0.22
    pathname: Y/YV/YVES/Carp-Assert-0.22.tar.gz
    provides:
      Carp::Assert 0.22
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      perl 5.006
      strict 0
      vars 0
      warnings 0
  Class-Load-0.25
    pathname: E/ET/ETHER/Class-Load-0.25.tar.gz
    provides:
      Class::Load 0.25
      Class::Load::PP 0.25
    requirements:
      Carp 0
      Data::OptList 0.110
      Exporter 0
      ExtUtils::MakeMaker 0
      Module::Implementation 0.04
      Module::Runtime 0.012
      Package::Stash 0.14
      Scalar::Util 0
      Try::Tiny 0
      base 0
      perl 5.006
      strict 0
      warnings 0
  Class-Load-XS-0.10
    pathname: E/ET/ETHER/Class-Load-XS-0.10.tar.gz
    provides:
      Class::Load::XS 0.10
    requirements:
      Class::Load 0.20
      ExtUtils::MakeMaker 0
      XSLoader 0
      perl 5.006
      strict 0
      warnings 0
  Class-Method-Modifiers-2.15
    pathname: E/ET/ETHER/Class-Method-Modifiers-2.15.tar.gz
    provides:
      Class::Method::Modifiers 2.15
    requirements:
      B 0
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      base 0
      perl 5.006
      strict 0
      warnings 0
  Class-MethodMaker-2.24
    pathname: S/SC/SCHWIGON/class-methodmaker/Class-MethodMaker-2.24.tar.gz
    provides:
      Class::MethodMaker 2.24
      Class::MethodMaker::Constants undef
      Class::MethodMaker::Engine 2.24
      Class::MethodMaker::OptExt undef
      Class::MethodMaker::V1Compat undef
      Generate undef
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.006
  Clone-0.46
    pathname: G/GA/GARU/Clone-0.46.tar.gz
    provides:
      Clone 0.46
    requirements:
      ExtUtils::MakeMaker 0
  Clone-Choose-0.010
    pathname: H/HE/HERMES/Clone-Choose-0.010.tar.gz
    provides:
      Clone::Choose 0.010
    requirements:
      ExtUtils::MakeMaker 0
      Storable 0
      perl 5.008001
  Convert-ASN1-0.34
    pathname: T/TI/TIMLEGGE/Convert-ASN1-0.34.tar.gz
    provides:
      Convert::ASN1 0.34
    requirements:
      ExtUtils::MakeMaker 0
  Cpanel-JSON-XS-4.37
    pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.37.tar.gz
    provides:
      Cpanel::JSON::XS 4.37
      Cpanel::JSON::XS::Type undef
    requirements:
      Carp 0
      Config 0
      Encode 1.9801
      Exporter 0
      ExtUtils::MakeMaker 0
      Pod::Text 2.08
      XSLoader 0
      overload 0
      strict 0
      warnings 0
  Crypt-PasswdMD5-1.42
    pathname: R/RS/RSAVAGE/Crypt-PasswdMD5-1.42.tgz
    provides:
      Crypt::PasswdMD5 1.42
    requirements:
      Digest::MD5 2.53
      ExtUtils::MakeMaker 0
      strict 0
      warnings 0
  DBD-MariaDB-1.23
    pathname: P/PA/PALI/DBD-MariaDB-1.23.tar.gz
    provides:
      DBD::MariaDB 1.23
    requirements:
      Config 0
      DBI 1.608
      Data::Dumper 0
      Devel::CheckLib 1.12
      DynaLoader 0
      ExtUtils::MakeMaker 0
      File::Spec 0
      Getopt::Long 0
      perl 5.008001
      strict 0
      utf8 0
      warnings 0
  DBD-Pg-3.18.0
    pathname: T/TU/TURNSTEP/DBD-Pg-3.18.0.tar.gz
    provides:
      Bundle::DBD::Pg v3.18.0
      DBD::Pg v3.18.0
    requirements:
      DBI 1.614
      ExtUtils::MakeMaker 6.58
      File::Temp 0
      Test::More 0.88
      Time::HiRes 0
      version 0
  DBD-SQLite-1.74
    pathname: I/IS/ISHIGAKI/DBD-SQLite-1.74.tar.gz
    provides:
      DBD::SQLite 1.74
      DBD::SQLite::Constants undef
      DBD::SQLite::GetInfo undef
      DBD::SQLite::VirtualTable 1.74
      DBD::SQLite::VirtualTable::Cursor 1.74
      DBD::SQLite::VirtualTable::FileContent undef
      DBD::SQLite::VirtualTable::FileContent::Cursor undef
      DBD::SQLite::VirtualTable::PerlData undef
      DBD::SQLite::VirtualTable::PerlData::Cursor undef
    requirements:
      DBI 1.57
      ExtUtils::MakeMaker 0
      File::Spec 0.82
      Test::More 0.88
      Tie::Hash 0
      perl 5.006
  DBI-1.643
    pathname: T/TI/TIMB/DBI-1.643.tar.gz
    provides:
      Bundle::DBI 12.008696
      DBD::DBM 0.08
      DBD::DBM::Statement 0.08
      DBD::DBM::Table 0.08
      DBD::DBM::db 0.08
      DBD::DBM::dr 0.08
      DBD::DBM::st 0.08
      DBD::ExampleP 12.014311
      DBD::ExampleP::db 12.014311
      DBD::ExampleP::dr 12.014311
      DBD::ExampleP::st 12.014311
      DBD::File 0.44
      DBD::File::DataSource::File 0.44
      DBD::File::DataSource::Stream 0.44
      DBD::File::Statement 0.44
      DBD::File::Table 0.44
      DBD::File::TableSource::FileSystem 0.44
      DBD::File::db 0.44
      DBD::File::dr 0.44
      DBD::File::st 0.44
      DBD::Gofer 0.015327
      DBD::Gofer::Policy::Base 0.010088
      DBD::Gofer::Policy::classic 0.010088
      DBD::Gofer::Policy::pedantic 0.010088
      DBD::Gofer::Policy::rush 0.010088
      DBD::Gofer::Transport::Base 0.014121
      DBD::Gofer::Transport::corostream undef
      DBD::Gofer::Transport::null 0.010088
      DBD::Gofer::Transport::pipeone 0.010088
      DBD::Gofer::Transport::stream 0.014599
      DBD::Gofer::db 0.015327
      DBD::Gofer::dr 0.015327
      DBD::Gofer::st 0.015327
      DBD::Mem 0.001
      DBD::Mem::DataSource 0.001
      DBD::Mem::Statement 0.001
      DBD::Mem::Table 0.001
      DBD::Mem::db 0.001
      DBD::Mem::dr 0.001
      DBD::Mem::st 0.001
      DBD::NullP 12.014715
      DBD::NullP::db 12.014715
      DBD::NullP::dr 12.014715
      DBD::NullP::st 12.014715
      DBD::Proxy 0.2004
      DBD::Proxy::RPC::PlClient 0.2004
      DBD::Proxy::db 0.2004
      DBD::Proxy::dr 0.2004
      DBD::Proxy::st 0.2004
      DBD::Sponge 12.010003
      DBD::Sponge::db 12.010003
      DBD::Sponge::dr 12.010003
      DBD::Sponge::st 12.010003
      DBDI 12.015129
      DBI 1.643
      DBI::Const::GetInfo::ANSI 2.008697
      DBI::Const::GetInfo::ODBC 2.011374
      DBI::Const::GetInfoReturn 2.008697
      DBI::Const::GetInfoType 2.008697
      DBI::DBD 12.015129
      DBI::DBD::Metadata 2.014214
      DBI::DBD::SqlEngine 0.06
      DBI::DBD::SqlEngine::DataSource 0.06
      DBI::DBD::SqlEngine::Statement 0.06
      DBI::DBD::SqlEngine::Table 0.06
      DBI::DBD::SqlEngine::TableSource 0.06
      DBI::DBD::SqlEngine::TieMeta 0.06
      DBI::DBD::SqlEngine::TieTables 0.06
      DBI::DBD::SqlEngine::db 0.06
      DBI::DBD::SqlEngine::dr 0.06
      DBI::DBD::SqlEngine::st 0.06
      DBI::Gofer::Execute 0.014283
      DBI::Gofer::Request 0.012537
      DBI::Gofer::Response 0.011566
      DBI::Gofer::Serializer::Base 0.009950
      DBI::Gofer::Serializer::DataDumper 0.009950
      DBI::Gofer::Serializer::Storable 0.015586
      DBI::Gofer::Transport::Base 0.012537
      DBI::Gofer::Transport::pipeone 0.012537
      DBI::Gofer::Transport::stream 0.012537
      DBI::Profile 2.015065
      DBI::ProfileData 2.010008
      DBI::ProfileDumper 2.015325
      DBI::ProfileDumper::Apache 2.014121
      DBI::ProfileSubs 0.009396
      DBI::ProxyServer 0.3005
      DBI::ProxyServer::db 0.3005
      DBI::ProxyServer::dr 0.3005
      DBI::ProxyServer::st 0.3005
      DBI::SQL::Nano 1.015544
      DBI::SQL::Nano::Statement_ 1.015544
      DBI::SQL::Nano::Table_ 1.015544
      DBI::Util::CacheMemory 0.010315
      DBI::Util::_accessor 0.009479
      DBI::common 1.643
    requirements:
      ExtUtils::MakeMaker 6.48
      Test::Simple 0.90
      perl 5.008001
  Data-OptList-0.114
    pathname: R/RJ/RJBS/Data-OptList-0.114.tar.gz
    provides:
      Data::OptList 0.114
    requirements:
      ExtUtils::MakeMaker 6.78
      List::Util 0
      Params::Util 0
      Sub::Install 0.921
      perl 5.012
      strict 0
      warnings 0
  Data-UUID-1.226
    pathname: R/RJ/RJBS/Data-UUID-1.226.tar.gz
    provides:
      Data::UUID 1.226
    requirements:
      Digest::MD5 0
      ExtUtils::MakeMaker 0
  Data-Validate-Domain-0.15
    pathname: D/DR/DROLSKY/Data-Validate-Domain-0.15.tar.gz
    provides:
      Data::Validate::Domain 0.15
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      Net::Domain::TLD 1.74
      strict 0
      warnings 0
  Data-Validate-IP-0.31
    pathname: D/DR/DROLSKY/Data-Validate-IP-0.31.tar.gz
    provides:
      Data::Validate::IP 0.31
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      NetAddr::IP 4
      Scalar::Util 0
      base 0
      perl 5.008
      strict 0
      warnings 0
  Data-Validate-URI-0.07
    pathname: S/SO/SONNEN/Data-Validate-URI-0.07.tar.gz
    provides:
      Data::Validate::URI 0.07
    requirements:
      Data::Validate::Domain 0
      Data::Validate::IP 0
      ExtUtils::MakeMaker 0
  Devel-CheckLib-1.16
    pathname: M/MA/MATTN/Devel-CheckLib-1.16.tar.gz
    provides:
      Devel::CheckLib 1.16
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      File::Spec 0
      File::Temp 0.16
      perl 5.004050
  Devel-Cover-1.40
    pathname: P/PJ/PJCJ/Devel-Cover-1.40.tar.gz
    provides:
      Devel::Cover 1.40
      Devel::Cover::Annotation::Git 1.40
      Devel::Cover::Annotation::Random 1.40
      Devel::Cover::Annotation::Svk 1.40
      Devel::Cover::Branch 1.40
      Devel::Cover::Collection 1.40
      Devel::Cover::Collection::Template::Provider 1.40
      Devel::Cover::Condition 1.40
      Devel::Cover::Condition_and_2 1.40
      Devel::Cover::Condition_and_3 1.40
      Devel::Cover::Condition_or_2 1.40
      Devel::Cover::Condition_or_3 1.40
      Devel::Cover::Condition_xor_4 1.40
      Devel::Cover::Criterion 1.40
      Devel::Cover::DB 1.40
      Devel::Cover::DB::Criterion 1.40
      Devel::Cover::DB::Digests 1.40
      Devel::Cover::DB::File 1.40
      Devel::Cover::DB::IO 1.40
      Devel::Cover::DB::IO::Base 1.40
      Devel::Cover::DB::IO::JSON 1.40
      Devel::Cover::DB::IO::Sereal 1.40
      Devel::Cover::DB::IO::Storable 1.40
      Devel::Cover::DB::Run 1.40
      Devel::Cover::DB::Structure 1.40
      Devel::Cover::Html_Common 1.40
      Devel::Cover::Op 1.40
      Devel::Cover::Pod 1.40
      Devel::Cover::Report::Compilation 1.40
      Devel::Cover::Report::Html 1.40
      Devel::Cover::Report::Html_basic 1.40
      Devel::Cover::Report::Html_basic::Template::Provider 1.40
      Devel::Cover::Report::Html_minimal 1.40
      Devel::Cover::Report::Html_subtle 1.40
      Devel::Cover::Report::Html_subtle::Template::Provider 1.40
      Devel::Cover::Report::Json 1.40
      Devel::Cover::Report::Sort 1.40
      Devel::Cover::Report::Text 1.40
      Devel::Cover::Report::Text2 1.40
      Devel::Cover::Report::Vim 1.40
      Devel::Cover::Report::Vim::Template::Provider 1.40
      Devel::Cover::Statement 1.40
      Devel::Cover::Subroutine 1.40
      Devel::Cover::Test 1.40
      Devel::Cover::Time 1.40
      Devel::Cover::Truth_Table 1.40
      Devel::Cover::Truth_Table::Row 1.40
      Devel::Cover::Util 1.40
      Devel::Cover::Web 1.40
    requirements:
      Digest::MD5 0
      ExtUtils::MakeMaker 0
      HTML::Entities 3.69
      Storable 0
      Test::More 0
  Devel-Cycle-1.12
    pathname: L/LD/LDS/Devel-Cycle-1.12.tar.gz
    provides:
      Devel::Cycle 1.12
    requirements:
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      Test::More 0
  Devel-GlobalDestruction-0.14
    pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz
    provides:
      Devel::GlobalDestruction 0.14
    requirements:
      ExtUtils::MakeMaker 0
      Sub::Exporter::Progressive 0.001011
      perl 5.006
  Devel-OverloadInfo-0.007
    pathname: I/IL/ILMARI/Devel-OverloadInfo-0.007.tar.gz
    provides:
      Devel::OverloadInfo 0.007
    requirements:
      B 0
      Exporter 5.57
      ExtUtils::MakeMaker 0
      MRO::Compat 0
      Package::Stash 0.14
      Scalar::Util 0
      Sub::Util 1.40
      Text::ParseWords 0
      overload 0
      perl 5.006
      strict 0
      warnings 0
  Devel-StackTrace-2.04
    pathname: D/DR/DROLSKY/Devel-StackTrace-2.04.tar.gz
    provides:
      Devel::StackTrace 2.04
      Devel::StackTrace::Frame 2.04
    requirements:
      ExtUtils::MakeMaker 0
      File::Spec 0
      Scalar::Util 0
      overload 0
      perl 5.006
      strict 0
      warnings 0
  Devel-Symdump-2.18
    pathname: A/AN/ANDK/Devel-Symdump-2.18.tar.gz
    provides:
      Devel::Symdump 2.18
      Devel::Symdump::Export undef
    requirements:
      Compress::Zlib 0
      ExtUtils::MakeMaker 0
      Test::More 0
      perl 5.004
  Digest-HMAC-1.04
    pathname: A/AR/ARODLAND/Digest-HMAC-1.04.tar.gz
    provides:
      Digest::HMAC 1.04
      Digest::HMAC_MD5 1.04
      Digest::HMAC_SHA1 1.04
    requirements:
      Digest::MD5 2
      Digest::SHA 1
      ExtUtils::MakeMaker 0
      perl 5.004
  Digest-JHash-0.10
    pathname: S/SH/SHLOMIF/Digest-JHash-0.10.tar.gz
    provides:
      Digest::JHash 0.10
    requirements:
      DynaLoader 0
      Exporter 0
      ExtUtils::MakeMaker 0
      perl 5.008
      strict 0
      vars 0
      warnings 0
  Dist-CheckConflicts-0.11
    pathname: D/DO/DOY/Dist-CheckConflicts-0.11.tar.gz
    provides:
      Dist::CheckConflicts 0.11
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 6.30
      Module::Runtime 0.009
      base 0
      strict 0
      warnings 0
  Encode-Locale-1.05
    pathname: G/GA/GAAS/Encode-Locale-1.05.tar.gz
    provides:
      Encode::Locale 1.05
    requirements:
      Encode 2
      Encode::Alias 0
      ExtUtils::MakeMaker 0
      perl 5.008
  Eval-Closure-0.14
    pathname: D/DO/DOY/Eval-Closure-0.14.tar.gz
    provides:
      Eval::Closure 0.14
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      constant 0
      overload 0
      strict 0
      warnings 0
  Exporter-Tiny-1.006002
    pathname: T/TO/TOBYINK/Exporter-Tiny-1.006002.tar.gz
    provides:
      Exporter::Shiny 1.006002
      Exporter::Tiny 1.006002
    requirements:
      ExtUtils::MakeMaker 6.17
      perl 5.006001
  ExtUtils-Config-0.008
    pathname: L/LE/LEONT/ExtUtils-Config-0.008.tar.gz
    provides:
      ExtUtils::Config 0.008
    requirements:
      Data::Dumper 0
      ExtUtils::MakeMaker 6.30
      strict 0
      warnings 0
  ExtUtils-Helpers-0.026
    pathname: L/LE/LEONT/ExtUtils-Helpers-0.026.tar.gz
    provides:
      ExtUtils::Helpers 0.026
      ExtUtils::Helpers::Unix 0.026
      ExtUtils::Helpers::VMS 0.026
      ExtUtils::Helpers::Windows 0.026
    requirements:
      Carp 0
      Exporter 5.57
      ExtUtils::MakeMaker 0
      File::Basename 0
      File::Copy 0
      File::Spec::Functions 0
      Text::ParseWords 3.24
      perl 5.006
      strict 0
      warnings 0
  ExtUtils-InstallPaths-0.012
    pathname: L/LE/LEONT/ExtUtils-InstallPaths-0.012.tar.gz
    provides:
      ExtUtils::InstallPaths 0.012
    requirements:
      Carp 0
      ExtUtils::Config 0.002
      ExtUtils::MakeMaker 0
      File::Spec 0
      perl 5.006
      strict 0
      warnings 0
  File-Listing-6.16
    pathname: P/PL/PLICEASE/File-Listing-6.16.tar.gz
    provides:
      File::Listing 6.16
      File::Listing::apache 6.16
      File::Listing::dosftp 6.16
      File::Listing::netware 6.16
      File::Listing::unix 6.16
      File::Listing::vms 6.16
    requirements:
      Exporter 5.57
      ExtUtils::MakeMaker 0
      HTTP::Date 0
      perl 5.006
  File-Remove-1.61
    pathname: S/SH/SHLOMIF/File-Remove-1.61.tar.gz
    provides:
      File::Remove 1.61
    requirements:
      Cwd 3.29
      ExtUtils::MakeMaker 0
      File::Glob 0
      File::Path 0
      File::Spec 3.29
      Module::Build 0.28
      constant 0
      perl 5.008
      strict 0
      vars 0
      warnings 0
  HTML-Parser-3.81
    pathname: O/OA/OALDERS/HTML-Parser-3.81.tar.gz
    provides:
      HTML::Entities 3.81
      HTML::Filter 3.81
      HTML::HeadParser 3.81
      HTML::LinkExtor 3.81
      HTML::Parser 3.81
      HTML::PullParser 3.81
      HTML::TokeParser 3.81
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 6.52
      HTML::Tagset 0
      HTTP::Headers 0
      IO::File 0
      URI 0
      URI::URL 0
      XSLoader 0
      strict 0
  HTML-Tagset-3.20
    pathname: P/PE/PETDANCE/HTML-Tagset-3.20.tar.gz
    provides:
      HTML::Tagset 3.20
    requirements:
      ExtUtils::MakeMaker 0
  HTTP-CookieJar-0.014
    pathname: D/DA/DAGOLDEN/HTTP-CookieJar-0.014.tar.gz
    provides:
      HTTP::CookieJar 0.014
      HTTP::CookieJar::LWP 0.014
    requirements:
      Carp 0
      ExtUtils::MakeMaker 6.17
      HTTP::Date 0
      Time::Local 1.1901
      parent 0
      perl 5.008001
      strict 0
      warnings 0
  HTTP-Cookies-6.11
    pathname: O/OA/OALDERS/HTTP-Cookies-6.11.tar.gz
    provides:
      HTTP::Cookies 6.11
      HTTP::Cookies::Microsoft 6.11
      HTTP::Cookies::Netscape 6.11
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      HTTP::Date 6
      HTTP::Headers::Util 6
      HTTP::Request 0
      locale 0
      perl 5.008001
      strict 0
  HTTP-Date-6.06
    pathname: O/OA/OALDERS/HTTP-Date-6.06.tar.gz
    provides:
      HTTP::Date 6.06
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      Time::Local 1.28
      Time::Zone 0
      perl 5.006002
      strict 0
  HTTP-Message-6.45
    pathname: O/OA/OALDERS/HTTP-Message-6.45.tar.gz
    provides:
      HTTP::Config 6.45
      HTTP::Headers 6.45
      HTTP::Headers::Auth 6.45
      HTTP::Headers::ETag 6.45
      HTTP::Headers::Util 6.45
      HTTP::Message 6.45
      HTTP::Request 6.45
      HTTP::Request::Common 6.45
      HTTP::Response 6.45
      HTTP::Status 6.45
    requirements:
      Carp 0
      Clone 0.46
      Compress::Raw::Bzip2 0
      Compress::Raw::Zlib 2.062
      Encode 3.01
      Encode::Locale 1
      Exporter 5.57
      ExtUtils::MakeMaker 0
      File::Spec 0
      HTTP::Date 6
      IO::Compress::Bzip2 2.021
      IO::Compress::Deflate 0
      IO::Compress::Gzip 0
      IO::HTML 0
      IO::Uncompress::Inflate 0
      IO::Uncompress::RawInflate 0
      LWP::MediaTypes 6
      MIME::Base64 2.1
      MIME::QuotedPrint 0
      URI 1.10
      parent 0
      perl 5.008001
      strict 0
      warnings 0
  HTTP-Negotiate-6.01
    pathname: G/GA/GAAS/HTTP-Negotiate-6.01.tar.gz
    provides:
      HTTP::Negotiate 6.01
    requirements:
      ExtUtils::MakeMaker 0
      HTTP::Headers 6
      perl 5.008001
  Hash-Merge-0.302
    pathname: H/HE/HERMES/Hash-Merge-0.302.tar.gz
    provides:
      Hash::Merge 0.302
    requirements:
      Clone::Choose 0.008
      ExtUtils::MakeMaker 6.64
      Scalar::Util 0
      perl 5.008001
  Hash-MoreUtils-0.06
    pathname: R/RE/REHSACK/Hash-MoreUtils-0.06.tar.gz
    provides:
      Hash::MoreUtils 0.06
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.008001
  IO-HTML-1.004
    pathname: C/CJ/CJM/IO-HTML-1.004.tar.gz
    provides:
      IO::HTML 1.004
    requirements:
      Carp 0
      Encode 2.10
      Exporter 5.57
      ExtUtils::MakeMaker 0
      perl 5.008
  IO-Interactive-1.025
    pathname: B/BD/BDFOY/IO-Interactive-1.025.tar.gz
    provides:
      IO::Interactive 1.025
    requirements:
      ExtUtils::MakeMaker 6.64
      File::Spec::Functions 0
      perl 5.008
  IO-Socket-SSL-2.084
    pathname: S/SU/SULLR/IO-Socket-SSL-2.084.tar.gz
    provides:
      IO::Socket::SSL 2.084
      IO::Socket::SSL::Intercept 2.056
      IO::Socket::SSL::OCSP_Cache 2.084
      IO::Socket::SSL::OCSP_Resolver 2.084
      IO::Socket::SSL::PublicSuffix undef
      IO::Socket::SSL::SSL_Context 2.084
      IO::Socket::SSL::SSL_HANDLE 2.084
      IO::Socket::SSL::Session_Cache 2.084
      IO::Socket::SSL::Trace 2.084
      IO::Socket::SSL::Utils 2.015
    requirements:
      ExtUtils::MakeMaker 0
      Mozilla::CA 0
      Net::SSLeay 1.46
      Scalar::Util 0
  Image-PNG-QRCode-0.10
    pathname: B/BK/BKB/Image-PNG-QRCode-0.10.tar.gz
    provides:
      Image::PNG::QRCode 0.10
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.006001
  JSON-4.10
    pathname: I/IS/ISHIGAKI/JSON-4.10.tar.gz
    provides:
      JSON 4.10
      JSON::Backend::PP 4.10
    requirements:
      ExtUtils::MakeMaker 0
      Test::More 0
  JSON-MaybeXS-1.004005
    pathname: E/ET/ETHER/JSON-MaybeXS-1.004005.tar.gz
    provides:
      JSON::MaybeXS 1.004005
    requirements:
      Carp 0
      Cpanel::JSON::XS 2.3310
      ExtUtils::MakeMaker 0
      JSON::PP 2.27300
      Scalar::Util 0
      perl 5.006
  JSON-XS-4.03
    pathname: M/ML/MLEHMANN/JSON-XS-4.03.tar.gz
    provides:
      JSON::XS 4.03
    requirements:
      Canary::Stability 0
      ExtUtils::MakeMaker 6.52
      Types::Serialiser 0
      common::sense 0
  LWP-MediaTypes-6.04
    pathname: O/OA/OALDERS/LWP-MediaTypes-6.04.tar.gz
    provides:
      LWP::MediaTypes 6.04
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      File::Basename 0
      Scalar::Util 0
      perl 5.006002
      strict 0
  List-BinarySearch-0.25
    pathname: D/DA/DAVIDO/List-BinarySearch-0.25.tar.gz
    provides:
      List::BinarySearch 0.25
      List::BinarySearch::PP 0.25
    requirements:
      English 0
      ExtUtils::MakeMaker 6.62
      List::BinarySearch::XS 0
      Scalar::Util 0
      Test::More 0.98
      perl 5.008000
  List-BinarySearch-XS-0.09
    pathname: D/DA/DAVIDO/List-BinarySearch-XS-0.09.tar.gz
    provides:
      List::BinarySearch::XS 0.09
    requirements:
      ExtUtils::MakeMaker 6.62
      Test::More 0.98
      perl 5.008000
  List-MoreUtils-0.430
    pathname: R/RE/REHSACK/List-MoreUtils-0.430.tar.gz
    provides:
      List::MoreUtils 0.430
      List::MoreUtils::PP 0.430
    requirements:
      Exporter::Tiny 0.038
      ExtUtils::MakeMaker 0
      List::MoreUtils::XS 0.430
  List-MoreUtils-XS-0.430
    pathname: R/RE/REHSACK/List-MoreUtils-XS-0.430.tar.gz
    provides:
      List::MoreUtils::XS 0.430
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      File::Basename 0
      File::Copy 0
      File::Path 0
      File::Spec 0
      IPC::Cmd 0
      XSLoader 0.22
      base 0
  Locale-Maketext-Lexicon-1.00
    pathname: D/DR/DRTECH/Locale-Maketext-Lexicon-1.00.tar.gz
    provides:
      Locale::Maketext::Extract 1.00
      Locale::Maketext::Extract::Plugin::Base 1.00
      Locale::Maketext::Extract::Plugin::FormFu 1.00
      Locale::Maketext::Extract::Plugin::FormFu::Extractor 1.00
      Locale::Maketext::Extract::Plugin::Generic 1.00
      Locale::Maketext::Extract::Plugin::Haml 1.00
      Locale::Maketext::Extract::Plugin::Mason 1.00
      Locale::Maketext::Extract::Plugin::PPI 1.00
      Locale::Maketext::Extract::Plugin::Perl 1.00
      Locale::Maketext::Extract::Plugin::TT2 1.00
      Locale::Maketext::Extract::Plugin::TT2::Directive 1.00
      Locale::Maketext::Extract::Plugin::TT2::Parser 1.00
      Locale::Maketext::Extract::Plugin::TextTemplate 1.00
      Locale::Maketext::Extract::Plugin::TextTemplate::Parser 1.00
      Locale::Maketext::Extract::Plugin::YAML 1.00
      Locale::Maketext::Extract::Plugin::YAML::Extractor 1.00
      Locale::Maketext::Extract::Run 1.00
      Locale::Maketext::Lexicon 1.00
      Locale::Maketext::Lexicon::Auto 1.00
      Locale::Maketext::Lexicon::Gettext 1.00
      Locale::Maketext::Lexicon::Msgcat 1.00
      Locale::Maketext::Lexicon::Tie 1.00
    requirements:
      ExtUtils::MakeMaker 6.30
      Locale::Maketext 1.17
  Log-Any-1.717
    pathname: P/PR/PREACTION/Log-Any-1.717.tar.gz
    provides:
      Log::Any 1.717
      Log::Any::Adapter 1.717
      Log::Any::Adapter::Base 1.717
      Log::Any::Adapter::Capture 1.717
      Log::Any::Adapter::File 1.717
      Log::Any::Adapter::Multiplex 1.717
      Log::Any::Adapter::Null 1.717
      Log::Any::Adapter::Stderr 1.717
      Log::Any::Adapter::Stdout 1.717
      Log::Any::Adapter::Syslog 1.717
      Log::Any::Adapter::Test 1.717
      Log::Any::Adapter::Util 1.717
      Log::Any::Manager 1.717
      Log::Any::Proxy 1.717
      Log::Any::Proxy::Null 1.717
      Log::Any::Proxy::Test 1.717
      Log::Any::Proxy::WithStackTrace 1.717
      Log::Any::Test 1.717
    requirements:
      ExtUtils::MakeMaker 0
  MRO-Compat-0.15
    pathname: H/HA/HAARG/MRO-Compat-0.15.tar.gz
    provides:
      MRO::Compat 0.15
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.006
  Minion-10.28
    pathname: S/SR/SRI/Minion-10.28.tar.gz
    provides:
      LinkCheck undef
      LinkCheck::Controller::Links undef
      LinkCheck::Task::CheckLinks undef
      Minion 10.28
      Minion::Backend undef
      Minion::Backend::Pg undef
      Minion::Command::minion undef
      Minion::Command::minion::job undef
      Minion::Command::minion::worker undef
      Minion::Iterator undef
      Minion::Job undef
      Minion::Worker undef
      Mojolicious::Plugin::Minion undef
      Mojolicious::Plugin::Minion::Admin undef
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 9.0
      YAML::XS 0.67
      perl 5.016
  Minion-Backend-SQLite-v5.0.7
    pathname: D/DB/DBOOK/Minion-Backend-SQLite-v5.0.7.tar.gz
    provides:
      Minion::Backend::SQLite v5.0.7
    requirements:
      List::Util 0
      Minion 10.13
      Module::Build::Tiny 0.034
      Mojo::SQLite 3.000
      Mojolicious 7.49
      Sys::Hostname 0
      Time::HiRes 0
      perl 5.010001
  Minion-Backend-mysql-1.004
    pathname: P/PR/PREACTION/Minion-Backend-mysql-1.004.tar.gz
    provides:
      Minion::Backend::mysql 1.004
    requirements:
      ExtUtils::MakeMaker 0
      Minion 10.13
      Mojo::mysql 1.04
      Mojolicious 9.0
      perl 5.016
  Module-Build-0.4234
    pathname: L/LE/LEONT/Module-Build-0.4234.tar.gz
    provides:
      Module::Build 0.4234
      Module::Build::Base 0.4234
      Module::Build::Compat 0.4234
      Module::Build::Config 0.4234
      Module::Build::Cookbook 0.4234
      Module::Build::Dumper 0.4234
      Module::Build::Notes 0.4234
      Module::Build::PPMMaker 0.4234
      Module::Build::Platform::Default 0.4234
      Module::Build::Platform::MacOS 0.4234
      Module::Build::Platform::Unix 0.4234
      Module::Build::Platform::VMS 0.4234
      Module::Build::Platform::VOS 0.4234
      Module::Build::Platform::Windows 0.4234
      Module::Build::Platform::aix 0.4234
      Module::Build::Platform::cygwin 0.4234
      Module::Build::Platform::darwin 0.4234
      Module::Build::Platform::os2 0.4234
      Module::Build::PodParser 0.4234
    requirements:
      CPAN::Meta 2.142060
      Cwd 0
      Data::Dumper 0
      ExtUtils::CBuilder 0.27
      ExtUtils::Install 0
      ExtUtils::Manifest 0
      ExtUtils::Mkbootstrap 0
      ExtUtils::ParseXS 2.21
      File::Basename 0
      File::Compare 0
      File::Copy 0
      File::Find 0
      File::Path 0
      File::Spec 0.82
      Getopt::Long 0
      Module::Metadata 1.000002
      Perl::OSType 1
      TAP::Harness 3.29
      Text::Abbrev 0
      Text::ParseWords 0
      perl 5.006001
      version 0.87
  Module-Build-Tiny-0.047
    pathname: L/LE/LEONT/Module-Build-Tiny-0.047.tar.gz
    provides:
      Module::Build::Tiny 0.047
    requirements:
      CPAN::Meta 0
      DynaLoader 0
      Exporter 5.57
      ExtUtils::CBuilder 0
      ExtUtils::Config 0.003
      ExtUtils::Helpers 0.020
      ExtUtils::Install 0
      ExtUtils::InstallPaths 0.002
      ExtUtils::ParseXS 0
      File::Basename 0
      File::Find 0
      File::Path 0
      File::Spec::Functions 0
      Getopt::Long 2.36
      JSON::PP 2
      Pod::Man 0
      TAP::Harness::Env 0
      perl 5.006
      strict 0
      warnings 0
  Module-Implementation-0.09
    pathname: D/DR/DROLSKY/Module-Implementation-0.09.tar.gz
    provides:
      Module::Implementation 0.09
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      Module::Runtime 0.012
      Try::Tiny 0
      strict 0
      warnings 0
  Module-Install-1.20-withdate
    pathname: E/ET/ETHER/Module-Install-1.20-withdate.tar.gz
    provides:
      Module::AutoInstall 1.20
      Module::Install 1.20
      Module::Install::Admin 1.20
      Module::Install::Admin::Bundle 1.20
      Module::Install::Admin::Compiler 1.20
      Module::Install::Admin::Find 1.20
      Module::Install::Admin::Include 1.20
      Module::Install::Admin::Makefile 1.20
      Module::Install::Admin::Manifest 1.20
      Module::Install::Admin::Metadata 1.20
      Module::Install::Admin::ScanDeps 1.20
      Module::Install::Admin::WriteAll 1.20
      Module::Install::AutoInstall 1.20
      Module::Install::Base 1.20
      Module::Install::Base::FakeAdmin 1.20
      Module::Install::Bundle 1.20
      Module::Install::Can 1.20
      Module::Install::Compiler 1.20
      Module::Install::Deprecated 1.20
      Module::Install::External 1.20
      Module::Install::Fetch 1.20
      Module::Install::Include 1.20
      Module::Install::Inline 1.20
      Module::Install::MakeMaker 1.20
      Module::Install::Makefile 1.20
      Module::Install::Metadata 1.20
      Module::Install::PAR 1.20
      Module::Install::Run 1.20
      Module::Install::Scripts 1.20
      Module::Install::Share 1.20
      Module::Install::Win32 1.20
      Module::Install::With 1.20
      Module::Install::WriteAll 1.20
      inc::Module::Install 1.20
      inc::Module::Install::DSL 1.20
    requirements:
      Devel::PPPort 3.16
      ExtUtils::Install 1.52
      ExtUtils::MakeMaker 6.59
      ExtUtils::ParseXS 2.19
      File::Path 0
      File::Remove 1.42
      File::Spec 3.28
      Module::Build 0.29
      Module::CoreList 2.17
      Module::ScanDeps 1.09
      Parse::CPAN::Meta 1.4413
      Test::Harness 3.13
      Test::More 0.86
      YAML::Tiny 1.38
      autodie 0
      perl 5.006
  Module-Runtime-0.016
    pathname: Z/ZE/ZEFRAM/Module-Runtime-0.016.tar.gz
    provides:
      Module::Runtime 0.016
    requirements:
      Module::Build 0
      Test::More 0.41
      perl 5.006
      strict 0
      warnings 0
  Module-Runtime-Conflicts-0.003
    pathname: E/ET/ETHER/Module-Runtime-Conflicts-0.003.tar.gz
    provides:
      Module::Runtime::Conflicts 0.003
    requirements:
      Dist::CheckConflicts 0
      ExtUtils::MakeMaker 0
      Module::Runtime 0
      perl 5.006
      strict 0
      warnings 0
  Module-ScanDeps-1.35
    pathname: R/RS/RSCHUPP/Module-ScanDeps-1.35.tar.gz
    provides:
      Module::ScanDeps 1.35
    requirements:
      ExtUtils::MakeMaker 0
      File::Spec 0
      File::Temp 0
      Getopt::Long 0
      List::Util 1.33
      Module::Metadata 0
      Text::ParseWords 0
      perl 5.008009
      version 0
  Mojo-Pg-4.27
    pathname: S/SR/SRI/Mojo-Pg-4.27.tar.gz
    provides:
      Mojo::Pg 4.27
      Mojo::Pg::Database undef
      Mojo::Pg::Migrations undef
      Mojo::Pg::PubSub undef
      Mojo::Pg::Results undef
      Mojo::Pg::Transaction undef
    requirements:
      DBD::Pg 3.007004
      ExtUtils::MakeMaker 0
      Mojolicious 8.50
      SQL::Abstract::Pg 1.0
      perl 5.016
  Mojo-SQLite-3.009
    pathname: D/DB/DBOOK/Mojo-SQLite-3.009.tar.gz
    provides:
      Mojo::SQLite 3.009
      Mojo::SQLite::Database 3.009
      Mojo::SQLite::Migrations 3.009
      Mojo::SQLite::PubSub 3.009
      Mojo::SQLite::Results 3.009
      Mojo::SQLite::Transaction 3.009
    requirements:
      Carp 0
      DBD::SQLite 1.68
      DBI 1.627
      File::Spec::Functions 0
      File::Temp 0
      Module::Build::Tiny 0.034
      Mojolicious 8.03
      SQL::Abstract::Pg 1.0
      Scalar::Util 0
      URI 1.69
      URI::db 0.15
      URI::file 4.21
      perl 5.010001
  Mojo-mysql-1.27
    pathname: J/JH/JHTHORSEN/Mojo-mysql-1.27.tar.gz
    provides:
      Mojo::mysql 1.27
      Mojo::mysql::Database undef
      Mojo::mysql::Migrations undef
      Mojo::mysql::PubSub undef
      Mojo::mysql::Results undef
      Mojo::mysql::Transaction undef
      SQL::Abstract::mysql undef
    requirements:
      DBD::MariaDB 1.21
      DBI 1.643
      ExtUtils::MakeMaker 0
      Mojolicious 8.03
      SQL::Abstract 1.86
      perl 5.016
  Mojolicious-9.35
    pathname: S/SR/SRI/Mojolicious-9.35.tar.gz
    provides:
      Mojo undef
      Mojo::Asset undef
      Mojo::Asset::File undef
      Mojo::Asset::Memory undef
      Mojo::Base undef
      Mojo::ByteStream undef
      Mojo::Cache undef
      Mojo::Collection undef
      Mojo::Content undef
      Mojo::Content::MultiPart undef
      Mojo::Content::Single undef
      Mojo::Cookie undef
      Mojo::Cookie::Request undef
      Mojo::Cookie::Response undef
      Mojo::DOM undef
      Mojo::DOM::CSS undef
      Mojo::DOM::HTML undef
      Mojo::Date undef
      Mojo::DynamicMethods undef
      Mojo::EventEmitter undef
      Mojo::Exception undef
      Mojo::File undef
      Mojo::Headers undef
      Mojo::HelloWorld undef
      Mojo::Home undef
      Mojo::IOLoop undef
      Mojo::IOLoop::Client undef
      Mojo::IOLoop::Server undef
      Mojo::IOLoop::Stream undef
      Mojo::IOLoop::Subprocess undef
      Mojo::IOLoop::TLS undef
      Mojo::JSON undef
      Mojo::JSON::Pointer undef
      Mojo::Loader undef
      Mojo::Log undef
      Mojo::Message undef
      Mojo::Message::Request undef
      Mojo::Message::Response undef
      Mojo::Parameters undef
      Mojo::Path undef
      Mojo::Promise undef
      Mojo::Reactor undef
      Mojo::Reactor::EV undef
      Mojo::Reactor::Poll undef
      Mojo::Server undef
      Mojo::Server::CGI undef
      Mojo::Server::Daemon undef
      Mojo::Server::Hypnotoad undef
      Mojo::Server::Morbo undef
      Mojo::Server::Morbo::Backend undef
      Mojo::Server::Morbo::Backend::Poll undef
      Mojo::Server::PSGI undef
      Mojo::Server::Prefork undef
      Mojo::Template undef
      Mojo::Transaction undef
      Mojo::Transaction::HTTP undef
      Mojo::Transaction::WebSocket undef
      Mojo::URL undef
      Mojo::Upload undef
      Mojo::UserAgent undef
      Mojo::UserAgent::CookieJar undef
      Mojo::UserAgent::Proxy undef
      Mojo::UserAgent::Server undef
      Mojo::UserAgent::Transactor undef
      Mojo::Util undef
      Mojo::WebSocket undef
      Mojolicious 9.35
      Mojolicious::Command undef
      Mojolicious::Command::Author::cpanify undef
      Mojolicious::Command::Author::generate undef
      Mojolicious::Command::Author::generate::app undef
      Mojolicious::Command::Author::generate::dockerfile undef
      Mojolicious::Command::Author::generate::lite_app undef
      Mojolicious::Command::Author::generate::makefile undef
      Mojolicious::Command::Author::generate::plugin undef
      Mojolicious::Command::Author::inflate undef
      Mojolicious::Command::cgi undef
      Mojolicious::Command::daemon undef
      Mojolicious::Command::eval undef
      Mojolicious::Command::get undef
      Mojolicious::Command::prefork undef
      Mojolicious::Command::psgi undef
      Mojolicious::Command::routes undef
      Mojolicious::Command::version undef
      Mojolicious::Commands undef
      Mojolicious::Controller undef
      Mojolicious::Lite undef
      Mojolicious::Plugin undef
      Mojolicious::Plugin::Config undef
      Mojolicious::Plugin::DefaultHelpers undef
      Mojolicious::Plugin::EPLRenderer undef
      Mojolicious::Plugin::EPRenderer undef
      Mojolicious::Plugin::HeaderCondition undef
      Mojolicious::Plugin::JSONConfig undef
      Mojolicious::Plugin::Mount undef
      Mojolicious::Plugin::NotYAMLConfig undef
      Mojolicious::Plugin::TagHelpers undef
      Mojolicious::Plugins undef
      Mojolicious::Renderer undef
      Mojolicious::Routes undef
      Mojolicious::Routes::Match undef
      Mojolicious::Routes::Pattern undef
      Mojolicious::Routes::Route undef
      Mojolicious::Sessions undef
      Mojolicious::Static undef
      Mojolicious::Types undef
      Mojolicious::Validator undef
      Mojolicious::Validator::Validation undef
      Test::Mojo undef
      ojo undef
    requirements:
      ExtUtils::MakeMaker 0
      IO::Socket::IP 0.37
      Sub::Util 1.41
      perl 5.016
  Mojolicious-Plugin-Authentication-1.39
    pathname: J/JJ/JJATRIA/Mojolicious-Plugin-Authentication-1.39.tar.gz
    provides:
      Mojolicious::Plugin::Authentication 1.39
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      Mojolicious 8.0
      perl 5.016
  Mojolicious-Plugin-CHI-0.20
    pathname: A/AK/AKRON/Mojolicious-Plugin-CHI-0.20.tar.gz
    provides:
      Mojolicious::Plugin::CHI 0.20
      Mojolicious::Plugin::CHI::chi undef
    requirements:
      CHI 0.58
      Digest::JHash 0.05
      ExtUtils::MakeMaker 0
      Mojolicious 4.77
      Test::Memory::Cycle 1.06
      Test::More 0
      Test::Output 1
      perl 5.010001
  Mojolicious-Plugin-CSPHeader-0.06
    pathname: L/LD/LDIDRY/Mojolicious-Plugin-CSPHeader-0.06.tar.gz
    provides:
      Mojolicious::Plugin::CSPHeader 0.06
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 7.75
  Mojolicious-Plugin-DebugDumperHelper-0.03
    pathname: L/LD/LDIDRY/Mojolicious-Plugin-DebugDumperHelper-0.03.tar.gz
    provides:
      Mojolicious::Plugin::DebugDumperHelper 0.03
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 6.11
  Mojolicious-Plugin-GzipStatic-0.04
    pathname: L/LD/LDIDRY/Mojolicious-Plugin-GzipStatic-0.04.tar.gz
    provides:
      Mojolicious::Plugin::GzipStatic 0.04
    requirements:
      ExtUtils::MakeMaker 0
      IO::Compress::Gzip 0
      Mojolicious 7.75
  Mojolicious-Plugin-I18N-1.6
    pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.6.tar.gz
    provides:
      Mojolicious::Plugin::I18N 1.6
    requirements:
      I18N::LangTags 0.35
      Module::Build 0.42
      Mojolicious 5
      Test::More 0
      perl 5.010001
  Mojolicious-Plugin-PgURLHelper-0.03
    pathname: L/LD/LDIDRY/Mojolicious-Plugin-PgURLHelper-0.03.tar.gz
    provides:
      Mojolicious::Plugin::PgURLHelper 0.03
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 7.23
  Mojolicious-Plugin-Piwik-2.00
    pathname: A/AK/AKRON/Mojolicious-Plugin-Piwik-2.00.tar.gz
    provides:
      Mojolicious::Plugin::Piwik 2.00
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 8.02
      Test::More 0
      perl 5.010001
  Mojolicious-Plugin-StaticCache-0.02
    pathname: L/LD/LDIDRY/Mojolicious-Plugin-StaticCache-0.02.tar.gz
    provides:
      Mojolicious::Plugin::StaticCache 0.02
    requirements:
      ExtUtils::MakeMaker 0
      Mojolicious 7.33
  Moo-2.005005
    pathname: H/HA/HAARG/Moo-2.005005.tar.gz
    provides:
      Method::Generate::Accessor undef
      Method::Generate::BuildAll undef
      Method::Generate::Constructor undef
      Method::Generate::DemolishAll undef
      Moo 2.005005
      Moo::HandleMoose undef
      Moo::HandleMoose::FakeConstructor undef
      Moo::HandleMoose::FakeMetaClass undef
      Moo::HandleMoose::_TypeMap undef
      Moo::Object undef
      Moo::Role 2.005005
      Moo::_Utils undef
      Moo::sification undef
      oo undef
    requirements:
      Carp 0
      Class::Method::Modifiers 1.10
      Exporter 0
      ExtUtils::MakeMaker 0
      Role::Tiny 2.002003
      Scalar::Util 1.00
      Sub::Defer 2.006006
      Sub::Quote 2.006006
      perl 5.006
  MooX-Types-MooseLike-0.29
    pathname: M/MA/MATEU/MooX-Types-MooseLike-0.29.tar.gz
    provides:
      MooX::Types::MooseLike 0.29
      MooX::Types::MooseLike::Base 0.29
    requirements:
      ExtUtils::MakeMaker 0
      Module::Runtime 0.014
  MooX-Types-MooseLike-Numeric-1.03
    pathname: M/MA/MATEU/MooX-Types-MooseLike-Numeric-1.03.tar.gz
    provides:
      MooX::Types::MooseLike::Numeric 1.03
    requirements:
      ExtUtils::MakeMaker 0
      Moo 1.004002
      MooX::Types::MooseLike 0.23
      Test::Fatal 0.003
      Test::More 0.96
  Moose-2.2206
    pathname: E/ET/ETHER/Moose-2.2206.tar.gz
    provides:
      Class::MOP 2.2206
      Class::MOP::Attribute 2.2206
      Class::MOP::Class 2.2206
      Class::MOP::Class::Immutable::Trait 2.2206
      Class::MOP::Deprecated 2.2206
      Class::MOP::Instance 2.2206
      Class::MOP::Method 2.2206
      Class::MOP::Method::Accessor 2.2206
      Class::MOP::Method::Constructor 2.2206
      Class::MOP::Method::Generated 2.2206
      Class::MOP::Method::Inlined 2.2206
      Class::MOP::Method::Meta 2.2206
      Class::MOP::Method::Wrapped 2.2206
      Class::MOP::MiniTrait 2.2206
      Class::MOP::Mixin 2.2206
      Class::MOP::Mixin::AttributeCore 2.2206
      Class::MOP::Mixin::HasAttributes 2.2206
      Class::MOP::Mixin::HasMethods 2.2206
      Class::MOP::Mixin::HasOverloads 2.2206
      Class::MOP::Module 2.2206
      Class::MOP::Object 2.2206
      Class::MOP::Overload 2.2206
      Class::MOP::Package 2.2206
      Moose 2.2206
      Moose::Cookbook 2.2206
      Moose::Cookbook::Basics::BankAccount_MethodModifiersAndSubclassing 2.2206
      Moose::Cookbook::Basics::BinaryTree_AttributeFeatures 2.2206
      Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild 2.2206
      Moose::Cookbook::Basics::Company_Subtypes 2.2206
      Moose::Cookbook::Basics::DateTime_ExtendingNonMooseParent 2.2206
      Moose::Cookbook::Basics::Document_AugmentAndInner 2.2206
      Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion 2.2206
      Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion 2.2206
      Moose::Cookbook::Basics::Immutable 2.2206
      Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD 2.2206
      Moose::Cookbook::Basics::Point_AttributesAndSubclassing 2.2206
      Moose::Cookbook::Extending::Debugging_BaseClassRole 2.2206
      Moose::Cookbook::Extending::ExtensionOverview 2.2206
      Moose::Cookbook::Extending::Mooseish_MooseSugar 2.2206
      Moose::Cookbook::Legacy::Debugging_BaseClassReplacement 2.2206
      Moose::Cookbook::Legacy::Labeled_AttributeMetaclass 2.2206
      Moose::Cookbook::Legacy::Table_ClassMetaclass 2.2206
      Moose::Cookbook::Meta::GlobRef_InstanceMetaclass 2.2206
      Moose::Cookbook::Meta::Labeled_AttributeTrait 2.2206
      Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass 2.2206
      Moose::Cookbook::Meta::Table_MetaclassTrait 2.2206
      Moose::Cookbook::Meta::WhyMeta 2.2206
      Moose::Cookbook::Roles::ApplicationToInstance 2.2206
      Moose::Cookbook::Roles::Comparable_CodeReuse 2.2206
      Moose::Cookbook::Roles::Restartable_AdvancedComposition 2.2206
      Moose::Cookbook::Snack::Keywords 2.2206
      Moose::Cookbook::Snack::Types 2.2206
      Moose::Cookbook::Style 2.2206
      Moose::Deprecated 2.2206
      Moose::Exception 2.2206
      Moose::Exception::AccessorMustReadWrite 2.2206
      Moose::Exception::AddParameterizableTypeTakesParameterizableType 2.2206
      Moose::Exception::AddRoleTakesAMooseMetaRoleInstance 2.2206
      Moose::Exception::AddRoleToARoleTakesAMooseMetaRole 2.2206
      Moose::Exception::ApplyTakesABlessedInstance 2.2206
      Moose::Exception::AttachToClassNeedsAClassMOPClassInstanceOrASubclass 2.2206
      Moose::Exception::AttributeConflictInRoles 2.2206
      Moose::Exception::AttributeConflictInSummation 2.2206
      Moose::Exception::AttributeExtensionIsNotSupportedInRoles 2.2206
      Moose::Exception::AttributeIsRequired 2.2206
      Moose::Exception::AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass 2.2206
      Moose::Exception::AttributeNamesDoNotMatch 2.2206
      Moose::Exception::AttributeValueIsNotAnObject 2.2206
      Moose::Exception::AttributeValueIsNotDefined 2.2206
      Moose::Exception::AutoDeRefNeedsArrayRefOrHashRef 2.2206
      Moose::Exception::BadOptionFormat 2.2206
      Moose::Exception::BothBuilderAndDefaultAreNotAllowed 2.2206
      Moose::Exception::BuilderDoesNotExist 2.2206
      Moose::Exception::BuilderMethodNotSupportedForAttribute 2.2206
      Moose::Exception::BuilderMethodNotSupportedForInlineAttribute 2.2206
      Moose::Exception::BuilderMustBeAMethodName 2.2206
      Moose::Exception::CallingMethodOnAnImmutableInstance 2.2206
      Moose::Exception::CallingReadOnlyMethodOnAnImmutableInstance 2.2206
      Moose::Exception::CanExtendOnlyClasses 2.2206
      Moose::Exception::CanOnlyConsumeRole 2.2206
      Moose::Exception::CanOnlyWrapBlessedCode 2.2206
      Moose::Exception::CanReblessOnlyIntoASubclass 2.2206
      Moose::Exception::CanReblessOnlyIntoASuperclass 2.2206
      Moose::Exception::CannotAddAdditionalTypeCoercionsToUnion 2.2206
      Moose::Exception::CannotAddAsAnAttributeToARole 2.2206
      Moose::Exception::CannotApplyBaseClassRolesToRole 2.2206
      Moose::Exception::CannotAssignValueToReadOnlyAccessor 2.2206
      Moose::Exception::CannotAugmentIfLocalMethodPresent 2.2206
      Moose::Exception::CannotAugmentNoSuperMethod 2.2206
      Moose::Exception::CannotAutoDerefWithoutIsa 2.2206
      Moose::Exception::CannotAutoDereferenceTypeConstraint 2.2206
      Moose::Exception::CannotCalculateNativeType 2.2206
      Moose::Exception::CannotCallAnAbstractBaseMethod 2.2206
      Moose::Exception::CannotCallAnAbstractMethod 2.2206
      Moose::Exception::CannotCoerceAWeakRef 2.2206
      Moose::Exception::CannotCoerceAttributeWhichHasNoCoercion 2.2206
      Moose::Exception::CannotCreateHigherOrderTypeWithoutATypeParameter 2.2206
      Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresent 2.2206
      Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresentInClass 2.2206
      Moose::Exception::CannotDelegateLocalMethodIsPresent 2.2206
      Moose::Exception::CannotDelegateWithoutIsa 2.2206
      Moose::Exception::CannotFindDelegateMetaclass 2.2206
      Moose::Exception::CannotFindType 2.2206
      Moose::Exception::CannotFindTypeGivenToMatchOnType 2.2206
      Moose::Exception::CannotFixMetaclassCompatibility 2.2206
      Moose::Exception::CannotGenerateInlineConstraint 2.2206
      Moose::Exception::CannotInitializeMooseMetaRoleComposite 2.2206
      Moose::Exception::CannotInlineTypeConstraintCheck 2.2206
      Moose::Exception::CannotLocatePackageInINC 2.2206
      Moose::Exception::CannotMakeMetaclassCompatible 2.2206
      Moose::Exception::CannotOverrideALocalMethod 2.2206
      Moose::Exception::CannotOverrideBodyOfMetaMethods 2.2206
      Moose::Exception::CannotOverrideLocalMethodIsPresent 2.2206
      Moose::Exception::CannotOverrideNoSuperMethod 2.2206
      Moose::Exception::CannotRegisterUnnamedTypeConstraint 2.2206
      Moose::Exception::CannotUseLazyBuildAndDefaultSimultaneously 2.2206
      Moose::Exception::CircularReferenceInAlso 2.2206
      Moose::Exception::ClassDoesNotHaveInitMeta 2.2206
      Moose::Exception::ClassDoesTheExcludedRole 2.2206
      Moose::Exception::ClassNamesDoNotMatch 2.2206
      Moose::Exception::CloneObjectExpectsAnInstanceOfMetaclass 2.2206
      Moose::Exception::CodeBlockMustBeACodeRef 2.2206
      Moose::Exception::CoercingWithoutCoercions 2.2206
      Moose::Exception::CoercionAlreadyExists 2.2206
      Moose::Exception::CoercionNeedsTypeConstraint 2.2206
      Moose::Exception::ConflictDetectedInCheckRoleExclusions 2.2206
      Moose::Exception::ConflictDetectedInCheckRoleExclusionsInToClass 2.2206
      Moose::Exception::ConstructClassInstanceTakesPackageName 2.2206
      Moose::Exception::CouldNotCreateMethod 2.2206
      Moose::Exception::CouldNotCreateWriter 2.2206
      Moose::Exception::CouldNotEvalConstructor 2.2206
      Moose::Exception::CouldNotEvalDestructor 2.2206
      Moose::Exception::CouldNotFindTypeConstraintToCoerceFrom 2.2206
      Moose::Exception::CouldNotGenerateInlineAttributeMethod 2.2206
      Moose::Exception::CouldNotLocateTypeConstraintForUnion 2.2206
      Moose::Exception::CouldNotParseType 2.2206
      Moose::Exception::CreateMOPClassTakesArrayRefOfAttributes 2.2206
      Moose::Exception::CreateMOPClassTakesArrayRefOfSuperclasses 2.2206
      Moose::Exception::CreateMOPClassTakesHashRefOfMethods 2.2206
      Moose::Exception::CreateTakesArrayRefOfRoles 2.2206
      Moose::Exception::CreateTakesHashRefOfAttributes 2.2206
      Moose::Exception::CreateTakesHashRefOfMethods 2.2206
      Moose::Exception::DefaultToMatchOnTypeMustBeCodeRef 2.2206
      Moose::Exception::DelegationToAClassWhichIsNotLoaded 2.2206
      Moose::Exception::DelegationToARoleWhichIsNotLoaded 2.2206
      Moose::Exception::DelegationToATypeWhichIsNotAClass 2.2206
      Moose::Exception::DoesRequiresRoleName 2.2206
      Moose::Exception::EnumCalledWithAnArrayRefAndAdditionalArgs 2.2206
      Moose::Exception::EnumValuesMustBeString 2.2206
      Moose::Exception::ExtendsMissingArgs 2.2206
      Moose::Exception::HandlesMustBeAHashRef 2.2206
      Moose::Exception::IllegalInheritedOptions 2.2206
      Moose::Exception::IllegalMethodTypeToAddMethodModifier 2.2206
      Moose::Exception::IncompatibleMetaclassOfSuperclass 2.2206
      Moose::Exception::InitMetaRequiresClass 2.2206
      Moose::Exception::InitializeTakesUnBlessedPackageName 2.2206
      Moose::Exception::InstanceBlessedIntoWrongClass 2.2206
      Moose::Exception::InstanceMustBeABlessedReference 2.2206
      Moose::Exception::InvalidArgPassedToMooseUtilMetaRole 2.2206
      Moose::Exception::InvalidArgumentToMethod 2.2206
      Moose::Exception::InvalidArgumentsToTraitAliases 2.2206
      Moose::Exception::InvalidBaseTypeGivenToCreateParameterizedTypeConstraint 2.2206
      Moose::Exception::InvalidHandleValue 2.2206
      Moose::Exception::InvalidHasProvidedInARole 2.2206
      Moose::Exception::InvalidNameForType 2.2206
      Moose::Exception::InvalidOverloadOperator 2.2206
      Moose::Exception::InvalidRoleApplication 2.2206
      Moose::Exception::InvalidTypeConstraint 2.2206
      Moose::Exception::InvalidTypeGivenToCreateParameterizedTypeConstraint 2.2206
      Moose::Exception::InvalidValueForIs 2.2206
      Moose::Exception::IsaDoesNotDoTheRole 2.2206
      Moose::Exception::IsaLacksDoesMethod 2.2206
      Moose::Exception::LazyAttributeNeedsADefault 2.2206
      Moose::Exception::Legacy 2.2206
      Moose::Exception::MOPAttributeNewNeedsAttributeName 2.2206
      Moose::Exception::MatchActionMustBeACodeRef 2.2206
      Moose::Exception::MessageParameterMustBeCodeRef 2.2206
      Moose::Exception::MetaclassIsAClassNotASubclassOfGivenMetaclass 2.2206
      Moose::Exception::MetaclassIsARoleNotASubclassOfGivenMetaclass 2.2206
      Moose::Exception::MetaclassIsNotASubclassOfGivenMetaclass 2.2206
      Moose::Exception::MetaclassMustBeASubclassOfMooseMetaClass 2.2206
      Moose::Exception::MetaclassMustBeASubclassOfMooseMetaRole 2.2206
      Moose::Exception::MetaclassMustBeDerivedFromClassMOPClass 2.2206
      Moose::Exception::MetaclassNotLoaded 2.2206
      Moose::Exception::MetaclassTypeIncompatible 2.2206
      Moose::Exception::MethodExpectedAMetaclassObject 2.2206
      Moose::Exception::MethodExpectsFewerArgs 2.2206
      Moose::Exception::MethodExpectsMoreArgs 2.2206
      Moose::Exception::MethodModifierNeedsMethodName 2.2206
      Moose::Exception::MethodNameConflictInRoles 2.2206
      Moose::Exception::MethodNameNotFoundInInheritanceHierarchy 2.2206
      Moose::Exception::MethodNameNotGiven 2.2206
      Moose::Exception::MustDefineAMethodName 2.2206
      Moose::Exception::MustDefineAnAttributeName 2.2206
      Moose::Exception::MustDefineAnOverloadOperator 2.2206
      Moose::Exception::MustHaveAtLeastOneValueToEnumerate 2.2206
      Moose::Exception::MustPassAHashOfOptions 2.2206
      Moose::Exception::MustPassAMooseMetaRoleInstanceOrSubclass 2.2206
      Moose::Exception::MustPassAPackageNameOrAnExistingClassMOPPackageInstance 2.2206
      Moose::Exception::MustPassEvenNumberOfArguments 2.2206
      Moose::Exception::MustPassEvenNumberOfAttributeOptions 2.2206
      Moose::Exception::MustProvideANameForTheAttribute 2.2206
      Moose::Exception::MustSpecifyAtleastOneMethod 2.2206
      Moose::Exception::MustSpecifyAtleastOneRole 2.2206
      Moose::Exception::MustSpecifyAtleastOneRoleToApplicant 2.2206
      Moose::Exception::MustSupplyAClassMOPAttributeInstance 2.2206
      Moose::Exception::MustSupplyADelegateToMethod 2.2206
      Moose::Exception::MustSupplyAMetaclass 2.2206
      Moose::Exception::MustSupplyAMooseMetaAttributeInstance 2.2206
      Moose::Exception::MustSupplyAnAccessorTypeToConstructWith 2.2206
      Moose::Exception::MustSupplyAnAttributeToConstructWith 2.2206
      Moose::Exception::MustSupplyArrayRefAsCurriedArguments 2.2206
      Moose::Exception::MustSupplyPackageNameAndName 2.2206
      Moose::Exception::NeedsTypeConstraintUnionForTypeCoercionUnion 2.2206
      Moose::Exception::NeitherAttributeNorAttributeNameIsGiven 2.2206
      Moose::Exception::NeitherClassNorClassNameIsGiven 2.2206
      Moose::Exception::NeitherRoleNorRoleNameIsGiven 2.2206
      Moose::Exception::NeitherTypeNorTypeNameIsGiven 2.2206
      Moose::Exception::NoAttributeFoundInSuperClass 2.2206
      Moose::Exception::NoBodyToInitializeInAnAbstractBaseClass 2.2206
      Moose::Exception::NoCasesMatched 2.2206
      Moose::Exception::NoConstraintCheckForTypeConstraint 2.2206
      Moose::Exception::NoDestructorClassSpecified 2.2206
      Moose::Exception::NoImmutableTraitSpecifiedForClass 2.2206
      Moose::Exception::NoParentGivenToSubtype 2.2206
      Moose::Exception::OnlyInstancesCanBeCloned 2.2206
      Moose::Exception::OperatorIsRequired 2.2206
      Moose::Exception::OverloadConflictInSummation 2.2206
      Moose::Exception::OverloadRequiresAMetaClass 2.2206
      Moose::Exception::OverloadRequiresAMetaMethod 2.2206
      Moose::Exception::OverloadRequiresAMetaOverload 2.2206
      Moose::Exception::OverloadRequiresAMethodNameOrCoderef 2.2206
      Moose::Exception::OverloadRequiresAnOperator 2.2206
      Moose::Exception::OverloadRequiresNamesForCoderef 2.2206
      Moose::Exception::OverrideConflictInComposition 2.2206
      Moose::Exception::OverrideConflictInSummation 2.2206
      Moose::Exception::PackageDoesNotUseMooseExporter 2.2206
      Moose::Exception::PackageNameAndNameParamsNotGivenToWrap 2.2206
      Moose::Exception::PackagesAndModulesAreNotCachable 2.2206
      Moose::Exception::ParameterIsNotSubtypeOfParent 2.2206
      Moose::Exception::ReferencesAreNotAllowedAsDefault 2.2206
      Moose::Exception::RequiredAttributeLacksInitialization 2.2206
      Moose::Exception::RequiredAttributeNeedsADefault 2.2206
      Moose::Exception::RequiredMethodsImportedByClass 2.2206
      Moose::Exception::RequiredMethodsNotImplementedByClass 2.2206
      Moose::Exception::Role::Attribute 2.2206
      Moose::Exception::Role::AttributeName 2.2206
      Moose::Exception::Role::Class 2.2206
      Moose::Exception::Role::EitherAttributeOrAttributeName 2.2206
      Moose::Exception::Role::Instance 2.2206
      Moose::Exception::Role::InstanceClass 2.2206
      Moose::Exception::Role::InvalidAttributeOptions 2.2206
      Moose::Exception::Role::Method 2.2206
      Moose::Exception::Role::ParamsHash 2.2206
      Moose::Exception::Role::Role 2.2206
      Moose::Exception::Role::RoleForCreate 2.2206
      Moose::Exception::Role::RoleForCreateMOPClass 2.2206
      Moose::Exception::Role::TypeConstraint 2.2206
      Moose::Exception::RoleDoesTheExcludedRole 2.2206
      Moose::Exception::RoleExclusionConflict 2.2206
      Moose::Exception::RoleNameRequired 2.2206
      Moose::Exception::RoleNameRequiredForMooseMetaRole 2.2206
      Moose::Exception::RolesDoNotSupportAugment 2.2206
      Moose::Exception::RolesDoNotSupportExtends 2.2206
      Moose::Exception::RolesDoNotSupportInner 2.2206
      Moose::Exception::RolesDoNotSupportRegexReferencesForMethodModifiers 2.2206
      Moose::Exception::RolesInCreateTakesAnArrayRef 2.2206
      Moose::Exception::RolesListMustBeInstancesOfMooseMetaRole 2.2206
      Moose::Exception::SingleParamsToNewMustBeHashRef 2.2206
      Moose::Exception::TriggerMustBeACodeRef 2.2206
      Moose::Exception::TypeConstraintCannotBeUsedForAParameterizableType 2.2206
      Moose::Exception::TypeConstraintIsAlreadyCreated 2.2206
      Moose::Exception::TypeParameterMustBeMooseMetaType 2.2206
      Moose::Exception::UnableToCanonicalizeHandles 2.2206
      Moose::Exception::UnableToCanonicalizeNonRolePackage 2.2206
      Moose::Exception::UnableToRecognizeDelegateMetaclass 2.2206
      Moose::Exception::UndefinedHashKeysPassedToMethod 2.2206
      Moose::Exception::UnionCalledWithAnArrayRefAndAdditionalArgs 2.2206
      Moose::Exception::UnionTakesAtleastTwoTypeNames 2.2206
      Moose::Exception::ValidationFailedForInlineTypeConstraint 2.2206
      Moose::Exception::ValidationFailedForTypeConstraint 2.2206
      Moose::Exception::WrapTakesACodeRefToBless 2.2206
      Moose::Exception::WrongTypeConstraintGiven 2.2206
      Moose::Exporter 2.2206
      Moose::Intro 2.2206
      Moose::Manual 2.2206
      Moose::Manual::Attributes 2.2206
      Moose::Manual::BestPractices 2.2206
      Moose::Manual::Classes 2.2206
      Moose::Manual::Concepts 2.2206
      Moose::Manual::Construction 2.2206
      Moose::Manual::Contributing 2.2206
      Moose::Manual::Delegation 2.2206
      Moose::Manual::Delta 2.2206
      Moose::Manual::Exceptions 2.2206
      Moose::Manual::Exceptions::Manifest 2.2206
      Moose::Manual::FAQ 2.2206
      Moose::Manual::MOP 2.2206
      Moose::Manual::MethodModifiers 2.2206
      Moose::Manual::MooseX 2.2206
      Moose::Manual::Resources 2.2206
      Moose::Manual::Roles 2.2206
      Moose::Manual::Support 2.2206
      Moose::Manual::Types 2.2206
      Moose::Manual::Unsweetened 2.2206
      Moose::Meta::Attribute 2.2206
      Moose::Meta::Attribute::Native 2.2206
      Moose::Meta::Attribute::Native::Trait 2.2206
      Moose::Meta::Attribute::Native::Trait::Array 2.2206
      Moose::Meta::Attribute::Native::Trait::Bool 2.2206
      Moose::Meta::Attribute::Native::Trait::Code 2.2206
      Moose::Meta::Attribute::Native::Trait::Counter 2.2206
      Moose::Meta::Attribute::Native::Trait::Hash 2.2206
      Moose::Meta::Attribute::Native::Trait::Number 2.2206
      Moose::Meta::Attribute::Native::Trait::String 2.2206
      Moose::Meta::Class 2.2206
      Moose::Meta::Class::Immutable::Trait 2.2206
      Moose::Meta::Instance 2.2206
      Moose::Meta::Method 2.2206
      Moose::Meta::Method::Accessor 2.2206
      Moose::Meta::Method::Accessor::Native 2.2206
      Moose::Meta::Method::Accessor::Native::Array 2.2206
      Moose::Meta::Method::Accessor::Native::Array::Writer 2.2206
      Moose::Meta::Method::Accessor::Native::Array::accessor 2.2206
      Moose::Meta::Method::Accessor::Native::Array::clear 2.2206
      Moose::Meta::Method::Accessor::Native::Array::count 2.2206
      Moose::Meta::Method::Accessor::Native::Array::delete 2.2206
      Moose::Meta::Method::Accessor::Native::Array::elements 2.2206
      Moose::Meta::Method::Accessor::Native::Array::first 2.2206
      Moose::Meta::Method::Accessor::Native::Array::first_index 2.2206
      Moose::Meta::Method::Accessor::Native::Array::get 2.2206
      Moose::Meta::Method::Accessor::Native::Array::grep 2.2206
      Moose::Meta::Method::Accessor::Native::Array::insert 2.2206
      Moose::Meta::Method::Accessor::Native::Array::is_empty 2.2206
      Moose::Meta::Method::Accessor::Native::Array::join 2.2206
      Moose::Meta::Method::Accessor::Native::Array::map 2.2206
      Moose::Meta::Method::Accessor::Native::Array::natatime 2.2206
      Moose::Meta::Method::Accessor::Native::Array::pop 2.2206
      Moose::Meta::Method::Accessor::Native::Array::push 2.2206
      Moose::Meta::Method::Accessor::Native::Array::reduce 2.2206
      Moose::Meta::Method::Accessor::Native::Array::set 2.2206
      Moose::Meta::Method::Accessor::Native::Array::shallow_clone 2.2206
      Moose::Meta::Method::Accessor::Native::Array::shift 2.2206
      Moose::Meta::Method::Accessor::Native::Array::shuffle 2.2206
      Moose::Meta::Method::Accessor::Native::Array::sort 2.2206
      Moose::Meta::Method::Accessor::Native::Array::sort_in_place 2.2206
      Moose::Meta::Method::Accessor::Native::Array::splice 2.2206
      Moose::Meta::Method::Accessor::Native::Array::uniq 2.2206
      Moose::Meta::Method::Accessor::Native::Array::unshift 2.2206
      Moose::Meta::Method::Accessor::Native::Bool::not 2.2206
      Moose::Meta::Method::Accessor::Native::Bool::set 2.2206
      Moose::Meta::Method::Accessor::Native::Bool::toggle 2.2206
      Moose::Meta::Method::Accessor::Native::Bool::unset 2.2206
      Moose::Meta::Method::Accessor::Native::Code::execute 2.2206
      Moose::Meta::Method::Accessor::Native::Code::execute_method 2.2206
      Moose::Meta::Method::Accessor::Native::Collection 2.2206
      Moose::Meta::Method::Accessor::Native::Counter::Writer 2.2206
      Moose::Meta::Method::Accessor::Native::Counter::dec 2.2206
      Moose::Meta::Method::Accessor::Native::Counter::inc 2.2206
      Moose::Meta::Method::Accessor::Native::Counter::reset 2.2206
      Moose::Meta::Method::Accessor::Native::Counter::set 2.2206
      Moose::Meta::Method::Accessor::Native::Hash 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::Writer 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::accessor 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::clear 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::count 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::defined 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::delete 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::elements 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::exists 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::get 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::is_empty 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::keys 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::kv 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::set 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::shallow_clone 2.2206
      Moose::Meta::Method::Accessor::Native::Hash::values 2.2206
      Moose::Meta::Method::Accessor::Native::Number::abs 2.2206
      Moose::Meta::Method::Accessor::Native::Number::add 2.2206
      Moose::Meta::Method::Accessor::Native::Number::div 2.2206
      Moose::Meta::Method::Accessor::Native::Number::mod 2.2206
      Moose::Meta::Method::Accessor::Native::Number::mul 2.2206
      Moose::Meta::Method::Accessor::Native::Number::set 2.2206
      Moose::Meta::Method::Accessor::Native::Number::sub 2.2206
      Moose::Meta::Method::Accessor::Native::Reader 2.2206
      Moose::Meta::Method::Accessor::Native::String::append 2.2206
      Moose::Meta::Method::Accessor::Native::String::chomp 2.2206
      Moose::Meta::Method::Accessor::Native::String::chop 2.2206
      Moose::Meta::Method::Accessor::Native::String::clear 2.2206
      Moose::Meta::Method::Accessor::Native::String::inc 2.2206
      Moose::Meta::Method::Accessor::Native::String::length 2.2206
      Moose::Meta::Method::Accessor::Native::String::match 2.2206
      Moose::Meta::Method::Accessor::Native::String::prepend 2.2206
      Moose::Meta::Method::Accessor::Native::String::replace 2.2206
      Moose::Meta::Method::Accessor::Native::String::substr 2.2206
      Moose::Meta::Method::Accessor::Native::Writer 2.2206
      Moose::Meta::Method::Augmented 2.2206
      Moose::Meta::Method::Constructor 2.2206
      Moose::Meta::Method::Delegation 2.2206
      Moose::Meta::Method::Destructor 2.2206
      Moose::Meta::Method::Meta 2.2206
      Moose::Meta::Method::Overridden 2.2206
      Moose::Meta::Mixin::AttributeCore 2.2206
      Moose::Meta::Object::Trait 2.2206
      Moose::Meta::Role 2.2206
      Moose::Meta::Role::Application 2.2206
      Moose::Meta::Role::Application::RoleSummation 2.2206
      Moose::Meta::Role::Application::ToClass 2.2206
      Moose::Meta::Role::Application::ToInstance 2.2206
      Moose::Meta::Role::Application::ToRole 2.2206
      Moose::Meta::Role::Attribute 2.2206
      Moose::Meta::Role::Composite 2.2206
      Moose::Meta::Role::Method 2.2206
      Moose::Meta::Role::Method::Conflicting 2.2206
      Moose::Meta::Role::Method::Required 2.2206
      Moose::Meta::TypeCoercion 2.2206
      Moose::Meta::TypeCoercion::Union 2.2206
      Moose::Meta::TypeConstraint 2.2206
      Moose::Meta::TypeConstraint::Class 2.2206
      Moose::Meta::TypeConstraint::DuckType 2.2206
      Moose::Meta::TypeConstraint::Enum 2.2206
      Moose::Meta::TypeConstraint::Parameterizable 2.2206
      Moose::Meta::TypeConstraint::Parameterized 2.2206
      Moose::Meta::TypeConstraint::Registry 2.2206
      Moose::Meta::TypeConstraint::Role 2.2206
      Moose::Meta::TypeConstraint::Union 2.2206
      Moose::Object 2.2206
      Moose::Role 2.2206
      Moose::Spec::Role 2.2206
      Moose::Unsweetened 2.2206
      Moose::Util 2.2206
      Moose::Util::MetaRole 2.2206
      Moose::Util::TypeConstraints 2.2206
      Moose::Util::TypeConstraints::Builtins 2.2206
      Test::Moose 2.2206
      metaclass 2.2206
      oose 2.2206
    requirements:
      Carp 1.22
      Class::Load 0.09
      Class::Load::XS 0.01
      Data::OptList 0.107
      Devel::GlobalDestruction 0
      Devel::OverloadInfo 0.005
      Devel::StackTrace 2.03
      Dist::CheckConflicts 0.02
      Eval::Closure 0.04
      ExtUtils::MakeMaker 0
      List::Util 1.56
      MRO::Compat 0.05
      Module::Runtime 0.014
      Module::Runtime::Conflicts 0.002
      Package::DeprecationManager 0.11
      Package::Stash 0.32
      Package::Stash::XS 0.24
      Params::Util 1.00
      Scalar::Util 1.19
      Sub::Exporter 0.980
      Sub::Util 1.40
      Try::Tiny 0.17
      parent 0.223
      strict 1.03
      warnings 1.03
  Mozilla-CA-20231213
    pathname: L/LW/LWP/Mozilla-CA-20231213.tar.gz
    provides:
      Mozilla::CA 20231213
    requirements:
      ExtUtils::MakeMaker 0
  Net-Abuse-Utils-Spamhaus-0.09
    pathname: S/SA/SAXJAZMAN/net/Net-Abuse-Utils-Spamhaus-0.09.tar.gz
    provides:
      Net::Abuse::Utils::Spamhaus 0.09
    requirements:
      ExtUtils::MakeMaker 6.59
      Net::DNS 0.74
      perl 5.008008
  Net-DNS-1.41
    pathname: N/NL/NLNETLABS/Net-DNS-1.41.tar.gz
    provides:
      Net::DNS 1.41
      Net::DNS::Domain 1913
      Net::DNS::DomainName 1898
      Net::DNS::DomainName1035 1898
      Net::DNS::DomainName2535 1898
      Net::DNS::Header 1910
      Net::DNS::Mailbox 1910
      Net::DNS::Mailbox1035 1910
      Net::DNS::Mailbox2535 1910
      Net::DNS::Nameserver 1949
      Net::DNS::Packet 1947
      Net::DNS::Parameters 1945
      Net::DNS::Question 1895
      Net::DNS::RR 1910
      Net::DNS::RR::A 1896
      Net::DNS::RR::AAAA 1896
      Net::DNS::RR::AFSDB 1945
      Net::DNS::RR::AMTRELAY 1896
      Net::DNS::RR::APL 1896
      Net::DNS::RR::APL::Item 1896
      Net::DNS::RR::CAA 1910
      Net::DNS::RR::CDNSKEY 1909
      Net::DNS::RR::CDS 1909
      Net::DNS::RR::CERT 1896
      Net::DNS::RR::CNAME 1896
      Net::DNS::RR::CSYNC 1910
      Net::DNS::RR::DHCID 1896
      Net::DNS::RR::DNAME 1896
      Net::DNS::RR::DNSKEY 1910
      Net::DNS::RR::DS 1909
      Net::DNS::RR::EUI48 1896
      Net::DNS::RR::EUI64 1896
      Net::DNS::RR::GPOS 1910
      Net::DNS::RR::HINFO 1896
      Net::DNS::RR::HIP 1896
      Net::DNS::RR::HTTPS 1945
      Net::DNS::RR::IPSECKEY 1909
      Net::DNS::RR::ISDN 1896
      Net::DNS::RR::KEY 1896
      Net::DNS::RR::KX 1945
      Net::DNS::RR::L32 1896
      Net::DNS::RR::L64 1896
      Net::DNS::RR::LOC 1896
      Net::DNS::RR::LP 1896
      Net::DNS::RR::MB 1910
      Net::DNS::RR::MG 1910
      Net::DNS::RR::MINFO 1896
      Net::DNS::RR::MR 1910
      Net::DNS::RR::MX 1945
      Net::DNS::RR::NAPTR 1898
      Net::DNS::RR::NID 1896
      Net::DNS::RR::NS 1896
      Net::DNS::RR::NSEC 1945
      Net::DNS::RR::NSEC3 1910
      Net::DNS::RR::NSEC3PARAM 1896
      Net::DNS::RR::NULL 1896
      Net::DNS::RR::OPENPGPKEY 1896
      Net::DNS::RR::OPT 1934
      Net::DNS::RR::OPT::CHAIN 1934
      Net::DNS::RR::OPT::CLIENT_SUBNET 1934
      Net::DNS::RR::OPT::COOKIE 1934
      Net::DNS::RR::OPT::DAU 1934
      Net::DNS::RR::OPT::DHU 1934
      Net::DNS::RR::OPT::EXPIRE 1934
      Net::DNS::RR::OPT::EXTENDED_ERROR 1934
      Net::DNS::RR::OPT::KEY_TAG 1934
      Net::DNS::RR::OPT::N3U 1934
      Net::DNS::RR::OPT::NSID 1934
      Net::DNS::RR::OPT::PADDING 1934
      Net::DNS::RR::OPT::REPORT_CHANNEL 1934
      Net::DNS::RR::OPT::TCP_KEEPALIVE 1934
      Net::DNS::RR::PTR 1896
      Net::DNS::RR::PX 1945
      Net::DNS::RR::RP 1945
      Net::DNS::RR::RRSIG 1896
      Net::DNS::RR::RT 1945
      Net::DNS::RR::SIG 1908
      Net::DNS::RR::SMIMEA 1896
      Net::DNS::RR::SOA 1945
      Net::DNS::RR::SPF 1896
      Net::DNS::RR::SRV 1945
      Net::DNS::RR::SSHFP 1896
      Net::DNS::RR::SVCB 1945
      Net::DNS::RR::TKEY 1908
      Net::DNS::RR::TLSA 1896
      Net::DNS::RR::TSIG 1909
      Net::DNS::RR::TXT 1911
      Net::DNS::RR::URI 1896
      Net::DNS::RR::X25 1896
      Net::DNS::RR::ZONEMD 1896
      Net::DNS::Resolver 1895
      Net::DNS::Resolver::Base 1947
      Net::DNS::Resolver::MSWin32 1856
      Net::DNS::Resolver::Recurse 1930
      Net::DNS::Resolver::UNIX 1856
      Net::DNS::Resolver::android 1856
      Net::DNS::Resolver::cygwin 1856
      Net::DNS::Resolver::os2 1856
      Net::DNS::Resolver::os390 1856
      Net::DNS::Text 1894
      Net::DNS::Update 1895
      Net::DNS::ZoneFile 1910
      Net::DNS::ZoneFile::Generator 1910
      Net::DNS::ZoneFile::Text 1910
    requirements:
      Carp 1.1
      Digest::HMAC 1.03
      Digest::MD5 2.13
      Digest::SHA 5.23
      Encode 2.26
      Exporter 5.63
      ExtUtils::MakeMaker 6.48
      File::Spec 3.29
      Getopt::Long 2.43
      IO::File 1.14
      IO::Select 1.17
      IO::Socket 1.3
      IO::Socket::IP 0.38
      MIME::Base64 2.13
      PerlIO 1.05
      Scalar::Util 1.19
      Time::Local 1.19
      perl 5.008009
  Net-Domain-TLD-1.75
    pathname: A/AL/ALEXP/Net-Domain-TLD-1.75.tar.gz
    provides:
      Net::Domain::TLD 1.75
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      Storable 0
  Net-Google-SafeBrowsing4-0.8
    pathname: J/JS/JSOBRIER/Net-Google-SafeBrowsing4-0.8.tar.gz
    provides:
      Net::Google::SafeBrowsing4 0.8
      Net::Google::SafeBrowsing4::Storage 0.3
      Net::Google::SafeBrowsing4::Storage::File 0.4
      Net::Google::SafeBrowsing4::URI undef
    requirements:
      Carp 0
      Digest::SHA 0
      Exporter 0
      ExtUtils::MakeMaker 0
      HTTP::Message 0
      JSON::XS 0
      LWP::UserAgent 0
      List::BinarySearch 0
      List::Util 0
      MIME::Base64 0
      Net::IP::Lite 0
      Path::Tiny 0
      Storable 0
      Test::LWP::UserAgent 0
      Test::More 0.92
      Test::Pod::Coverage 0
      Text::Trim 0
      Time::HiRes 0
      URI 1.61
      constant 0
  Net-HTTP-6.23
    pathname: O/OA/OALDERS/Net-HTTP-6.23.tar.gz
    provides:
      Net::HTTP 6.23
      Net::HTTP::Methods 6.23
      Net::HTTP::NB 6.23
      Net::HTTPS 6.23
    requirements:
      Carp 0
      Compress::Raw::Zlib 0
      ExtUtils::MakeMaker 0
      IO::Socket::INET 0
      IO::Uncompress::Gunzip 0
      URI 0
      base 0
      perl 5.006002
      strict 0
      warnings 0
  Net-IP-Lite-0.03
    pathname: A/AL/ALEXKOM/Net-IP-Lite-0.03.tar.gz
    provides:
      Net::IP::Lite 0.03
      Net::IP::Lite::Net 0.03
    requirements:
      ExtUtils::MakeMaker 0
      Test::Exception 0
      Test::More 0
  Net-SSLeay-1.92
    pathname: C/CH/CHRISN/Net-SSLeay-1.92.tar.gz
    provides:
      Net::SSLeay 1.92
      Net::SSLeay::Handle 1.92
    requirements:
      English 0
      ExtUtils::MakeMaker 0
      File::Spec::Functions 0
      MIME::Base64 0
      Text::Wrap 0
      constant 0
      perl 5.008001
  NetAddr-IP-4.079
    pathname: M/MI/MIKER/NetAddr-IP-4.079.tar.gz
    provides:
      NetAddr::IP 4.079
      NetAddr::IP::InetBase 0.08
      NetAddr::IP::Lite 1.57
      NetAddr::IP::Util 1.53
      NetAddr::IP::UtilPP 1.09
      NetAddr::IP::UtilPolluted 1.53
      NetAddr::IP::Util_IS 1
    requirements:
      ExtUtils::MakeMaker 0
      Test::More 0
  Package-DeprecationManager-0.18
    pathname: D/DR/DROLSKY/Package-DeprecationManager-0.18.tar.gz
    provides:
      Package::DeprecationManager 0.18
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      List::Util 1.33
      Package::Stash 0
      Params::Util 0
      Sub::Install 0
      Sub::Util 0
      strict 0
      warnings 0
  Package-Stash-0.40
    pathname: E/ET/ETHER/Package-Stash-0.40.tar.gz
    provides:
      Package::Stash 0.40
      Package::Stash::PP 0.40
    requirements:
      B 0
      Carp 0
      Dist::CheckConflicts 0.02
      ExtUtils::MakeMaker 0
      Getopt::Long 0
      Module::Implementation 0.06
      Package::Stash::XS 0.26
      Scalar::Util 0
      Symbol 0
      Text::ParseWords 0
      constant 0
      perl 5.008001
      strict 0
      warnings 0
  Package-Stash-XS-0.30
    pathname: E/ET/ETHER/Package-Stash-XS-0.30.tar.gz
    provides:
      Package::Stash::XS 0.30
    requirements:
      ExtUtils::MakeMaker 0
      XSLoader 0
      perl 5.008001
      strict 0
      warnings 0
  PadWalker-2.5
    pathname: R/RO/ROBIN/PadWalker-2.5.tar.gz
    provides:
      PadWalker 2.5
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.008001
  Params-Util-1.102
    pathname: R/RE/REHSACK/Params-Util-1.102.tar.gz
    provides:
      Params::Util 1.102
      Params::Util::PP 1.102
    requirements:
      Carp 0
      ExtUtils::MakeMaker 0
      File::Basename 0
      File::Copy 0
      File::Path 0
      File::Spec 0
      IPC::Cmd 0
      Scalar::Util 1.18
      XSLoader 0.22
      parent 0
  Path-Tiny-0.144
    pathname: D/DA/DAGOLDEN/Path-Tiny-0.144.tar.gz
    provides:
      Path::Tiny 0.144
      Path::Tiny::Error 0.144
    requirements:
      Carp 0
      Cwd 0
      Digest 1.03
      Digest::SHA 5.45
      Encode 0
      Exporter 5.57
      ExtUtils::MakeMaker 6.17
      Fcntl 0
      File::Compare 0
      File::Copy 0
      File::Glob 0
      File::Path 2.07
      File::Spec 0.86
      File::Temp 0.19
      File::stat 0
      constant 0
      overload 0
      perl 5.008001
      strict 0
      warnings 0
      warnings::register 0
  Pod-Coverage-0.23
    pathname: R/RC/RCLAMP/Pod-Coverage-0.23.tar.gz
    provides:
      Pod::Coverage 0.23
      Pod::Coverage::CountParents undef
      Pod::Coverage::ExportOnly undef
      Pod::Coverage::Extractor 0.23
      Pod::Coverage::Overloader undef
    requirements:
      Devel::Symdump 2.01
      ExtUtils::MakeMaker 0
      Pod::Find 0.21
      Pod::Parser 1.13
      Test::More 0
  Pod-Parser-1.66
    pathname: M/MA/MAREKR/Pod-Parser-1.66.tar.gz
    provides:
      Pod::Cache 1.66
      Pod::Cache::Item 1.66
      Pod::Find 1.66
      Pod::Hyperlink 1.66
      Pod::InputObjects 1.66
      Pod::InputSource 1.66
      Pod::InteriorSequence 1.66
      Pod::List 1.66
      Pod::Paragraph 1.66
      Pod::ParseTree 1.66
      Pod::ParseUtils 1.66
      Pod::Parser 1.66
      Pod::PlainText 2.07
      Pod::Select 1.66
    requirements:
      Cwd 0
      ExtUtils::MakeMaker 0
      File::Basename 0
      Test::More 0.6
  Role-Tiny-2.002004
    pathname: H/HA/HAARG/Role-Tiny-2.002004.tar.gz
    provides:
      Role::Tiny 2.002004
      Role::Tiny::With 2.002004
    requirements:
      Exporter 5.57
      perl 5.006
  SQL-Abstract-2.000001
    pathname: M/MS/MSTROUT/SQL-Abstract-2.000001.tar.gz
    provides:
      Chunkstrumenter undef
      DBIx::Class::SQLMaker::Role::SQLA2Passthrough undef
      SQL::Abstract 2.000001
      SQL::Abstract::Formatter undef
      SQL::Abstract::Parts undef
      SQL::Abstract::Plugin::BangOverrides undef
      SQL::Abstract::Plugin::ExtraClauses undef
      SQL::Abstract::Reference undef
      SQL::Abstract::Role::Plugin undef
      SQL::Abstract::Test undef
      SQL::Abstract::Tree undef
    requirements:
      Exporter 5.57
      ExtUtils::MakeMaker 0
      Hash::Merge 0.12
      List::Util 0
      MRO::Compat 0.12
      Moo 2.000001
      Scalar::Util 0
      Sub::Quote 2.000001
      Test::Builder::Module 0.84
      Test::Deep 0.101
      Text::Balanced 2.00
      perl 5.006
  SQL-Abstract-Pg-1.0
    pathname: S/SR/SRI/SQL-Abstract-Pg-1.0.tar.gz
    provides:
      SQL::Abstract::Pg 1.0
    requirements:
      ExtUtils::MakeMaker 0
      SQL::Abstract 2.0
      perl 5.016
  Safe-Isa-1.000010
    pathname: E/ET/ETHER/Safe-Isa-1.000010.tar.gz
    provides:
      Safe::Isa 1.000010
    requirements:
      Exporter 5.57
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      perl 5.006
  String-CRC32-2.100
    pathname: L/LE/LEEJO/String-CRC32-2.100.tar.gz
    provides:
      String::CRC32 2.100
    requirements:
      ExtUtils::MakeMaker 0
  String-RewritePrefix-0.009
    pathname: R/RJ/RJBS/String-RewritePrefix-0.009.tar.gz
    provides:
      String::RewritePrefix 0.009
    requirements:
      Carp 0
      ExtUtils::MakeMaker 6.78
      Sub::Exporter 0.972
      perl 5.012
      strict 0
      warnings 0
  Sub-Exporter-0.991
    pathname: R/RJ/RJBS/Sub-Exporter-0.991.tar.gz
    provides:
      Sub::Exporter 0.991
      Sub::Exporter::Util 0.991
    requirements:
      Carp 0
      Data::OptList 0.100
      ExtUtils::MakeMaker 6.78
      Params::Util 0.14
      Sub::Install 0.92
      perl 5.012
      strict 0
      warnings 0
  Sub-Exporter-Progressive-0.001013
    pathname: F/FR/FREW/Sub-Exporter-Progressive-0.001013.tar.gz
    provides:
      Sub::Exporter::Progressive 0.001013
    requirements:
      ExtUtils::MakeMaker 0
  Sub-Install-0.929
    pathname: R/RJ/RJBS/Sub-Install-0.929.tar.gz
    provides:
      Sub::Install 0.929
    requirements:
      B 0
      Carp 0
      ExtUtils::MakeMaker 6.78
      Scalar::Util 0
      perl 5.008000
      strict 0
      warnings 0
  Sub-Quote-2.006008
    pathname: H/HA/HAARG/Sub-Quote-2.006008.tar.gz
    provides:
      Sub::Defer 2.006008
      Sub::Quote 2.006008
    requirements:
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      perl 5.006
  Sub-Uplevel-0.2800
    pathname: D/DA/DAGOLDEN/Sub-Uplevel-0.2800.tar.gz
    provides:
      Sub::Uplevel 0.2800
    requirements:
      Carp 0
      ExtUtils::MakeMaker 6.17
      constant 0
      perl 5.006
      strict 0
      warnings 0
  Task-Weaken-1.06
    pathname: E/ET/ETHER/Task-Weaken-1.06.tar.gz
    provides:
      Task::Weaken 1.06
    requirements:
      Config 0
      ExtUtils::MakeMaker 0
      File::Spec 0
      Scalar::Util 1.14
      perl 5.006
      strict 0
  Term-ProgressBar-2.23
    pathname: M/MA/MANWAR/Term-ProgressBar-2.23.tar.gz
    provides:
      Term::ProgressBar 2.23
      Term::ProgressBar::IO 2.23
    requirements:
      Capture::Tiny 0.13
      Carp 0
      Class::MethodMaker 1.02
      ExtUtils::MakeMaker 0
      Fatal 0
      File::Temp 0
      POSIX 0
      Term::ReadKey 2.14
      Test::Exception 0.31
      Test::More 0.80
      Test::Warnings 0
      perl 5.006
  Term-ProgressBar-Quiet-0.31
    pathname: L/LB/LBROCARD/Term-ProgressBar-Quiet-0.31.tar.gz
    provides:
      Term::ProgressBar::Quiet 0.31
    requirements:
      ExtUtils::MakeMaker 0
      IO::Interactive 0
      Term::ProgressBar 0
      Test::MockObject 0
      Test::More 0
  TermReadKey-2.38
    pathname: J/JS/JSTOWE/TermReadKey-2.38.tar.gz
    provides:
      Term::ReadKey 2.38
    requirements:
      ExtUtils::MakeMaker 6.58
  Test-Deep-1.204
    pathname: R/RJ/RJBS/Test-Deep-1.204.tar.gz
    provides:
      Test::Deep 1.204
      Test::Deep::All 1.204
      Test::Deep::Any 1.204
      Test::Deep::Array 1.204
      Test::Deep::ArrayEach 1.204
      Test::Deep::ArrayElementsOnly 1.204
      Test::Deep::ArrayLength 1.204
      Test::Deep::ArrayLengthOnly 1.204
      Test::Deep::Blessed 1.204
      Test::Deep::Boolean 1.204
      Test::Deep::Cache 1.204
      Test::Deep::Cache::Simple 1.204
      Test::Deep::Class 1.204
      Test::Deep::Cmp 1.204
      Test::Deep::Code 1.204
      Test::Deep::Hash 1.204
      Test::Deep::HashEach 1.204
      Test::Deep::HashElements 1.204
      Test::Deep::HashKeys 1.204
      Test::Deep::HashKeysOnly 1.204
      Test::Deep::Ignore 1.204
      Test::Deep::Isa 1.204
      Test::Deep::ListMethods 1.204
      Test::Deep::MM 1.204
      Test::Deep::Methods 1.204
      Test::Deep::NoTest 1.204
      Test::Deep::None 1.204
      Test::Deep::Number 1.204
      Test::Deep::Obj 1.204
      Test::Deep::Ref 1.204
      Test::Deep::RefType 1.204
      Test::Deep::Regexp 1.204
      Test::Deep::RegexpMatches 1.204
      Test::Deep::RegexpOnly 1.204
      Test::Deep::RegexpRef 1.204
      Test::Deep::RegexpRefOnly 1.204
      Test::Deep::RegexpVersion 1.204
      Test::Deep::ScalarRef 1.204
      Test::Deep::ScalarRefOnly 1.204
      Test::Deep::Set 1.204
      Test::Deep::Shallow 1.204
      Test::Deep::Stack 1.204
      Test::Deep::String 1.204
      Test::Deep::SubHash 1.204
      Test::Deep::SubHashElements 1.204
      Test::Deep::SubHashKeys 1.204
      Test::Deep::SubHashKeysOnly 1.204
      Test::Deep::SuperHash 1.204
      Test::Deep::SuperHashElements 1.204
      Test::Deep::SuperHashKeys 1.204
      Test::Deep::SuperHashKeysOnly 1.204
    requirements:
      ExtUtils::MakeMaker 6.78
      List::Util 1.09
      Scalar::Util 1.09
      Test::Builder 0
      Test::More 0.96
      perl 5.012
  Test-Exception-0.43
    pathname: E/EX/EXODIST/Test-Exception-0.43.tar.gz
    provides:
      Test::Exception 0.43
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      Sub::Uplevel 0.18
      Test::Builder 0.7
      Test::Builder::Tester 1.07
      Test::Harness 2.03
      base 0
      perl 5.006001
      strict 0
      warnings 0
  Test-Fatal-0.017
    pathname: R/RJ/RJBS/Test-Fatal-0.017.tar.gz
    provides:
      Test::Fatal 0.017
    requirements:
      Carp 0
      Exporter 5.57
      ExtUtils::MakeMaker 6.78
      Test::Builder 0
      Try::Tiny 0.07
      strict 0
      warnings 0
  Test-LWP-UserAgent-0.036
    pathname: E/ET/ETHER/Test-LWP-UserAgent-0.036.tar.gz
    provides:
      Test::LWP::UserAgent 0.036
    requirements:
      CPAN::Meta::Requirements 2.120620
      Carp 0
      ExtUtils::MakeMaker 0
      HTTP::Date 0
      HTTP::Request 0
      HTTP::Response 0
      HTTP::Status 0
      LWP::UserAgent 0
      Module::Metadata 0
      Safe::Isa 0
      Scalar::Util 0
      Storable 0
      Try::Tiny 0
      URI 1.62
      namespace::clean 0.19
      parent 0
      perl 5.006
      strict 0
      warnings 0
  Test-Memory-Cycle-1.06
    pathname: P/PE/PETDANCE/Test-Memory-Cycle-1.06.tar.gz
    provides:
      Test::Memory::Cycle 1.06
    requirements:
      Devel::Cycle 1.07
      ExtUtils::MakeMaker 0
      Getopt::Long 0
      PadWalker 0
      Test::Builder 0
      Test::Builder::Tester 0
      Test::More 0
      Test::Simple 0.62
  Test-MockObject-1.20200122
    pathname: C/CH/CHROMATIC/Test-MockObject-1.20200122.tar.gz
    provides:
      Test::MockObject 1.20200122
      Test::MockObject::Extends 1.20200122
    requirements:
      Carp 0
      Devel::Peek 0
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      Test::Builder 0
      UNIVERSAL::can 1.20110617
      UNIVERSAL::isa 1.20110614
      constant 0
      perl 5.008
      strict 0
      warnings 0
  Test-Output-1.034
    pathname: B/BD/BDFOY/Test-Output-1.034.tar.gz
    provides:
      Test::Output 1.034
    requirements:
      Capture::Tiny 0.17
      ExtUtils::MakeMaker 6.64
      File::Spec::Functions 0
      File::Temp 0.17
      perl 5.008
  Test-Pod-Coverage-1.10
    pathname: N/NE/NEILB/Test-Pod-Coverage-1.10.tar.gz
    provides:
      Test::Pod::Coverage 1.10
    requirements:
      ExtUtils::MakeMaker 0
      Pod::Coverage 0
      Test::Builder 0
      perl 5.006
      strict 0
      warnings 0
  Test-Warnings-0.032
    pathname: E/ET/ETHER/Test-Warnings-0.032.tar.gz
    provides:
      Test::Warnings 0.032
    requirements:
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      Test::Builder 0
      parent 0
      perl 5.006
      strict 0
      warnings 0
  Text-Soundex-3.05
    pathname: R/RJ/RJBS/Text-Soundex-3.05.tar.gz
    provides:
      Text::Soundex 3.05
    requirements:
      ExtUtils::MakeMaker 0
      if 0
  Text-Trim-1.04
    pathname: R/RJ/RJT/Text-Trim-1.04.tar.gz
    provides:
      Text::Trim 1.04
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.006
  Time-Duration-1.21
    pathname: N/NE/NEILB/Time-Duration-1.21.tar.gz
    provides:
      Time::Duration 1.21
    requirements:
      Exporter 0
      ExtUtils::MakeMaker 0
      constant 0
      perl 5.006
      strict 0
      warnings 0
  Time-Duration-Parse-0.16
    pathname: N/NE/NEILB/Time-Duration-Parse-0.16.tar.gz
    provides:
      Time::Duration::Parse 0.16
    requirements:
      Carp 0
      Exporter 5.57
      ExtUtils::MakeMaker 0
      perl 5.006
      strict 0
      warnings 0
  TimeDate-2.33
    pathname: A/AT/ATOOMIC/TimeDate-2.33.tar.gz
    provides:
      Date::Format 2.24
      Date::Format::Generic 2.24
      Date::Language 1.10
      Date::Language::Afar 0.99
      Date::Language::Amharic 1.00
      Date::Language::Austrian 1.01
      Date::Language::Brazilian 1.01
      Date::Language::Bulgarian 1.01
      Date::Language::Chinese 1.00
      Date::Language::Chinese_GB 1.01
      Date::Language::Czech 1.01
      Date::Language::Danish 1.01
      Date::Language::Dutch 1.02
      Date::Language::English 1.01
      Date::Language::Finnish 1.01
      Date::Language::French 1.04
      Date::Language::Gedeo 0.99
      Date::Language::German 1.02
      Date::Language::Greek 1.00
      Date::Language::Hungarian 1.01
      Date::Language::Icelandic 1.01
      Date::Language::Italian 1.01
      Date::Language::Norwegian 1.01
      Date::Language::Occitan 1.04
      Date::Language::Oromo 0.99
      Date::Language::Romanian 1.01
      Date::Language::Russian 1.01
      Date::Language::Russian_cp1251 1.01
      Date::Language::Russian_koi8r 1.01
      Date::Language::Sidama 0.99
      Date::Language::Somali 0.99
      Date::Language::Spanish 1.00
      Date::Language::Swedish 1.01
      Date::Language::Tigrinya 1.00
      Date::Language::TigrinyaEritrean 1.00
      Date::Language::TigrinyaEthiopian 1.00
      Date::Language::Turkish 1.0
      Date::Parse 2.33
      Time::Zone 2.24
      TimeDate 1.21
    requirements:
      ExtUtils::MakeMaker 0
  Try-Tiny-0.31
    pathname: E/ET/ETHER/Try-Tiny-0.31.tar.gz
    provides:
      Try::Tiny 0.31
    requirements:
      Carp 0
      Exporter 5.57
      ExtUtils::MakeMaker 0
      constant 0
      perl 5.006
      strict 0
      warnings 0
  Types-Serialiser-1.01
    pathname: M/ML/MLEHMANN/Types-Serialiser-1.01.tar.gz
    provides:
      JSON::PP::Boolean 1.01
      Types::Serialiser 1.01
      Types::Serialiser::BooleanBase 1.01
      Types::Serialiser::Error 1.01
    requirements:
      ExtUtils::MakeMaker 0
      common::sense 0
  UNIVERSAL-can-1.20140328
    pathname: C/CH/CHROMATIC/UNIVERSAL-can-1.20140328.tar.gz
    provides:
      UNIVERSAL::can 1.20140328
    requirements:
      ExtUtils::MakeMaker 6.30
      Scalar::Util 0
      strict 0
      vars 0
      warnings 0
      warnings::register 0
  UNIVERSAL-isa-1.20171012
    pathname: E/ET/ETHER/UNIVERSAL-isa-1.20171012.tar.gz
    provides:
      UNIVERSAL::isa 1.20171012
    requirements:
      ExtUtils::MakeMaker 0
      Scalar::Util 0
      perl 5.006002
      strict 0
      warnings 0
      warnings::register 0
  URI-5.21
    pathname: O/OA/OALDERS/URI-5.21.tar.gz
    provides:
      URI 5.21
      URI::Escape 5.21
      URI::Heuristic 5.21
      URI::IRI 5.21
      URI::QueryParam 5.21
      URI::Split 5.21
      URI::URL 5.21
      URI::WithBase 5.21
      URI::data 5.21
      URI::file 5.21
      URI::file::Base 5.21
      URI::file::FAT 5.21
      URI::file::Mac 5.21
      URI::file::OS2 5.21
      URI::file::QNX 5.21
      URI::file::Unix 5.21
      URI::file::Win32 5.21
      URI::ftp 5.21
      URI::gopher 5.21
      URI::http 5.21
      URI::https 5.21
      URI::icap 5.21
      URI::icaps 5.21
      URI::ldap 5.21
      URI::ldapi 5.21
      URI::ldaps 5.21
      URI::mailto 5.21
      URI::mms 5.21
      URI::news 5.21
      URI::nntp 5.21
      URI::nntps 5.21
      URI::pop 5.21
      URI::rlogin 5.21
      URI::rsync 5.21
      URI::rtsp 5.21
      URI::rtspu 5.21
      URI::sftp 5.21
      URI::sip 5.21
      URI::sips 5.21
      URI::snews 5.21
      URI::ssh 5.21
      URI::telnet 5.21
      URI::tn3270 5.21
      URI::urn 5.21
      URI::urn::isbn 5.21
      URI::urn::oid 5.21
    requirements:
      Carp 0
      Cwd 0
      Data::Dumper 0
      Encode 0
      Exporter 5.57
      ExtUtils::MakeMaker 0
      MIME::Base64 2
      Net::Domain 0
      Scalar::Util 0
      constant 0
      integer 0
      overload 0
      parent 0
      perl 5.008001
      strict 0
      utf8 0
      warnings 0
  URI-Nested-0.10
    pathname: D/DW/DWHEELER/URI-Nested-0.10.tar.gz
    provides:
      URI::Nested 0.10
    requirements:
      Module::Build 0.30
      Test::More 0.88
      URI 1.40
      perl 5.008001
  URI-db-0.21
    pathname: D/DW/DWHEELER/URI-db-0.21.tar.gz
    provides:
      URI::cassandra 0.21
      URI::cockroach 0.21
      URI::cockroachdb 0.21
      URI::couch 0.21
      URI::couchdb 0.21
      URI::cubrid 0.21
      URI::db 0.21
      URI::db2 0.21
      URI::derby 0.21
      URI::exasol 0.21
      URI::firebird 0.21
      URI::hive 0.21
      URI::impala 0.21
      URI::informix 0.21
      URI::ingres 0.21
      URI::interbase 0.21
      URI::ldapdb 0.21
      URI::maria 0.21
      URI::mariadb 0.21
      URI::max 0.21
      URI::maxdb 0.21
      URI::monet 0.21
      URI::monetdb 0.21
      URI::mongo 0.21
      URI::mongodb 0.21
      URI::mssql 0.21
      URI::mysql 0.21
      URI::oracle 0.21
      URI::pg 0.21
      URI::pgsql 0.21
      URI::pgxc 0.21
      URI::postgres 0.21
      URI::postgresql 0.21
      URI::postgresxc 0.21
      URI::redshift 0.21
      URI::snowflake 0.21
      URI::sqlite 0.21
      URI::sqlite3 0.21
      URI::sqlserver 0.21
      URI::sybase 0.21
      URI::teradata 0.21
      URI::unify 0.21
      URI::vertica 0.21
      URI::yugabyte 0.21
      URI::yugabytedb 0.21
    requirements:
      Module::Build 0.30
      Test::More 0.88
      URI 1.40
      URI::Nested 0.10
      perl 5.008001
  Variable-Magic-0.63
    pathname: V/VP/VPIT/Variable-Magic-0.63.tar.gz
    provides:
      Variable::Magic 0.63
    requirements:
      Carp 0
      Config 0
      Exporter 0
      ExtUtils::MakeMaker 0
      IO::Handle 0
      IO::Select 0
      IPC::Open3 0
      POSIX 0
      Socket 0
      Test::More 0
      XSLoader 0
      base 0
      lib 0
      perl 5.008
  WWW-RobotRules-6.02
    pathname: G/GA/GAAS/WWW-RobotRules-6.02.tar.gz
    provides:
      WWW::RobotRules 6.02
      WWW::RobotRules::AnyDBM_File 6.00
      WWW::RobotRules::InCore 6.02
    requirements:
      AnyDBM_File 0
      ExtUtils::MakeMaker 0
      Fcntl 0
      URI 1.10
      perl 5.008001
  YAML-LibYAML-0.88
    pathname: I/IN/INGY/YAML-LibYAML-0.88.tar.gz
    provides:
      YAML::LibYAML 0.88
      YAML::XS 0.88
      YAML::XS::LibYAML undef
    requirements:
      ExtUtils::MakeMaker 0
      perl 5.008001
  YAML-Tiny-1.74
    pathname: E/ET/ETHER/YAML-Tiny-1.74.tar.gz
    provides:
      YAML::Tiny 1.74
    requirements:
      B 0
      Carp 0
      Exporter 0
      ExtUtils::MakeMaker 0
      Fcntl 0
      Scalar::Util 0
      perl 5.008001
      strict 0
      warnings 0
  common-sense-3.75
    pathname: M/ML/MLEHMANN/common-sense-3.75.tar.gz
    provides:
      common::sense 3.75
    requirements:
      ExtUtils::MakeMaker 0
  libwww-perl-6.72
    pathname: O/OA/OALDERS/libwww-perl-6.72.tar.gz
    provides:
      LWP 6.72
      LWP::Authen::Basic 6.72
      LWP::Authen::Digest 6.72
      LWP::Authen::Ntlm 6.72
      LWP::ConnCache 6.72
      LWP::Debug 6.72
      LWP::Debug::TraceHTTP 6.72
      LWP::DebugFile 6.72
      LWP::MemberMixin 6.72
      LWP::Protocol 6.72
      LWP::Protocol::cpan 6.72
      LWP::Protocol::data 6.72
      LWP::Protocol::file 6.72
      LWP::Protocol::ftp 6.72
      LWP::Protocol::gopher 6.72
      LWP::Protocol::http 6.72
      LWP::Protocol::loopback 6.72
      LWP::Protocol::mailto 6.72
      LWP::Protocol::nntp 6.72
      LWP::Protocol::nogo 6.72
      LWP::RobotUA 6.72
      LWP::Simple 6.72
      LWP::UserAgent 6.72
    requirements:
      Digest::MD5 0
      Encode 2.12
      Encode::Locale 0
      ExtUtils::MakeMaker 0
      File::Copy 0
      File::Listing 6
      File::Temp 0
      Getopt::Long 0
      HTML::Entities 0
      HTML::HeadParser 3.71
      HTTP::CookieJar::LWP 0
      HTTP::Cookies 6
      HTTP::Date 6
      HTTP::Negotiate 6
      HTTP::Request 6.18
      HTTP::Request::Common 6.18
      HTTP::Response 6.18
      HTTP::Status 6.18
      IO::Select 0
      IO::Socket 0
      LWP::MediaTypes 6
      MIME::Base64 2.1
      Module::Load 0
      Net::FTP 2.58
      Net::HTTP 6.18
      Scalar::Util 0
      Try::Tiny 0
      URI 1.10
      URI::Escape 0
      WWW::RobotRules 6
      parent 0.217
      perl 5.008001
      strict 0
      warnings 0
  namespace-clean-0.27
    pathname: R/RI/RIBASUSHI/namespace-clean-0.27.tar.gz
    provides:
      namespace::clean 0.27
    requirements:
      B::Hooks::EndOfScope 0.12
      ExtUtils::MakeMaker 0
      Package::Stash 0.23
      perl 5.008001
  perl-ldap-0.68
    pathname: M/MA/MARSCHAP/perl-ldap-0.68.tar.gz
    provides:
      Bundle::Net::LDAP 0.03
      LWP::Protocol::ldap 1.25
      LWP::Protocol::ldapi undef
      LWP::Protocol::ldaps undef
      Net::LDAP 0.68
      Net::LDAP::ASN 0.13
      Net::LDAP::Bind 1.05
      Net::LDAP::Constant 0.24
      Net::LDAP::Control 0.20
      Net::LDAP::Control::Assertion 0.02
      Net::LDAP::Control::DontUseCopy 0.02
      Net::LDAP::Control::EntryChange 0.02
      Net::LDAP::Control::ManageDsaIT 0.04
      Net::LDAP::Control::MatchedValues 0.02
      Net::LDAP::Control::NoOp 0.01
      Net::LDAP::Control::Paged 0.05
      Net::LDAP::Control::PasswordPolicy 0.04
      Net::LDAP::Control::PersistentSearch 0.04
      Net::LDAP::Control::PostRead 0.03
      Net::LDAP::Control::PreRead 0.04
      Net::LDAP::Control::ProxyAuth 1.09
      Net::LDAP::Control::Relax 0.03
      Net::LDAP::Control::Sort 0.04
      Net::LDAP::Control::SortResult 0.03
      Net::LDAP::Control::Subentries 0.01
      Net::LDAP::Control::SyncDone 0.03
      Net::LDAP::Control::SyncRequest 0.03
      Net::LDAP::Control::SyncState 0.04
      Net::LDAP::Control::TreeDelete 0.01
      Net::LDAP::Control::VLV 0.07
      Net::LDAP::Control::VLVResponse 0.04
      Net::LDAP::DSML 0.17
      Net::LDAP::DSML::output 0.17
      Net::LDAP::DSML::pp 0.17
      Net::LDAP::Entry 0.29
      Net::LDAP::Extension 1.04
      Net::LDAP::Extension::Cancel 0.02
      Net::LDAP::Extension::Refresh 0.04
      Net::LDAP::Extension::SetPassword 0.06
      Net::LDAP::Extension::WhoAmI 0.02
      Net::LDAP::Extra 0.02
      Net::LDAP::Extra::AD 0.05
      Net::LDAP::Extra::eDirectory 0.03
      Net::LDAP::Filter 0.20
      Net::LDAP::FilterList 0.02
      Net::LDAP::FilterMatch 0.27
      Net::LDAP::Intermediate 0.04
      Net::LDAP::Intermediate::SyncInfo 0.03
      Net::LDAP::LDIF 0.27
      Net::LDAP::Message 1.12
      Net::LDAP::Message::Dummy 1.12
      Net::LDAP::Reference 0.14
      Net::LDAP::RootDSE 0.02
      Net::LDAP::Schema 0.9908
      Net::LDAP::Search 0.14
      Net::LDAP::Util 0.20
      Net::LDAPI 0.04
      Net::LDAPS 0.06
    requirements:
      Authen::SASL 2.00
      Convert::ASN1 0.2
      Digest::HMAC_MD5 0
      Digest::MD5 0
      ExtUtils::MakeMaker 6.59
      File::Basename 0
      File::Compare 0
      File::Path 0
      HTTP::Negotiate 0
      HTTP::Response 0
      HTTP::Status 0
      IO::File 0
      IO::Socket::SSL 1.26
      JSON 0
      LWP 0
      LWP::MediaTypes 0
      LWP::Protocol 0
      MIME::Base64 0
      Test::More 0
      Text::Soundex 0
      Time::Local 0
      URI::ldap 1.1
      perl 5.008001


================================================
FILE: docker/entrypoint.sh
================================================
#!/bin/sh

set -eu

cd ~lstu

if [ "${1:-}" == "dev" ]
then
    echo ""
    echo ""
    echo "Container started in dev mode. Connect to the container with the following command:"
    echo "    docker-compose -f docker-compose.dev.yml exec -u root app_dev sh"
    echo ""
    echo ""
    echo "You can then install the build dependencies with this command"
    echo "    apk --update add vim build-base perl-utils perl-dev make sudo zlib-dev libpng-dev postgresql-dev mariadb-dev"
    
    tail -f /dev/null
    exit 0
fi

# If MySQL/PostgreSQL, wait for database to be up
DB_TYPE=$(perl utilities/read_conf.pl dbtype)
DB_HOST=
DB_PORT=
if [ "$DB_TYPE" == "mysql" ]
then
    DB_HOST=$(perl utilities/read_conf.pl mysqldb/host db)
    DB_PORT=$(perl utilities/read_conf.pl mysqldb/port 3306)
fi
if [ "$DB_TYPE" == "postgresql" ]
then
    DB_HOST=$(perl utilities/read_conf.pl pgdb/host db)
    DB_PORT=$(perl utilities/read_conf.pl pgdb/port 5432)
fi
if [ -n "$DB_HOST" -a -n "$DB_PORT" ]
then
    while ! nc -vz "${DB_HOST}" "${DB_PORT}"; do
        echo "Waiting for database..."
        sleep 1;
    done
fi

if [ "${1:-}" == "minion" ]
then
    exec carton exec script/application minion worker
fi

exec carton exec hypnotoad -f script/lstu

================================================
FILE: docker-compose.dev.yml
================================================
version: '3.3'

services:
    app_dev:
        build: .
        ports:
            - 8080:8080
        volumes:
            - .:/home/lstu
        command: dev
    mariadb_dev:
        image: mariadb:10.2
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: lstu
    postgres_dev:
        image: postgres:10.3-alpine
        environment:
            POSTGRES_PASSWORD: password
            POSTGRES_USER: lstu
            POSTGRES_DB: lstu
    memcached:
        image: memcached:1.5-alpine
    adminer:
        image: dehy/adminer
        ports:
            - 8081:80

================================================
FILE: docker-compose.yml
================================================
version: '3.3'

services:
    app:
        build: .
        ports:
            - 8080:8080
        volumes:
            - ./lstu.conf:/home/lstu/lstu.conf:ro
    db:
        image: mariadb:10.2
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: lstu
    cache:
        image: memcached:1.5-alpine
    minion:
        build: .
        command: minion
        volumes:
            - ./lstu.conf:/home/lstu/lstu.conf:ro
    minion_db:
        image: mariadb:10.2
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: lstu_minion

================================================
FILE: docker-stack.yml
================================================
version: '3.3'

services:
    app:
        image: aquinum/lstu
        configs:
            - source: lstu.conf
              target: /home/lstu/lstu.conf
              uid: '1000'
              gid: '1000'
              mode: 0440
        deploy:
            replicas: 1
    db:
        image: mariadb:10.2
        environment:
            MYSQL_ROOT_PASSWORD: <changeme>
            MYSQL_DATABASE: lstu
    cache:
        image: memcached:1.5-alpine
    minion:
        image: aquinum/lstu
        command: minion
        configs:
            - source: lstu.conf
              target: /home/lstu/lstu.conf
              uid: '1000'
              gid: '1000'
              mode: 0440
    minion_db:
        image: mariadb:10.2
        environment:
            MYSQL_ROOT_PASSWORD: <changeme>
            MYSQL_DATABASE: lstu_minion

configs:
    lstu.conf:
        file: ./lstu.conf

================================================
FILE: hooks/build
================================================
#!/bin/bash

# https://medium.com/microscaling-systems/labelling-automated-builds-on-docker-hub-f3d073fb8e1#.yldbwesu7

if [ -z "${IMAGE_NAME}" ]; then
    echo ! "IMAGE_NAME" variable missing.
    echo eg. IMAGE_NAME="aquinum/lstu:local" sh $0
    exit 1
fi

function evil_git_dirty {
    [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "-dirty"
}

function last_tag {
    git describe --abbrev=0
}

function version_number_plus {
    [[ $(git rev-list --count ${1}..HEAD) -gt 0 ]] && echo "+"
}

VERSION=$(last_tag)
VERSION=${VERSION}$(version_number_plus ${VERSION})
VCS_REF=$(git rev-parse --short HEAD)$(evil_git_dirty)
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

docker build --build-arg VCS_REF=${VCS_REF} \
             --build-arg BUILD_DATE=${BUILD_DATE} \
             --build-arg VERSION=${VERSION} \
             -t $IMAGE_NAME .


================================================
FILE: lib/Lstu/Command/ban.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Command::ban;
use Mojo::Base 'Mojolicious::Command';
use FindBin qw($Bin);
use File::Spec qw(catfile);
use Mojo::Util qw(getopt);
use Lstu::DB::Ban;

has description => 'Ban IPs addresses for ten years, or unban them';
has usage => sub { shift->extract_usage };

sub run {
    my $c = shift;
    my @args = @_;


    getopt \@args,
      'b|ban=s{1,}'   => \my @ban_ips,
      'u|unban=s{1,}' => \my @unban_ips;

    for my $ip (@ban_ips) {
        Lstu::DB::Ban->new(
            app    => $c->app,
            ip     => $ip
        )->ban_ten_years;
    }
    say sprintf("%d banned IP addresses", scalar(@ban_ips)) if (@ban_ips);

    for my $ip (@unban_ips) {
        Lstu::DB::Ban->new(
            app    => $c->app,
            ip     => $ip
        )->unban;
    }
    say sprintf("%d unbanned IP addresses", scalar(@unban_ips)) if (@unban_ips);

    say $c->extract_usage unless (scalar(@ban_ips) || scalar(@unban_ips));
}

=encoding utf8

=head1 NAME

Lstu::Command::ban - Ban IPs addresses for ten years, or unban them

=head1 SYNOPSIS

  Usage:
      carton exec script/lstu ban -b|--ban <ip> <ip>    Ban the space separated IP addresses for ten years
      carton exec script/lstu ban -u|--unban <ip> <ip>  Unban the space separated IP addresses

  Please note that you can pass the --ban and --unban options at the same time.

=cut

1;


================================================
FILE: lib/Lstu/Command/safebrowsingcheck.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Command::safebrowsingcheck;
use Mojo::Base 'Mojolicious::Command';
use FindBin qw($Bin);
use File::Spec qw(catfile);
use Term::ProgressBar::Quiet;
use Mojo::Util qw(getopt);
use Mojo::Collection 'c';
use Lstu::DB::URL;
use Lstu::DB::Ban;

has description => 'Checks all URLs in database against Google Safe Browsing database (local copy)';
has usage => sub { shift->extract_usage };

sub run {
    my $c = shift;
    my @args = @_;

    getopt \@args,
      'u|url=s{1,}'  => \my @urls_to_check,
      't|test=s{1,}' => \my @urls_to_test,
      's|seconds=i'  => \my $delay,
      'r|remove'     => \my $remove,
      'a|all'        => \my $all,
      'b|ban'        => \my $ban;

    if ($c->app->gsb) {
        my $urls;
        if (@urls_to_check) {
            $urls = c(get_shorts($c, @urls_to_check));
        } elsif ($delay) {
            $urls = Lstu::DB::URL->new(app => $c->app)->get_all_urls_created_ago($delay);
        } elsif (@urls_to_test) {
            $urls = c(@urls_to_test);
        } else {
            $urls = Lstu::DB::URL->new(app => $c->app)->get_all_urls;
        }

        unless ($urls->size) {
            say 'No URLs to check.';
            exit;
        }

        my $progress = Term::ProgressBar::Quiet->new(
            { name => 'Scanning '.$urls->size.' URLs', count => $urls->size, ETA => 'linear' }
        );
        my (@bad, %bad_ips, @bad_from_ips);
        my $gsb     = $c->app->gsb;
        my $disabled = 0;
        my @testing_results;
        $urls->each(sub {
            my ($e, $num) = @_;
            my $u = (@urls_to_test) ? $e : $e->{url};

            $progress->update($num);

            my @matches = $gsb->lookup(url => $u);

            if (@matches) {
                if (@urls_to_test) {
                    push @testing_results, sprintf('%s is in GSB base!', $e);
                } else {
                    push @bad, $e->{short};
                    $bad_ips{$e->{created_by}} = 1 if $e->{created_by};
                    $disabled += Lstu::DB::URL->new(
                        app => $c->app,
                        short => $e->{short}
                    )->remove if $remove;
                }
            } elsif (@urls_to_test) {
                push @testing_results, sprintf('%s is safe.', $e);
            }
        });
        if (@urls_to_test) {
            map {say $_;} @testing_results;
            exit;
        }

        say sprintf('All URLs (%d) have been scanned.', $urls->size);
        say sprintf('%d bad URLs detected.', scalar(@bad));

        if ($remove) {
            say sprintf('%d bad URLs disabled.', $disabled) if $disabled;
        } else {
            say sprintf("If you want to disable the detected bad URLs, please do:\n  carton exec script/lstu url --remove %s", join(' ', @bad)) if @bad;
        }

        $disabled = 0;
        for my $ip (keys %bad_ips) {
            my $u = Lstu::DB::URL->new(app => $c->app)->search_creator($ip);
            $u->each(sub {
                my ($e, $num) = @_;
                push @bad_from_ips, $e->{short};
                $disabled += Lstu::DB::URL->new(
                    app => $c->app,
                    short => $e->{short}
                )->remove if ($remove && $all);
            });
        }
        my @ips = keys %bad_ips;
        say sprintf("Bad URLs creators' IP addresses: \n  %s", join(", ", @ips)) if (@ips);

        if ($ban) {
            for my $ip (@ips) {
                Lstu::DB::Ban->new(
                    app    => $c->app,
                    ip     => $ip
                )->ban_ten_years;
            }
            say sprintf("%d banned IP addresses", scalar(@ips)) if (@ips);
        }

        if ($remove && $all) {
            say sprintf('%d URLs from same IPs disabled.', $disabled) if $disabled;
        } else {
            say sprintf("If you want to disable the URLs created by the same IPs than the detected bad URLs, please do:\n  carton exec script/lstu url --remove %s", join(' ', @bad_from_ips)) if @bad_from_ips;
        }
    } else {
        say 'It seems that safebrowsing_api_key isn\'t set. Please, check your configuration';
    }
}

sub get_shorts {
    my $c      = shift;
    my @shorts = @_;

    my @results;

    for my $short (@shorts) {
        my $u = Lstu::DB::URL->new(app => $c->app, short => $short);
        if ($u->url && !$u->disabled) {
            push @results, $u->to_hash;
        } else {
            say sprintf('Sorry, unable to find an URL with short = %s', $short);
        }
    }
    return @results;
}

=encoding utf8

=head1 NAME

Lstu::Command::safebrowsing - Checks all URLs in database against Google Safe Browsing database (local copy)

=head1 SYNOPSIS

  Usage:
      carton exec script/lstu safebrowsingcheck                          Checks all URLs in database against Google Safe Browsing database
      carton exec script/lstu safebrowsingcheck -u|--url <short> <short> Checks the space-separated URLs against Google Safe Browsing database
      carton exec script/lstu safebrowsingcheck -s|--seconds <xxx>       Checks URLs created the last xxx seconds against Google Safe Browsing database
      carton exec script/lstu safebrowsingcheck -t|--test <url> <url>    Checks URLs against Google Safe Browsing database

  Options (available with all commands except --test):
      -r|--remove  Remove bad URLs that have been found
      -a|--all     Remove all URLs created by the same IP addresses that created bad URLs (only in combination with the `-r|--remove` option)
      -b|--ban     Ban IP addresses that created bad URLs

=cut

1;


================================================
FILE: lib/Lstu/Command/theme.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Command::theme;
use Mojo::Base 'Mojolicious::Commands';
use FindBin qw($Bin);
use File::Spec qw(catfile cat dir);
use File::Path qw(make_path);

has description => 'Create new theme skeleton.';
has usage => sub { shift->extract_usage };
has message    => sub { shift->extract_usage . "\nCreate new theme skeleton:\n" };
has namespaces => sub { ['Lstu::Command::theme'] };

sub run {
    my $c    = shift;
    my $name = shift;

    unless (defined $name) {
        say $c->extract_usage;
        exit 1;
    }

    my $home = File::Spec->catdir($Bin, '..', 'themes', $name);

    unless (-d $home) {

        # Create skeleton
        mkdir $home;
        mkdir File::Spec->catdir($home, 'public');
        make_path(File::Spec->catdir($home, 'templates', 'layouts'));
        make_path(File::Spec->catdir($home, 'lib', 'Lstu', 'I18N'));

        my $i18n = <<EOF;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::I18N;

use base 'Locale::Maketext';
use File::Basename qw/dirname/;
use Locale::Maketext::Lexicon {
    _auto => 1,
    _decode => 1,
    _style  => 'gettext',
    '*' => [
        Gettext => dirname(__FILE__) . '/I18N/*.po',
        Gettext => $app_dir . 'themes/default/lib/Lstu/I18N/*.po',
    ]
};

use vars qw($app_dir);
BEGIN {
    use Cwd;
    my $app_dir = getcwd;
}

1;
EOF

        open my $f, '>', File::Spec->catfile($home, 'lib', 'Lstu', 'I18N.pm') or die "Unable to open $home/lib/Lstu/I18N.pm: $!";
        print $f $i18n;
        close $f;

        my $makefile = <<EOF;
POT=lib/Lstu/I18N/$home.pot
SEDOPTS=-e "s\@SOME DESCRIPTIVE TITLE\@Lstu language file\@" \\
		-e "s\@YEAR THE PACKAGE'S COPYRIGHT HOLDER\@2015 Luc Didry\@" \\
		-e "s\@CHARSET\@utf8\@" \\
		-e "s\@the PACKAGE package\@the Lstu package\@" \\
		-e '/^\\#\\. (/{N;/\\n\\#\\. (/{N;/\\n.*\\.\\.\\/default\\//{s/\\#\\..*\\n.*\\#\\./\\#. (/g}}}' \\
		-e '/^\\#\\. (/{N;/\\n.*\\.\\.\\/default\\//{s/\\n/ /}}'
SEDOPTS2=-e '/^\\#.*\\.\\.\\/default\\//,+3d'
XGETTEXT=carton exec ../../local/bin/xgettext.pl
CARTON=carton exec

locales:
		$(XGETTEXT) -D templates -D ../default/templates -o $(POT) 2>/dev/null
		sed $(SEDOPTS) -i $(POT)
		sed $(SEDOPTS2) -i $(POT)
EOF

        open $f, '>', File::Spec->catfile($home, 'Makefile') or die "Unable to open $home/Makefile: $!";
        print $f $makefile;
        close $f;
    } else {
        say "$name theme already exists. Aborting.";
        exit 1;
    }
}

=encoding utf8

=head1 NAME

Lstu::Command::theme - Create new theme skeleton.

=head1 SYNOPSIS

  Usage: script/lstu theme THEME_NAME

  Your new theme will be available in the themes directory.

=cut

1;


================================================
FILE: lib/Lstu/Command/url.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Command::url;
use Mojo::Base 'Mojolicious::Command';
use Mojo::Util qw(getopt);
use Mojo::Collection 'c';
use Lstu::DB::URL;
use FindBin qw($Bin);
use File::Spec qw(catfile);

has description => 'Manage stored URL';
has usage => sub { shift->extract_usage };

sub run {
    my $c = shift;
    my @args = @_;

    getopt \@args,
      'info=s{1,}'         => \my @info,
      'r|remove=s{1,}'     => \my @remove,
      's|search=s'         => \my $search,
      'ip=s{1,}'           => \my @ips,
      'y|yes'              => \my $yes,
      'e|even-if-disabled' => \my $even_disabled;

    if (scalar @info) {
        c(@info)->each(
            sub {
                my ($e, $num) = @_;
                my $u = get_short($c, $e, $even_disabled);
                print_infos($u->to_hash) if $u;
            }
        );
    }
    if (scalar @remove) {
        my @r_ips;
        c(@remove)->each(
            sub {
                my ($e, $num) = @_;
                my $u = get_short($c, $e, 1);
                if ($u) {
                    push @r_ips, $u->created_by if $u->created_by;
                    print_infos($u->to_hash);
                    if ($u->disabled) {
                        say sprintf('%s URL is already disabled', $e);
                    } else {
                        my $confirm = ($yes) ? 'yes' : undef;
                        unless (defined $confirm) {
                            printf('Are you sure you want to remove this URL (%s)? [N/y] ', $e);
                            $confirm = <STDIN>;
                            chomp $confirm;
                        }
                        if ($confirm =~ m/^y(es)?$/i) {
                            if ($u->remove) {
                                say sprintf('Success: %s URL has been removed', $e);
                            } else {
                                say sprintf('Failure: %s URL has not been removed', $e);
                            }
                        } else {
                            say 'Answer was not "y" or "yes". Aborting deletion.';
                        }
                    }
                }
            }
        );
        say sprintf("If you want to ban the uploaders' IPs, please do:\n  carton exec script/lstu ban --ban %s", join(' ', @r_ips)) if @r_ips;
    }
    if ($search) {
        my $u = Lstu::DB::URL->new(app => $c->app)->search_url($search);
        my @shorts;
        my @s_ips;
        $u->each(sub {
            my ($e, $num) = @_;
            push @shorts, $e->{short};
            push @s_ips, $e->{created_by} if $e->{created_by};
            print_infos($e);
        });
        say sprintf('%d matching URLs', $u->size);
        say sprintf("If you want to delete those URLs, please do:\n  carton exec script/lstu url --yes --remove %s", join(' ', @shorts)) if @shorts;
        say sprintf("If you want to ban those IPs, please do:\n  carton exec script/lstu ban --ban %s", join(' ', @s_ips)) if @s_ips;
    }
    if (scalar(@ips)) {
        my @recap;
        c(@ips)->each(sub {
            my ($ip, $num) = @_;
            my $u = Lstu::DB::URL->new(app => $c->app)->search_creator($ip);
            my @shorts;
            $u->each(sub {
                my ($e, $num) = @_;
                push @shorts, $e->{short};
                print_infos($e);
            });
            say sprintf('[%s] %d matching URLs', $ip, $u->size);
            if (@shorts) {
                say sprintf("[%s] If you want to delete those URLs, please do:\n  carton exec script/lstu url --yes --remove %s", $ip, join(' ', @shorts));
                push @recap, @shorts;
            }
        });
        say sprintf("If you want to delete all those URLs, please do:\n  carton exec script/lstu url --yes --remove %s", join(' ', @recap)) if @recap;
        say sprintf("If you want to ban those IPs, please do:\n  carton exec script/lstu ban --ban %s", join(' ', @ips)) if @ips;
    }
}

sub get_short {
    my $c                = shift;
    my $short            = shift;
    my $even_if_disabled = shift;

    my $u = Lstu::DB::URL->new(app => $c->app, short => $short);
    if ($u->url) {
        return $u if !$u->disabled;
        return $u if $even_if_disabled;
    }
    say sprintf('Sorry, unable to find an URL with short = %s', $short);
    return undef;
}

sub print_infos {
    my $u = shift;

    if ($u) {
        my $msg = <<EOF;
%s
    url        : %s
    disabled   : %d
    counter    : %d
    created at : %s
    timestamp  : %d
EOF
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($u->{timestamp});
        my $timestamp = sprintf('%d-%d-%d %d:%d:%d GMT', $year + 1900, ++$mon, $mday, $hour, $min, $sec);
        if ($u->{created_by}) {
            $msg .= '    created_by : %s';
            say sprintf($msg, $u->{short}, $u->{url}, $u->{disabled}, $u->{counter}, $timestamp, $u->{timestamp}, $u->{created_by});
        } else {
            say sprintf($msg, $u->{short}, $u->{url}, $u->{disabled}, $u->{counter}, $timestamp, $u->{timestamp});
        }
    }
}

=encoding utf8

=head1 NAME

Lstu::Command::url - Manage URL in Lstu's database

=head1 SYNOPSIS

  Usage:
      carton exec script/lstu url --info <short> <short>           Print infos about the space-separated URLs
      carton exec script/lstu url --remove <short> <short> [--yes] Remove the space-separated URLs (ask for confirmation unless --yes is given)
                                                                   Will print infos about URL before confirmation
      carton exec script/lstu url --search <url>                   Search URLs by its true URL (LIKE match)
      carton exec script/lstu url --ip <ip address> <ip address>   Search URLs by the IP address of its creator (exact match)

=cut

1;


================================================
FILE: lib/Lstu/Controller/Admin.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Controller::Admin;
use Mojo::Base 'Mojolicious::Controller';
use Digest::SHA qw(sha256_hex);
use Lstu::DB::URL;
use Lstu::DB::Ban;
use Lstu::DB::Session;

sub login {
    my $c    = shift;
    my $pwd  = $c->param('adminpwd');
    my $act  = $c->param('action');

    $c->cleaning;

    my $ip = $c->ip;

    my $banned = Lstu::DB::Ban->new(
        app    => $c,
        ip     => $ip
    )->is_banned($c->config('ban_min_strike'));
    if (defined $banned) {
        my $penalty = 3600;
        if ($banned->strike >= 2 * $c->config('ban_min_strike')) {
            $penalty = 3600 * 24 * 30; # 30 days of banishing
        }
        $banned->increment_ban_delay($penalty);

        $c->flash('msg'    => $c->l('Too many bad passwords. You\'re banned.'));
        $c->flash('banned' => 1);
        $c->redirect_to('stats');
    } else {
        if (
            (defined($c->config('adminpwd')) && defined($pwd) && $pwd eq $c->config('adminpwd')) ||
            (defined($c->config('hashed_adminpwd')) && defined($pwd) && sha256_hex($pwd) eq $c->config('hashed_adminpwd'))
           ) {
            my $token = $c->shortener(32);

            Lstu::DB::Session->new(
                app    => $c,
                token  => $token,
                until  => time + 3600
            )->write;

            $c->session('token' => $token);
            $c->respond_to(
                json => sub {
                    my $c = shift;
                    $c->render(
                        json => {
                            success => Mojo::JSON->true,
                            msg     => $c->l('You have been successfully logged in.')
                        }
                    );
                },
                any => sub {
                    my $c = shift;
                    $c->redirect_to('stats');
                }
            );
        } elsif (defined($act) && $act eq 'logout') {
            Lstu::DB::Session->new(
                app    => $c,
                token  => $c->session('token')
            )->remove;
            delete $c->session->{token};
            $c->respond_to(
                json => sub {
                    my $c = shift;
                    $c->render(
                        json => {
                            success => Mojo::JSON->true,
                            msg     => $c->l('You have been successfully logged out.')
                        }
                    );
                },
                any => sub {
                    shift->redirect_to('stats');
                }
            );
        } else {
            Lstu::DB::Ban->new(
                app    => $c,
                ip     => $ip
            )->increment_ban_delay(3600);

            my $msg = $c->l('Bad password');
            $c->respond_to(
                json => sub {
                    my $c = shift;
                    $c->render(
                        json => {
                            success => Mojo::JSON->false,
                            msg     => $msg
                        }
                    );
                },
                any => sub {
                    my $c = shift;
                    $c->flash('msg' => $msg);
                    $c->redirect_to('stats');
                }
            );
        }
    }
}

sub delete {
    my $c     = shift;
    my $short = $c->param('short');

    my $db_session = Lstu::DB::Session->new(
        app    => $c,
        token  => $c->session('token')
    );
    if (defined($c->session('token')) && $db_session->is_valid) {
        my $db_url = Lstu::DB::URL->new(
            app    => $c,
            short  => $short
        );
        if ($db_url->url) {
            my $deleted = $db_url->remove;
            $c->respond_to(
                json => { json => { success => Mojo::JSON->true, deleted => $deleted } },
                any  => sub {
                    my $c = shift;
                    $c->redirect_to('stats');
                }
            );
        } else {
            my $msg = $c->l('The shortened URL %1 doesn\'t exist.', $c->url_for('/')->to_abs.$short);
            $c->respond_to(
                json => { json => { success => Mojo::JSON->false, msg => $msg } },
                any  => sub {
                    my $c = shift;
                    $c->flash('msg' => $msg);
                    $c->redirect_to('stats');
                }
            );
        }
    } else {
        $c->flash('msg' => $c->l('You\'re not authenticated as the admin'));
        $c->redirect_to('stats');
    }
}

1;


================================================
FILE: lib/Lstu/Controller/Authent.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Controller::Authent;
use Mojo::Base 'Mojolicious::Controller';

sub index {
    my $c = shift;
    if ($c->is_user_authenticated) {
        $c->redirect_to('index');
    } else {
        $c->render(template => 'login');
    }
}

sub login {
    my $c     = shift;
    my $login = $c->param('login');
    my $pwd   = $c->param('password');

    if($c->authenticate($login, $pwd)) {
        $c->respond_to(
            json => sub {
                my $c = shift;
                $c->render(
                    json => {
                        success => Mojo::JSON->true,
                        msg     => $c->l('You have been successfully logged in.')
                    }
                );
            },
            any => sub {
                $c->redirect_to('index');
            }
        );
    } else {
        my $msg = $c->l('Please, check your credentials: unable to authenticate.');
        $c->respond_to(
            json => sub {
                my $c = shift;
                $c->render(
                    json => {
                        success => Mojo::JSON->false,
                        msg     => $msg
                    }
                );
            },
            any => sub {
                $c->stash(msg => $msg);
                $c->render(template => 'login')
            }
        );
    }
}

sub log_out {
    my $c = shift;
    if ($c->is_user_authenticated) {
        $c->logout;
    }
    $c->respond_to(
        json => sub {
            my $c = shift;
            $c->render(
                json => {
                    success => Mojo::JSON->true,
                    msg     => $c->l('You have been successfully logged out.')
                }
            );
        },
        any => sub {
            $c->render(template => 'logout');
        }
    );
}

1;


================================================
FILE: lib/Lstu/Controller/Stats.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Controller::Stats;
use Mojo::Base 'Mojolicious::Controller';
use Lstu::DB::URL;
use Lstu::DB::Session;
use Mojo::JSON qw(to_json decode_json);
use Mojo::Util qw(b64_encode);
use Image::PNG::QRCode 'qrpng';

sub export_cookie {
    my $c = shift;

    my $u = (defined($c->cookie('url'))) ? decode_json $c->cookie('url') : [];

    $c->res->headers->add('Content-Disposition' => 'attachment;filename=lstu_export.json');
    return $c->render(json => $u);
}

sub import_cookie {
    my $c    = shift;
    my $file = $c->param('file');

    my $json = decode_json($file->slurp);

    if (ref($json) eq 'ARRAY') {
        # Get URLs from cookie
        my $u = (defined($c->cookie('url'))) ? decode_json $c->cookie('url') : [];
        # Add the new URL
        push @{$u}, @{$json};
        # Make the array contain only unique URLs
        my %k = map { $_, 1 } @{$u};
        @{$u} = keys %k;
        # And set the cookie
        my $cookie = to_json($u);
        $c->cookie(
            'url' => $cookie,
            {
                path => $c->config('prefix'),
                expires => time + 142560000
            }
        ); # expires in 10 years

        $c->flash(success_msg => $c->l('File imported'));
    } else {
        $c->flash(msg => $c->l('Sorry, unable to parse the provided file'));
    }
    return $c->redirect_to('stats');
}

sub fullstats {
    my $c = shift;

    my $url = Lstu::DB::URL->new(app => $c);
    return $c->render(
        json => {
            empty     => $url->count_empty,
            urls      => $url->total,
            timestamp => time,
        }
    );
}

sub stats {
    my $c     = shift;
    my $order = $c->param('order') // 'counter';
    my $dir   = $c->param('dir')   // '-desc';

    my %orders = (
        'short'      => 1,
        'url'        => 1,
        'counter'    => 1,
        'created_by' => 1,
    );
    my %dirs = (-desc => 1, -asc => 1);

    $order = 'counter' unless $orders{$order};
    $dir   = '-desc'   unless $dirs{$dir};


    if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
        my $db_session = Lstu::DB::Session->new(
            app    => $c,
            token  => $c->session('token')
        );
        if (defined($c->session('token')) && $db_session->is_valid) {
            my $total = Lstu::DB::URL->new(app => $c)->total;
            my $page  = $c->param('page') || 0;
               $page  = 0 if ($page < 0);
               $page  = $page - 1 if ($page * $c->config('page_offset') > $total);

            my ($first, $last) = (!$page, ($page * $c->config('page_offset') <= $total && $total < ($page + 1) * $c->config('page_offset')));

            my @urls  = Lstu::DB::URL->new(
                app    => $c,
            )->paginate($page, $c->config('page_offset'), $order, $dir);

            $c->respond_to(
                json => sub {
                    my $c = shift;
                    $c->render(
                        json => {
                            prefix   => $c->prefix,
                            urls     => \@urls,
                            first    => $first,
                            last     => $last,
                            page     => $page,
                            admin    => 1,
                            total    => $total
                        }
                    );
                },
                any => sub {
                    my $c = shift;
                    $c->render(
                        template => 'stats',
                        prefix   => $c->prefix,
                        urls     => \@urls,
                        first    => $first,
                        last     => $last,
                        page     => $page,
                        admin    => 1,
                        total    => $total
                    )
                }
            );
        } else {
            my $u = (defined($c->cookie('url'))) ? decode_json $c->cookie('url') : [];

            my @urls  = Lstu::DB::URL->new(
                app    => $c
            )->get_a_lot($u);

            my $prefix = $c->prefix;

            $c->respond_to(
                json => sub {
                    my @struct;
                    for my $url (@urls) {
                        push @struct, {
                            short      => $prefix.$url->{short},
                            url        => $url->{url},
                            counter    => $url->{counter},
                            created_at => $url->{timestamp},
                            qrcode     => b64_encode(qrpng(text => $prefix.$url->{short}))
                        };
                    }
                    $c->render( json => \@struct );
                },
                any  => sub {
                    my @struct;
                    for my $url (@urls) {
                        push @struct, {
                            short     => $url->{short},
                            url       => $url->{url},
                            counter   => $url->{counter},
                            timestamp => $url->{timestamp},
                            qrcode    => b64_encode(qrpng(text => $prefix.$url->{short}))
                        };
                    }
                    $c->render(
                        template => 'stats',
                        prefix   => $prefix,
                        urls     => \@struct
                    )
                }
            )
        }
    } else {
        $c->redirect_to('login');
    }
}


sub stat_for_one_short {
    my $c = shift;
    my $short = $c->param('short');

    my $url  = Lstu::DB::URL->new(
        app    => $c,
        short  => $short
    );

    if ($url->{url}) {
        my $prefix = $c->prefix;

        $c->render(
            json => {
                success    => Mojo::JSON->true,
                short      => $prefix.$url->{short},
                url        => $url->{url},
                counter    => $url->{counter},
                created_at => $url->{timestamp},
                timestamp  => time
            }
        );
    } else {
        $c->render(
            json => {
                success => Mojo::JSON->false,
                msg     => $c->l('The shortened URL %1 doesn\'t exist.', $c->url_for('/')->to_abs.$short)
            }
        );
    }
}

1;


================================================
FILE: lib/Lstu/Controller/URL.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Controller::URL;
use Mojo::Base 'Mojolicious::Controller';
use Lstu::DB::URL;
use Lstu::DB::Ban;
use Data::Validate::URI qw(is_http_uri is_https_uri);
use Mojo::JSON qw(to_json decode_json);
use Mojo::URL;
use Mojo::Util qw(b64_encode slugify);
use Image::PNG::QRCode 'qrpng';

sub add {
    my $c = shift;

    $c->cleaning;

    # Is the user allowed to create a short URL?
    if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
        my $ip = $c->ip;

        # Check banning
        my $banned = Lstu::DB::Ban->new(
            app    => $c,
            ip     => $ip
        )->is_banned($c->config('ban_min_strike'));

        my $disabled_api = 0;
        if ($c->config('disable_api')) {
            $disabled_api = 1 if $c->validation->csrf_protect->has_error('csrf_token');
            $disabled_api = 1 if (!defined($c->req->headers->referrer) || Mojo::URL->new($c->req->headers->referrer)->host ne Mojo::URL->new('https://'.$c->req->headers->host)->host)
        }

        if (defined $banned) {
            # Increase ban delay if necessary
            my $penalty = 3600;
            if ($banned->strike >= 2 * $c->config('ban_min_strike')) {
                $penalty = 3600 * 24 * 30; # 30 days of banishing
            }
            $banned->increment_ban_delay($penalty);

            my $msg = $c->l('You asked to shorten too many URLs too quickly. You\'re banned for %1 hour(s).', $penalty/3600);
            $c->respond_to(
                json => { json => { success => Mojo::JSON->false, msg => $msg } },
                any  => sub {
                    shift->render(
                        template => 'index',
                        msg      => $msg,
                        banned   => 1
                    );
                }
            );
        } elsif ($disabled_api) {
            my $msg = $c->l('Sorry, the API is disabled.');
            $c->app->log->info('Blocked API call for '.$ip);
            $c->respond_to(
                json => { json => { success => Mojo::JSON->false, msg => $msg } },
                any  => sub {
                    shift->render(
                        template => 'index',
                        msg      => $msg,
                    );
                }
            );
        } else {
            my $lsturl     = $c->param('lsturl');
            $lsturl        =~ s/^\s+|\s+$//g;
            my $url        = Mojo::URL->new($lsturl);
            my $custom_url = $c->param('lsturl-custom');
            my $format     = $c->param('format');

            $custom_url = undef if (defined($custom_url) && $custom_url eq '');

            my ($msg, $short);
            if (defined($custom_url) &&
                       ($custom_url =~ m#^(a|d|cookie|stats|fullstats|login|logout|api)$# || $custom_url =~ m/\.json$/)
                ) {
                $msg = $c->l('The shortened text can\'t be "a", "api", "d", "cookie", "stats", "fullstats", "login" or "logout" or end with ".json". Your URL to shorten: %1', $url);
            } elsif (is_http_uri($url->to_string) || is_https_uri($url->to_string) || (defined($url->host) && $url->host =~ m/\.onion$/)) {
                my $res = ($url->host =~ m/\.onion$/) ? {} : $c->is_spam($url, 0);

                # Check if spam
                if ($res->{is_spam}) {
                    $msg = $res->{msg};
                } else {
                    # Not spam, let's go

                    Lstu::DB::Ban->new(
                        app    => $c,
                        ip     => $ip
                    )->increment_ban_delay(1);

                    my $db_url = Lstu::DB::URL->new(
                        app    => $c,
                        url    => $url
                    );

                    if ($db_url->short && !defined($custom_url)) {
                        # Already got this URL
                        $short = $db_url->short;
                    } else {
                        if (defined($custom_url)) {
                            $custom_url             = slugify $custom_url;
                            my $suffix              = 2;
                            my $original_custom_url = $custom_url;
                            while (Lstu::DB::URL->new(app => $c)->exist($custom_url) > 0) {
                                $custom_url = $original_custom_url.'-'.$suffix;
                                $suffix++;
                            }
                            Lstu::DB::URL->new(
                                app        => $c,
                                short      => $custom_url,
                                url        => $url,
                                timestamp  => time(),
                                created_by => ($c->config('log_creator_ip')) ? $ip : undef
                            )->write;

                            $short = $custom_url;
                        } else {
                            $db_url = Lstu::DB::URL->new(app => $c)->choose_empty;
                            if (defined $db_url) {
                                $db_url->url($url)->timestamp(time);

                                $db_url->created_by($ip) if $c->config('log_creator_ip');

                                $db_url->write;

                                $short = $db_url->short;
                            } else {
                                # Houston, we have a problem
                                $msg = $c->l('No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: [_2]', $c->config('contact'), $url);
                            }
                        }
                    }
                }
            } else {
                $msg = $c->l('%1 is not a valid URL.', $url);
            }
            if ($msg) {
                $c->respond_to(
                    json => { json => { success => Mojo::JSON->false, msg => $msg } },
                    any  => sub {
                        shift->render(
                            template => 'index',
                            msg      => $msg
                        );
                    }
                );
            } else {
                # Get URLs from cookie
                my $u = (defined($c->cookie('url'))) ? decode_json $c->cookie('url') : [];

                # Add the new URL
                push @{$u}, $short;

                # Make the array contain only unique URLs
                my %k = map { $_, 1 } @{$u};
                @{$u} = keys %k;

                # And set the cookie
                my $cookie = to_json($u);
                $c->cookie(
                    'url' => $cookie,
                    {
                        path => $c->config('prefix'),
                        expires => time + 142560000
                    }
                ); # expires in 10 years

                my $prefix = $c->prefix;

                my $qrcode = b64_encode(qrpng(text => $prefix.$short, scale => $c->config('qrcode_size')));

                $c->respond_to(
                    json => { json => { success => Mojo::JSON->true, url => $url, short => $prefix.$short, qrcode => $qrcode } },
                    any  => sub {
                        shift->render(
                            template => 'index',
                            url      => $url,
                            short    => $prefix.$short,
                            qrcode   => $qrcode
                        );
                    }
                );
            }
        }
    } else {
        # Not authorized
        $c->redirect_to('login');
    }
}

sub get {
    my $c = shift;
    my $short = $c->param('short');

    if (defined($c->stash('format')) && $short eq 'robots' && $c->stash('format') eq 'txt') {
        if ($c->app->static->file('robots.txt')) {
            $c->res->headers->content_type('text/plain');
            return $c->reply->static('robots.txt');
        } else {
            return $c->reply->not_found;
        }
    }

    my $url;
    my $disabled_url = 0;
    if (scalar(@{$c->config('memcached_servers')})) {
        $url = $c->chi('lstu_urls_cache')->compute($short, undef, sub {
            my $db_url = Lstu::DB::URL->new(app => $c, short => $short);
            if ($db_url->disabled) {
                $disabled_url++;
                return undef
            } else {
                return $db_url->url;
            }
        });
    } else {
        my $db_url = Lstu::DB::URL->new(app => $c, short => $short);
        if ($db_url->disabled) {
            $disabled_url++;
        } else {
            $url = $db_url->url;
        }
    }

    if ($url) {
        $c->respond_to(
            json => { json => { success => Mojo::JSON->true, url => $url } },
            any  => sub {
                my $c = shift;
                $c->res->code(301);
                $c->redirect_to($url);
            }
        );
        # Update counter
        $c->on(finish => sub {
            if ($c->config('minion')->{enabled} && $c->config('minion')->{db_path}) {
                $c->app->minion->enqueue(increase_counter => [$short, $c->{url}]);
            } else {
                Lstu::DB::URL->new(app => $c, short => $short)->increment_counter;

                my $piwik = $c->config('piwik');
                if (defined($piwik) && $piwik->{idsite} && $piwik->{url}) {
                    $c->piwik_api(
                        'Track' => {
                            idSite     => $piwik->{idsite},
                            action_url => $c->{url},
                            url        => $piwik->{url}
                        }
                    );
                }

            }
        });
    } else {
        my $msg;
        if ($disabled_url) {
            $msg = $c->l('The shortened URL %1 no longer exists.', $c->url_for('/')->to_abs.$short);
        } else {
            $msg = $c->l('The shortened URL %1 doesn\'t exist.', $c->url_for('/')->to_abs.$short);
        }
        $c->res->code(404);
        $c->respond_to(
            json => { json => { success => Mojo::JSON->false, msg => $msg } },
            any  => sub {
                my $c = shift;

                $c->render(
                    template => 'index',
                    msg      => $msg
                );
            }
        );
    }
}

1;


================================================
FILE: lib/Lstu/DB/Ban/MySQL.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::DB::Ban::MySQL;
use Mojo::Base 'Lstu::DB::Ban';

sub new {
    my $c = shift;

    $c = $c->SUPER::new(@_);

    $c = $c->_slurp if ($c->ip);

    return $c;
}

1;


================================================
FILE: lib/Lstu/DB/Ban/Pg.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::DB::Ban::Pg;
use Mojo::Base 'Lstu::DB::Ban';

sub new {
    my $c = shift;

    $c = $c->SUPER::new(@_);

    $c = $c->_slurp if ($c->ip);

    return $c;
}

sub increment_ban_delay {
    my $c       = shift;
    my $penalty = shift;

    my $until = time + $penalty;

    my $h = {
        strike => 1
    };
    if ($c->record) {
        $h = $c->app->dbi->db->query('UPDATE ban SET until = ?, strike = strike + 1 WHERE ip = ? RETURNING strike', $until, $c->ip)->hashes->first;
    } else {
        $c->app->dbi->db->query('INSERT INTO ban (ip, until, strike) VALUES (?, ?, 1)', $c->ip, $until);
        $c->record(1);
    }

    $c->strike($h->{strike});
    $c->until($until);

    return $c;
}

sub ban_ten_years {
    my $c = shift;

    my $until = time + 315360000;

    my $h = {
        strike => time
    };
    if ($c->record) {
        $h = $c->app->dbi->db->query('UPDATE ban SET until = ?, strike = ? WHERE ip = ? RETURNING strike', $until, time, $c->ip)->hashes->first;
    } else {
        $c->app->dbi->db->query('INSERT INTO ban (ip, until, strike) VALUES (?, ?, ?)', $c->ip, $until, time);
        $c->record(1);
    }

    $c->strike($h->{strike});
    $c->until($until);

    return $c;
}

1;


================================================
FILE: lib/Lstu/DB/Ban/SQLite.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::DB::Ban::SQLite;
use Mojo::Base 'Lstu::DB::Ban';

sub new {
    my $c = shift;

    $c = $c->SUPER::new(@_);

    $c = $c->_slurp if ($c->ip);

    return $c;
}

1;


================================================
FILE: lib/Lstu/DB/Ban.pm
================================================
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::DB::Ban;
use Mojo::Base -base;
use Mojo::Collection 'c';

has 'ip';
has 'until';
has 'strike' => 0;
has 'record' => 0;
has 'app';

=head1 NAME

Lstu::DB::Ban - Abstraction layer for Lstu ban system

=head1 Contributing

When creating a new database accessor, make sure that it provides the following subroutines.
After that, modify this file and modify the C<new> subroutine to allow to use your accessor.

Have a look at Lstu::DB::Ban::SQLite's code: it's simple and may be more understandable that this doc.

=head1 Attributes

=over 1

=item B<ip>     : string, an IP address

=item B<until>  : unix timestamp

=item B<strike> : integer

=item B<app>    : a mojolicious object

=back

=head1 Sub routines

=head2 new

=over 1

=item B<Usage>     : C<$c = Lstu::DB::Ban-E<gt>new(app =E<gt> $self);>

=item B<Arguments> : any of the attribute above

=item B<Purpose>   : construct a new Lstu::DB::Ban object. If the C<ip> attribute is provided, it have to load the informations from the database

=item B<Returns>   : the Lstu::DB::Ban object

=item B<Info>      : the app argument is used by Lstu::DB::Ban to choose which db accessor will be used, you don't need to use it in new(), but you can use it to access helpers or configuration settings in the other subroutines

=back

=cut

sub new {
    my $c = shift;

    $c = $c->SUPER::new(@_);

    if (ref($c) eq 'Lstu::DB::Ban') {
        my $dbtype = $c->app->config('dbtype');
        if ($dbtype eq 'sqlite') {
            require Lstu::DB::Ban::SQLite;
            $c = Lstu::DB::Ban::SQLite->new(@_);
        } elsif ($dbtype eq 'postgresql') {
            require Lstu::DB::Ban::Pg;
            $c = Lstu::DB::Ban::Pg->new(@_);
        } elsif ($dbtype eq 'mysql') {
            require Lstu::DB::Ban::MySQL;
            $c = Lstu::DB::Ban::MySQL->new(@_);
        }
    }

    return $c;
}

sub to_hash {
    my $c = shift;

    return {
        ip     => $c->ip,
        until  => $c->until,
        strike => $c->strike
    };
}

=head2 is_whitelisted

=over 1

=item B<Usage>     : C<$c-E<gt>is_whitelisted>

=item B<Arguments> : none

=item B<Purpose>   : tells you if the current object is in the configured whitelisted IPs

=item B<Returns>   : boolean

=back

=cut

sub is_whitelisted {
    my $c = shift;

    my $ip = $c->ip;
    return c(@{$c->app->config('ban_whitelist')})->grep(sub { $_ eq $ip })->size;
}

=head2 is_blacklisted

=over 1

=item B<Usage>     : C<$c-E<gt>is_blacklisted>

=item B<Arguments> : none

=item B<Purpose>   : tells you if the current object is in the configured blacklisted IPs

=item B<Returns>   : boolean

=back

=cut

sub is_blacklisted {
    my $c = shift;

    my $ip = $c->ip;
    return c(@{$c->app->config('ban_blacklist')})->grep(sub { $_ eq $ip })->size;
}

=head2 is_banned

=over 1

=item B<Usage>     : C<$c-E<gt>is_banned(3)>

=item B<Arguments> : an integer. Will be config('ban_min_strike'), which is the number of strike before being banned (default: 3)

=item B<Purpose>   : check the db record with C<ip> equal to the object's ip attribute if C<until> is superior to current time and if C<strike> is superior or equal to the argument.

eg: C<WHERE ip = ? AND until E<gt> ? AND strike E<gt>= ?', $c->ip, time, $argument>

=item B<Returns>   : the Lstu::DB::Ban object if the ip is banned, undef otherwise

=item B<Info>      : if the IP is whitelisted (see C<is_whitelisted> above), it must return undef

=back

=cut

sub is_banned {
    my $c              = shift;
    my $ban_min_strike = shift;

    return undef if $c->is_whitelisted;

    if ($c->is_blacklisted) {
        $c->until(time + 3600);
        $c->strike(1 + $c->app->config('ban_min_strike'));
        return $c;
    }

    my $h = $c->app->dbi->db->query('SELECT * FROM ban WHERE ip = ? AND until > ? AND strike >= ?', $c->ip, time, $ban_min_strike)->hashes;

    if ($h->size) {
        $c->until($h->first->{until});
        $c->strike($
Download .txt
gitextract_qiht013d/

├── .dockerignore
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── .provision/
│   ├── README.md
│   ├── ansible-role-lstu/
│   │   ├── README.md
│   │   ├── handlers/
│   │   │   └── main.yml
│   │   ├── tasks/
│   │   │   ├── apprun.yaml
│   │   │   ├── dependencies.yaml
│   │   │   ├── gitclone.yaml
│   │   │   └── main.yml
│   │   ├── templates/
│   │   │   ├── app.conf
│   │   │   └── lstu.conf.j2
│   │   └── vars/
│   │       └── main.yml
│   └── terraform-aws-lstu/
│       ├── README.md
│       ├── lstu_startup.sh
│       ├── main.tf
│       ├── output.tf
│       ├── provider.tf
│       └── vars.tf
├── .weblate
├── AUTHORS.md
├── CHANGELOG
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cpanfile
├── cpanfile.snapshot
├── docker/
│   └── entrypoint.sh
├── docker-compose.dev.yml
├── docker-compose.yml
├── docker-stack.yml
├── hooks/
│   └── build
├── lib/
│   ├── Lstu/
│   │   ├── Command/
│   │   │   ├── ban.pm
│   │   │   ├── safebrowsingcheck.pm
│   │   │   ├── theme.pm
│   │   │   └── url.pm
│   │   ├── Controller/
│   │   │   ├── Admin.pm
│   │   │   ├── Authent.pm
│   │   │   ├── Stats.pm
│   │   │   └── URL.pm
│   │   ├── DB/
│   │   │   ├── Ban/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   ├── Ban.pm
│   │   │   ├── Session/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   ├── Session.pm
│   │   │   ├── URL/
│   │   │   │   ├── MySQL.pm
│   │   │   │   ├── Pg.pm
│   │   │   │   └── SQLite.pm
│   │   │   └── URL.pm
│   │   ├── DefaultConfig.pm
│   │   └── Plugin/
│   │       ├── Headers.pm
│   │       └── Helpers.pm
│   ├── Lstu.pm
│   └── Mounter.pm
├── lstu.conf.template
├── script/
│   ├── application
│   └── lstu
├── t/
│   ├── lstu.passwd
│   ├── mysql1.conf
│   ├── mysql2.conf
│   ├── mysql3.conf
│   ├── postgresql1.conf
│   ├── postgresql2.conf
│   ├── postgresql3.conf
│   ├── sqlite1.conf
│   ├── sqlite2.conf
│   ├── sqlite3.conf
│   └── test.t
├── themes/
│   ├── default/
│   │   ├── lib/
│   │   │   └── Lstu/
│   │   │       ├── I18N/
│   │   │       │   ├── br.po
│   │   │       │   ├── de.po
│   │   │       │   ├── en.po
│   │   │       │   ├── es.po
│   │   │       │   ├── fr.po
│   │   │       │   ├── fr_FR.po
│   │   │       │   ├── hr.po
│   │   │       │   ├── lstu.pot
│   │   │       │   ├── oc.po
│   │   │       │   ├── pt_BR.po
│   │   │       │   └── sv.po
│   │   │       └── I18N.pm
│   │   ├── public/
│   │   │   ├── browserconfig.xml
│   │   │   ├── css/
│   │   │   │   ├── animation.css
│   │   │   │   ├── bootstrap-lstu.min.css
│   │   │   │   ├── bootstrap.min.css
│   │   │   │   ├── fontelico-codes.css
│   │   │   │   ├── fontelico-embedded.css
│   │   │   │   ├── fontelico-ie7-codes.css
│   │   │   │   ├── fontelico-ie7.css
│   │   │   │   ├── fontelico.css
│   │   │   │   ├── fontelico.min.css
│   │   │   │   └── lstu.css
│   │   │   ├── font/
│   │   │   │   └── licenses/
│   │   │   │       ├── Apache License.txt
│   │   │   │       └── SIL Open Font License.txt
│   │   │   ├── fontello.json
│   │   │   └── manifest.json
│   │   └── templates/
│   │       ├── api.html.ep
│   │       ├── index.html.ep
│   │       ├── layouts/
│   │       │   └── default.html.ep
│   │       ├── login.html.ep
│   │       ├── logout.html.ep
│   │       ├── partial/
│   │       │   └── lstu.js.ep
│   │       └── stats.html.ep
│   └── milligram/
│       ├── Makefile
│       ├── lib/
│       │   └── Lstu/
│       │       ├── I18N/
│       │       │   ├── en.po
│       │       │   ├── fr.po
│       │       │   ├── milligram.pot
│       │       │   └── oc.po
│       │       └── I18N.pm
│       ├── public/
│       │   └── css/
│       │       ├── lstu.css
│       │       ├── lstu.min.css
│       │       ├── milli-lstu.min.css
│       │       ├── milligram.min.css
│       │       └── milligram.min.css.map
│       └── templates/
│           ├── index.html.ep
│           ├── layouts/
│           │   └── default.html.ep
│           └── stats.html.ep
└── utilities/
    ├── bootstrap.json
    ├── lstu-minion@.service
    ├── lstu.apache
    ├── lstu.default
    ├── lstu.init
    ├── lstu.nginx
    ├── lstu.service
    ├── lstu_upstart.conf
    ├── migrations/
    │   ├── mysql.sql
    │   ├── postgresql.sql
    │   └── sqlite.sql
    └── read_conf.pl
Download .txt
SYMBOL INDEX (13 symbols across 3 files)

FILE: utilities/migrations/mysql.sql
  type lstu (line 2) | CREATE TABLE IF NOT EXISTS lstu (
  type sessions (line 8) | CREATE TABLE IF NOT EXISTS sessions (
  type ban (line 12) | CREATE TABLE IF NOT EXISTS ban (

FILE: utilities/migrations/postgresql.sql
  type lstu (line 2) | CREATE TABLE IF NOT EXISTS lstu (
  type sessions (line 8) | CREATE TABLE IF NOT EXISTS sessions (
  type ban (line 12) | CREATE TABLE IF NOT EXISTS ban (
  type empty_short_idx (line 22) | CREATE INDEX IF NOT EXISTS empty_short_idx ON lstu (short) WHERE url IS ...

FILE: utilities/migrations/sqlite.sql
  type lstu (line 2) | CREATE TABLE IF NOT EXISTS lstu (
  type sessions (line 8) | CREATE TABLE IF NOT EXISTS sessions (
  type ban (line 12) | CREATE TABLE IF NOT EXISTS ban (
  type empty_short_idx (line 17) | CREATE INDEX IF NOT EXISTS empty_short_idx ON lstu (short) WHERE url IS ...
  type lstu_backup (line 27) | CREATE TABLE lstu_backup(
  type lstu_backup (line 41) | CREATE TABLE lstu_backup(
Condensed preview — 134 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (843K chars).
[
  {
    "path": ".dockerignore",
    "chars": 66,
    "preview": ".cpan\n.cpanm\n.git\ndocker-compose.yml\nlocal\nlog/*\nlstu.conf\nlstu.db"
  },
  {
    "path": ".gitattributes",
    "chars": 22,
    "preview": "zanata.xml merge=ours\n"
  },
  {
    "path": ".gitignore",
    "chars": 305,
    "preview": ".cpan\n.cpanm\n.*_history\nlocal/*\ncover_db/*\nsafebrowsing_db/*\n.tx/*\n*.db\n*.db-shm\n*.db-wal\n*.db-journal\nlstu.conf\n*.swp\ns"
  },
  {
    "path": ".gitlab-ci.yml",
    "chars": 4131,
    "preview": "image: hatsoftwares/lstu-test-ci:latest\nstages:\n  - tags\n  - carton\n  - carton_bdd\n  - tests\n\nvariables:\n  POSTGRES_DB: "
  },
  {
    "path": ".provision/README.md",
    "chars": 363,
    "preview": "## ansible-role-lstu\n\nAn ansible role deploy the application on host machine(Ubuntu 20.04)\n\n## terraform-aws-lstu\n\nA ter"
  },
  {
    "path": ".provision/ansible-role-lstu/README.md",
    "chars": 1471,
    "preview": "Ansible-Role-Lstu\n=========\nThis role installs the and configures lstu on Debian/Ubuntu servers with nginx web server co"
  },
  {
    "path": ".provision/ansible-role-lstu/handlers/main.yml",
    "chars": 102,
    "preview": "---\n# handlers file for ansible-role-lstu\n- name: restart nginx\n  service: name=nginx state=restarted\n"
  },
  {
    "path": ".provision/ansible-role-lstu/tasks/apprun.yaml",
    "chars": 615,
    "preview": "#apprun.yml\n---\n- name: This command will install the postgress module\n  ansible.builtin.shell:\n    cmd: carton install "
  },
  {
    "path": ".provision/ansible-role-lstu/tasks/dependencies.yaml",
    "chars": 350,
    "preview": "#dependencies.yaml\n---\n- name: Lstu | Update apt cache\n  ansible.builtin.apt: update_cache=yes \n  changed_when: no\n\n- na"
  },
  {
    "path": ".provision/ansible-role-lstu/tasks/gitclone.yaml",
    "chars": 400,
    "preview": "#gitclone\n---\n- name: Clone the repository\n  ansible.builtin.git:\n    repo: 'https://framagit.org/luc/lstu.git'\n    dest"
  },
  {
    "path": ".provision/ansible-role-lstu/tasks/main.yml",
    "chars": 115,
    "preview": "---\n# tasks file for ansible-role-lstu\n- include: dependencies.yaml\n- include: gitclone.yaml\n- include: apprun.yaml"
  },
  {
    "path": ".provision/ansible-role-lstu/templates/app.conf",
    "chars": 636,
    "preview": "upstream lstu {\n    server 127.0.0.1:8080;\n}\n\nserver {\n    listen 80; \n    listen [::]:80;\n\n    server_name {{ _server_n"
  },
  {
    "path": ".provision/ansible-role-lstu/templates/lstu.conf.j2",
    "chars": 11672,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": ".provision/ansible-role-lstu/vars/main.yml",
    "chars": 179,
    "preview": "---\n# vars file for ansible-role-lstu\n\nlstu_owner: \"www-data\"\n\nlstu_group: \"www-data\"\n\napp_dir: \"/var/www/lstu\"\n\n_contac"
  },
  {
    "path": ".provision/terraform-aws-lstu/README.md",
    "chars": 3060,
    "preview": "# Terraform-AWS-Deploy\n\n This terraform plan create the resourcess of EC2 instance\n\n## Terraform Variables\n Edit the `va"
  },
  {
    "path": ".provision/terraform-aws-lstu/lstu_startup.sh",
    "chars": 2959,
    "preview": "#!/bin/bash\n\necho \"**********************************************************************\"\necho \"                       "
  },
  {
    "path": ".provision/terraform-aws-lstu/main.tf",
    "chars": 2949,
    "preview": "locals {\n  user_data_vars = {\n    user = var.lstu_owner\n    group = var.lstu_group\n    directory = var.app_dir\n    conta"
  },
  {
    "path": ".provision/terraform-aws-lstu/output.tf",
    "chars": 166,
    "preview": "output \"public_ip\" {\n  value = \"${aws_instance.ec2_instance.public_ip}\"\n}\n\noutput \"App_running_at\" {\n  value = \"http://$"
  },
  {
    "path": ".provision/terraform-aws-lstu/provider.tf",
    "chars": 243,
    "preview": "terraform {\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"~> 3.0\"\n    }\n  }\n}\n\npro"
  },
  {
    "path": ".provision/terraform-aws-lstu/vars.tf",
    "chars": 848,
    "preview": "variable \"aws_region\" {\n    default = \"aws_region\"\n}\nvariable \"vpc_cidr\" {\n    default = \"cidr_value\"\n}\nvariable \"public"
  },
  {
    "path": ".weblate",
    "chars": 70,
    "preview": "[weblate]\nurl = https://weblate.framasoft.org/api/\ntranslation = lstu\n"
  },
  {
    "path": "AUTHORS.md",
    "chars": 491,
    "preview": "# Lstu's authors\n\n## Main developer\n\n* Luc Didry, aka Sky (<https://fiat-tux.fr>), core developer, framasky@framasphere."
  },
  {
    "path": "CHANGELOG",
    "chars": 7084,
    "preview": "Revision history for Perl application Lstu\n\n0.29-0 ????-??-??\n\n0.28-0 2023-12-17\n\t- ⬆️ Update dependencies\n\t- 💥 BREAKING"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 697,
    "preview": "# How to contribute?\n\nThe official git repository is <https://framagit.org/fiat-tux/hat-softwares/lstu>.\n\nYou can create"
  },
  {
    "path": "Dockerfile",
    "chars": 1125,
    "preview": "FROM alpine:3.19\n\nARG BUILD_DATE\nARG VCS_REF\nARG VERSION\nLABEL org.label-schema.build-date=$BUILD_DATE \\\n      org.label"
  },
  {
    "path": "LICENSE",
    "chars": 487,
    "preview": "        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE \n                    Version 2, December 2004 \n\n Copyright (C) 2004 "
  },
  {
    "path": "Makefile",
    "chars": 1924,
    "preview": "EXTRACTDIR=-D lib -D themes/default/templates\nPOT=themes/default/lib/Lstu/I18N/lstu.pot\nXGETTEXT=carton exec local/bin/x"
  },
  {
    "path": "README.md",
    "chars": 1718,
    "preview": "# Lstu\n\n## What does Lstu mean?\n\nIt means Let's Shorten That Url.\n\n## License\n\nLstu is licensed under the terms of the W"
  },
  {
    "path": "cpanfile",
    "chars": 1835,
    "preview": "requires 'inc::Module::Install::DSL';\nrequires 'Mojolicious', '>= 8.09';\nrequires 'Data::Validate::URI';\nrequires 'Net::"
  },
  {
    "path": "cpanfile.snapshot",
    "chars": 98840,
    "preview": "# carton snapshot format: version 1.0\nDISTRIBUTIONS\n  Apache-Htpasswd-1.9\n    pathname: K/KM/KMELTZ/Apache-Htpasswd-1.9."
  },
  {
    "path": "docker/entrypoint.sh",
    "chars": 1242,
    "preview": "#!/bin/sh\n\nset -eu\n\ncd ~lstu\n\nif [ \"${1:-}\" == \"dev\" ]\nthen\n    echo \"\"\n    echo \"\"\n    echo \"Container started in dev m"
  },
  {
    "path": "docker-compose.dev.yml",
    "chars": 606,
    "preview": "version: '3.3'\n\nservices:\n    app_dev:\n        build: .\n        ports:\n            - 8080:8080\n        volumes:\n        "
  },
  {
    "path": "docker-compose.yml",
    "chars": 602,
    "preview": "version: '3.3'\n\nservices:\n    app:\n        build: .\n        ports:\n            - 8080:8080\n        volumes:\n            "
  },
  {
    "path": "docker-stack.yml",
    "chars": 884,
    "preview": "version: '3.3'\n\nservices:\n    app:\n        image: aquinum/lstu\n        configs:\n            - source: lstu.conf\n        "
  },
  {
    "path": "hooks/build",
    "chars": 864,
    "preview": "#!/bin/bash\n\n# https://medium.com/microscaling-systems/labelling-automated-builds-on-docker-hub-f3d073fb8e1#.yldbwesu7\n\n"
  },
  {
    "path": "lib/Lstu/Command/ban.pm",
    "chars": 1409,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Command::ban;\nuse Mojo::Base 'Mojolicious::Command';\nuse Find"
  },
  {
    "path": "lib/Lstu/Command/safebrowsingcheck.pm",
    "chars": 5653,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Command::safebrowsingcheck;\nuse Mojo::Base 'Mojolicious::Comm"
  },
  {
    "path": "lib/Lstu/Command/theme.pm",
    "chars": 2676,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Command::theme;\nuse Mojo::Base 'Mojolicious::Commands';\nuse F"
  },
  {
    "path": "lib/Lstu/Command/url.pm",
    "chars": 5833,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Command::url;\nuse Mojo::Base 'Mojolicious::Command';\nuse Mojo"
  },
  {
    "path": "lib/Lstu/Controller/Admin.pm",
    "chars": 4616,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Controller::Admin;\nuse Mojo::Base 'Mojolicious::Controller';\n"
  },
  {
    "path": "lib/Lstu/Controller/Authent.pm",
    "chars": 1872,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Controller::Authent;\nuse Mojo::Base 'Mojolicious::Controller'"
  },
  {
    "path": "lib/Lstu/Controller/Stats.pm",
    "chars": 6439,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Controller::Stats;\nuse Mojo::Base 'Mojolicious::Controller';\n"
  },
  {
    "path": "lib/Lstu/Controller/URL.pm",
    "chars": 10430,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::Controller::URL;\nuse Mojo::Base 'Mojolicious::Controller';\nus"
  },
  {
    "path": "lib/Lstu/DB/Ban/MySQL.pm",
    "chars": 223,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Ban::MySQL;\nuse Mojo::Base 'Lstu::DB::Ban';\n\nsub new {\n  "
  },
  {
    "path": "lib/Lstu/DB/Ban/Pg.pm",
    "chars": 1274,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Ban::Pg;\nuse Mojo::Base 'Lstu::DB::Ban';\n\nsub new {\n    m"
  },
  {
    "path": "lib/Lstu/DB/Ban/SQLite.pm",
    "chars": 224,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Ban::SQLite;\nuse Mojo::Base 'Lstu::DB::Ban';\n\nsub new {\n "
  },
  {
    "path": "lib/Lstu/DB/Ban.pm",
    "chars": 7559,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Ban;\nuse Mojo::Base -base;\nuse Mojo::Collection 'c';\n\nhas"
  },
  {
    "path": "lib/Lstu/DB/Session/MySQL.pm",
    "chars": 234,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Session::MySQL;\nuse Mojo::Base 'Lstu::DB::Session';\n\nsub "
  },
  {
    "path": "lib/Lstu/DB/Session/Pg.pm",
    "chars": 476,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Session::Pg;\nuse Mojo::Base 'Lstu::DB::Session';\n\nsub new"
  },
  {
    "path": "lib/Lstu/DB/Session/SQLite.pm",
    "chars": 235,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Session::SQLite;\nuse Mojo::Base 'Lstu::DB::Session';\n\nsub"
  },
  {
    "path": "lib/Lstu/DB/Session.pm",
    "chars": 4576,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::Session;\nuse Mojo::Base -base;\n\nhas 'token';\nhas 'until';"
  },
  {
    "path": "lib/Lstu/DB/URL/MySQL.pm",
    "chars": 237,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::URL::MySQL;\nuse Mojo::Base 'Lstu::DB::URL';\n\nsub new {\n  "
  },
  {
    "path": "lib/Lstu/DB/URL/Pg.pm",
    "chars": 1099,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::URL::Pg;\nuse Mojo::Base 'Lstu::DB::URL';\n\nsub new {\n    m"
  },
  {
    "path": "lib/Lstu/DB/URL/SQLite.pm",
    "chars": 638,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::URL::SQLite;\nuse Mojo::Base 'Lstu::DB::URL';\n\nsub new {\n "
  },
  {
    "path": "lib/Lstu/DB/URL.pm",
    "chars": 11431,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DB::URL;\nuse Mojo::Base -base;\n\nhas 'short';\nhas 'url';\nhas '"
  },
  {
    "path": "lib/Lstu/DefaultConfig.pm",
    "chars": 1138,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::DefaultConfig;\nrequire Exporter;\n@ISA = qw(Exporter);\n@EXPORT"
  },
  {
    "path": "lib/Lstu/Plugin/Headers.pm",
    "chars": 1857,
    "preview": "package Lstu::Plugin::Headers;\nuse Mojo::Base 'Mojolicious::Plugin';\n\nsub register {\n    my ($self, $app) = @_;\n\n    # A"
  },
  {
    "path": "lib/Lstu/Plugin/Helpers.pm",
    "chars": 8648,
    "preview": "package Lstu::Plugin::Helpers;\nuse Mojo::Base 'Mojolicious::Plugin';\nuse Mojo::URL;\nuse Net::Abuse::Utils::Spamhaus qw(c"
  },
  {
    "path": "lib/Lstu.pm",
    "chars": 11978,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu;\nuse Mojo::Base 'Mojolicious';\nuse Mojo::JSON;\nuse Lstu::DB::U"
  },
  {
    "path": "lib/Mounter.pm",
    "chars": 1717,
    "preview": "package Mounter;\nuse Mojo::Base 'Mojolicious';\nuse Mojo::File;\nuse FindBin qw($Bin);\nuse File::Spec qw(catfile);\nuse Lst"
  },
  {
    "path": "lstu.conf.template",
    "chars": 12341,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "script/application",
    "chars": 229,
    "preview": "#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\n\nuse FindBin;\nBEGIN { unshift @INC, \"$FindBin::Bin/../lib\" }\n\n# Start com"
  },
  {
    "path": "script/lstu",
    "chars": 232,
    "preview": "#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\n\nuse FindBin;\nBEGIN { unshift @INC, \"$FindBin::Bin/../lib\" }\n\n# Start com"
  },
  {
    "path": "t/lstu.passwd",
    "chars": 42,
    "preview": "luc:$apr1$zG4UAKGa$FqSi4widrkVH/pT3qPawd.\n"
  },
  {
    "path": "t/mysql1.conf",
    "chars": 11912,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/mysql2.conf",
    "chars": 11926,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/mysql3.conf",
    "chars": 11914,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/postgresql1.conf",
    "chars": 11925,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/postgresql2.conf",
    "chars": 11912,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/postgresql3.conf",
    "chars": 11916,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/sqlite1.conf",
    "chars": 11916,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/sqlite2.conf",
    "chars": 11923,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/sqlite3.conf",
    "chars": 10534,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\n{\n    ####################\n    # Hypnotoad settings\n    ###################"
  },
  {
    "path": "t/test.t",
    "chars": 16900,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\nuse Mojo::Base -strict;\nuse Mojo::JSON qw(true false);\nuse Mojo::File;\nuse "
  },
  {
    "path": "themes/default/lib/Lstu/I18N/br.po",
    "chars": 13492,
    "preview": "# Lstu\n# Copyright (C) 2013 - 2015 Luc Didry\n# This file is distributed under the same license as the Lstu package.\n# \n#"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/de.po",
    "chars": 13394,
    "preview": "# Nico Domino <yo@iamnico.xyz>, 2018. #zanata\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-D"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/en.po",
    "chars": 15306,
    "preview": "# Luc Didry <luc@framasoft.org>, 2018. #zanata\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/es.po",
    "chars": 15869,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "themes/default/lib/Lstu/I18N/fr.po",
    "chars": 16268,
    "preview": "# Lstu\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu package.\n# \n# Transl"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/fr_FR.po",
    "chars": 16279,
    "preview": "# Lstu\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu package.\n# \n# Transl"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/hr.po",
    "chars": 16149,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "themes/default/lib/Lstu/I18N/lstu.pot",
    "chars": 12350,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "themes/default/lib/Lstu/I18N/oc.po",
    "chars": 16165,
    "preview": "# Lstu\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu package.\n# \n# Transl"
  },
  {
    "path": "themes/default/lib/Lstu/I18N/pt_BR.po",
    "chars": 12434,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "themes/default/lib/Lstu/I18N/sv.po",
    "chars": 15524,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "themes/default/lib/Lstu/I18N.pm",
    "chars": 238,
    "preview": "package Lstu::I18N;\n\nuse base 'Locale::Maketext';\nuse File::Basename qw/dirname/;\nuse Locale::Maketext::Lexicon {\n    _a"
  },
  {
    "path": "themes/default/public/browserconfig.xml",
    "chars": 435,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square70x70logo s"
  },
  {
    "path": "themes/default/public/css/animation.css",
    "chars": 1857,
    "preview": "/*\n   Animation example, for spinners\n*/\n.animate-spin {\n  -moz-animation: spin 2s infinite linear;\n  -o-animation: spin"
  },
  {
    "path": "themes/default/public/css/bootstrap-lstu.min.css",
    "chars": 47992,
    "preview": "/*!\n * Bootstrap v3.3.4 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://gi"
  },
  {
    "path": "themes/default/public/css/bootstrap.min.css",
    "chars": 47607,
    "preview": "/*!\n * Bootstrap v3.3.4 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://gi"
  },
  {
    "path": "themes/default/public/css/fontelico-codes.css",
    "chars": 106,
    "preview": "\n.icon-clipboard:before { content: '\\e800'; } /* '' */\n.icon-trash:before { content: '\\e804'; } /* '' */"
  },
  {
    "path": "themes/default/public/css/fontelico-embedded.css",
    "chars": 13758,
    "preview": "@font-face {\n  font-family: 'fontelico';\n  src: url('../font/fontelico.eot?87465342');\n  src: url('../font/fontelico.eot"
  },
  {
    "path": "themes/default/public/css/fontelico-ie7-codes.css",
    "chars": 212,
    "preview": "\n.icon-clipboard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }\n.icon-trash"
  },
  {
    "path": "themes/default/public/css/fontelico-ie7.css",
    "chars": 464,
    "preview": "[class^=\"icon-\"], [class*=\" icon-\"] {\n  font-family: 'fontelico';\n  font-style: normal;\n  font-weight: normal;\n \n  /* fi"
  },
  {
    "path": "themes/default/public/css/fontelico.css",
    "chars": 1856,
    "preview": "@font-face {\n  font-family: 'fontelico';\n  src: url('../font/fontelico.eot?21941692');\n  src: url('../font/fontelico.eot"
  },
  {
    "path": "themes/default/public/css/fontelico.min.css",
    "chars": 34405,
    "preview": "@font-face{font-family:fontelico;src:url(data:application/vnd.ms-fontobject;base64,6BYAADwWAAABAAIAAAAAAAIABQMAAAAAAAABA"
  },
  {
    "path": "themes/default/public/css/lstu.css",
    "chars": 1687,
    "preview": "body {\n    padding-top: 40px;\n    padding-bottom: 40px;\n}\n\n.container {\n    padding: 15px;\n    margin: 0 auto;\n}\n\n@font-"
  },
  {
    "path": "themes/default/public/font/licenses/Apache License.txt",
    "chars": 11323,
    "preview": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licens"
  },
  {
    "path": "themes/default/public/font/licenses/SIL Open Font License.txt",
    "chars": 4392,
    "preview": "Copyright (c) 2012, Vernon Adams (vern@newtypography.co.uk),\nwith Reserved Font Name Oswald\n\nThis Font Software is licen"
  },
  {
    "path": "themes/default/public/fontello.json",
    "chars": 424,
    "preview": "{\n  \"name\": \"fontelico\",\n  \"css_prefix_text\": \"icon-\",\n  \"css_use_suffix\": false,\n  \"hinting\": true,\n  \"units_per_em\": 1"
  },
  {
    "path": "themes/default/public/manifest.json",
    "chars": 914,
    "preview": "{\n    \"name\": \"Let's Shorten That Url\",\n    \"short_name\": \"lstu\",\n    \"icons\": [\n        {\n            \"src\": \"/img/lstu"
  },
  {
    "path": "themes/default/templates/api.html.ep",
    "chars": 9701,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu API';\n% use Mojo::JSON qw(to_json);\n<h2>Lstu API</h2>\n%"
  },
  {
    "path": "themes/default/templates/index.html.ep",
    "chars": 1616,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu';\n<form class=\"form\" method=\"POST\" action=\"<%== url_for"
  },
  {
    "path": "themes/default/templates/layouts/default.html.ep",
    "chars": 4057,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtim"
  },
  {
    "path": "themes/default/templates/login.html.ep",
    "chars": 660,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu login';\n% if (defined stash('msg')) {\n    <%= stash('ms"
  },
  {
    "path": "themes/default/templates/logout.html.ep",
    "chars": 227,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu logout';\n<h4><%= l('You have been successfully logged o"
  },
  {
    "path": "themes/default/templates/partial/lstu.js.ep",
    "chars": 1465,
    "preview": "// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:\nvar j = document.getElementById('js');\nj.classList.remove('hidden');"
  },
  {
    "path": "themes/default/templates/stats.html.ep",
    "chars": 4938,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu stats';\n% use Mojo::Date;\n% my $order = $self->param('o"
  },
  {
    "path": "themes/milligram/Makefile",
    "chars": 611,
    "preview": "POT=lib/Lstu/I18N/milligram.pot\nSEDOPTS=-e \"s@SOME DESCRIPTIVE TITLE@Lstu language file@\" \\\n\t\t-e \"s@YEAR THE PACKAGE'S C"
  },
  {
    "path": "themes/milligram/lib/Lstu/I18N/en.po",
    "chars": 559,
    "preview": "# Lstu language file.\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu packa"
  },
  {
    "path": "themes/milligram/lib/Lstu/I18N/fr.po",
    "chars": 531,
    "preview": "# Lstu language file.\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu packa"
  },
  {
    "path": "themes/milligram/lib/Lstu/I18N/milligram.pot",
    "chars": 577,
    "preview": "# Lstu language file.\n# Copyright (C) 2015 Luc Didry\n# This file is distributed under the same license as the Lstu packa"
  },
  {
    "path": "themes/milligram/lib/Lstu/I18N/oc.po",
    "chars": 510,
    "preview": "# Lstu language file.\n# Copyright (C) 2013 Luc Didry\n# This file is distributed under the same license as the Lstu packa"
  },
  {
    "path": "themes/milligram/lib/Lstu/I18N.pm",
    "chars": 438,
    "preview": "# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:\npackage Lstu::I18N;\n\nuse base 'Locale::Maketext';\nuse File::Basename qw/dir"
  },
  {
    "path": "themes/milligram/public/css/lstu.css",
    "chars": 2352,
    "preview": "@font-face {\n    font-family: 'Henny_Penny';\n    font-style: normal;\n    font-weight: 400;\n    src: local('Henny Penny')"
  },
  {
    "path": "themes/milligram/public/css/lstu.min.css",
    "chars": 691,
    "preview": "@font-face{font-family:Henny_Penny;font-style:normal;font-weight:400;src:local('Henny Penny'),local('HennyPenny-Regular'"
  },
  {
    "path": "themes/milligram/public/css/milli-lstu.min.css",
    "chars": 11156,
    "preview": "/*!\n * Milligram v1.2.0\n * http://milligram.github.io\n *\n * Copyright (c) 2016 CJ Patoilo\n * Licensed under the MIT lice"
  },
  {
    "path": "themes/milligram/public/css/milligram.min.css",
    "chars": 8795,
    "preview": "/*!\n * Milligram v1.2.0\n * http://milligram.github.io\n *\n * Copyright (c) 2016 CJ Patoilo\n * Licensed under the MIT lice"
  },
  {
    "path": "themes/milligram/public/css/milligram.min.css.map",
    "chars": 11063,
    "preview": "{\"version\":3,\"sources\":[\"milligram.min.css\"],\"names\":[],\"mappings\":\"AAAA,KAAK,sBAAsB,eAAe,CAAC,KAAK,cAAc,yEAAyE,gBAAgB,g"
  },
  {
    "path": "themes/milligram/templates/index.html.ep",
    "chars": 1586,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu';\n<form class=\"form\" method=\"POST\" action=\"<%== url_for"
  },
  {
    "path": "themes/milligram/templates/layouts/default.html.ep",
    "chars": 4149,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtim"
  },
  {
    "path": "themes/milligram/templates/stats.html.ep",
    "chars": 3559,
    "preview": "% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:\n% title 'Lstu stats';\n% use Mojo::Date;\n<h2><%= l('Statistics') %></h"
  },
  {
    "path": "utilities/bootstrap.json",
    "chars": 17256,
    "preview": "{\n  \"vars\": {\n    \"@gray-base\": \"#000\",\n    \"@gray-darker\": \"lighten(@gray-base, 13.5%)\",\n    \"@gray-dark\": \"lighten(@gr"
  },
  {
    "path": "utilities/lstu-minion@.service",
    "chars": 292,
    "preview": "[Unit]\nDescription=Shortened URLs service job queue\nDocumentation=https://framagit.org/fiat-tux/hat-softwares/lstu\n\n[Ser"
  },
  {
    "path": "utilities/lstu.apache",
    "chars": 650,
    "preview": "<VirtualHost *:80>\n    ServerName http://lstu.example.org\n    ServerAdmin contact@lstu.example.org\n\n    ProxyRequests Of"
  },
  {
    "path": "utilities/lstu.default",
    "chars": 150,
    "preview": "# LDIR is the path where you installed Lstu\n# It has to end with a final /\nLDIR=/var/www/lstu/\n\n# USER is the user who w"
  },
  {
    "path": "utilities/lstu.init",
    "chars": 4676,
    "preview": "#!/bin/sh\n# vim: set ts=4 sw=4 sts=4 tw=0:\n# vim: set expandtab:\n\n### BEGIN INIT INFO\n# Provides:          lstu\n# Requir"
  },
  {
    "path": "utilities/lstu.nginx",
    "chars": 634,
    "preview": "upstream lstu {\n    server 127.0.0.1:8442;\n}\n\nserver {\n    listen 80; \n    listen [::]:80;\n\n    server_name lstu.example"
  },
  {
    "path": "utilities/lstu.service",
    "chars": 501,
    "preview": "[Unit]\nDescription=Shortened URLs service\nDocumentation=https://framagit.org/fiat-tux/hat-softwares/lstu\nRequires=networ"
  },
  {
    "path": "utilities/lstu_upstart.conf",
    "chars": 575,
    "preview": "# -*- upstart -*-\ndescription \"lstu\"\nauthor \"Luc Didry <luc@didry.org>\"\n\nstart on (networking)\nstop on runlevel [!2345]\n"
  },
  {
    "path": "utilities/migrations/mysql.sql",
    "chars": 718,
    "preview": "-- 1 up\nCREATE TABLE IF NOT EXISTS lstu (\n    short varchar(255) PRIMARY KEY,\n    url text,\n    counter integer default "
  },
  {
    "path": "utilities/migrations/postgresql.sql",
    "chars": 724,
    "preview": "-- 1 up\nCREATE TABLE IF NOT EXISTS lstu (\n    short text PRIMARY KEY,\n    url text,\n    counter integer default 0,\n    t"
  },
  {
    "path": "utilities/migrations/sqlite.sql",
    "chars": 1319,
    "preview": "-- 1 up\nCREATE TABLE IF NOT EXISTS lstu (\n    short     TEXT PRIMARY KEY,\n    url       TEXT,\n    counter   INTEGER,\n   "
  },
  {
    "path": "utilities/read_conf.pl",
    "chars": 1235,
    "preview": "#!/usr/bin/env perl\n\n# read_conf.pl - Outputs lstu's config value for given keypath\n\nuse strict;\nuse warnings;\n\nuse Find"
  }
]

About this extraction

This page contains the full source code of the ldidry/lstu GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 134 files (787.2 KB), approximately 249.0k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!