diff options
491 files changed, 25796 insertions, 22864 deletions
@@ -1,6 +1,14 @@ *.pyc *.swp *.swo +*~ +.DS_Store local_settings.py archweb.db +archweb.db-* +database.db +newrelic.key +tags +collected_static/ testing/ +env/ @@ -8,3 +8,7 @@ eliott <eliott@cactuswax.net> Thayer Williams <thayer@archlinux.org> Dusty Phillips <dusty@archlinux.org> +# PARABOLAWEB AUTHORS +Konstantinos Karantias <kostis@gtklocker.com> +Nicolás Reynolds <fauno@kiwwwi.com.ar> +Luke Shumaker <lukeshu@sbcglobal.net> @@ -1,3 +1,27 @@ +# Parabolaweb HACKING + +Things you should know: + +1. You don't need to mess with the fixtures every time you want to add + something. It's OK to just add it through the web-based admin + interface. The fixtures are for setting up the inital data that + things might not work without. + +2. Please don't add new pages to the `legacy_urls` list in `urls.py`. + It's for old, compatibility URLs. But once it's added there, it's + there forever, don't remove it. + +Which branch you should use: + + - If it's a Parabola-specific change, put it on `master`. + - If it's not Parabola-specific, put it on `archweb-generic`, then + merge it into `master`. + +Following is Archweb's version of the HACKING file; you should follow +it too. + +# Archweb HACKING + Contributing ====================== diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..57efeab9 --- /dev/null +++ b/Makefile @@ -0,0 +1,137 @@ +# Where are we? +dl-cache = ../download-cache +www = $(dl-cache)/www +bin = $(dl-cache)/bin + +# What versions of 3rd party libraries are we using? +jquery-ver=1.8.3 +bootstrap-ver=2.1.1 +tablesorter-ver=2.7 +d3-ver=3.0.6 +konami-ver=c0f686e647765860ff4d2fcb7b48122785432b75 + +# What files do we make? +branding-images = \ + sitestatic/favicon.ico sitestatic/silhouette.png \ + sitestatic/archnavbar/archlogo.png \ + sitestatic/logos/apple-touch-icon-114x114.png \ + sitestatic/logos/apple-touch-icon-144x144.png \ + sitestatic/logos/apple-touch-icon-57x57.png \ + sitestatic/logos/apple-touch-icon-72x72.png \ + sitestatic/logos/icon-transparent-64x64.png +targets = \ + $(branding-images) \ + sitestatic/.gitignore visualize/.gitignore \ + sitestatic/rss.png \ + sitestatic/rss@2x.png \ + sitestatic/bootstrap-typeahead.js \ + sitestatic/homepage.js \ + sitestatic/jquery-$(jquery-ver).min.js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js \ + sitestatic/konami.min.js \ + visualize/static/d3-$(d3-ver).js \ + visualize/static/d3-$(d3-ver).min.js + +js-basenames = $(sort $(patsubst %.min,%,$(patsubst %.js,%,$(filter %.js,$(targets))))) +generated = $(sort $(targets) $(foreach f,$(js-basenames),$f.js $f.min.js)) + +generated := $(generated) +targets := $(generated) + + +# The base rules + +all: $(targets) +.PHONY: all + +clean: + rm -f -- $(generated) +.PHONY: clean + +%/.gitignore: $(MAKEFILE_LIST) + printf -- '%s\n' $(patsubst $*%,%,$(filter $*/%,$(generated))) | LC_COLLATE=C sort > $@ + +# Make directories +$(dl-cache) $(dl-cache)/unzip $(bin): + mkdir -p '$@' + +# Don't have non-minimized .js stick around unless we asked for them. +.INTERMEDIATE: $(filter-out $(targets),$(generated)) + +# Turn on sane error handling +.DELETE_ON_ERROR: + +.PHONY: FORCE + + +# How to download files + + mangle = $(subst %,^25,$(subst :,^3A,$(subst =,^3D,$(subst ^,^5E,$1)))) +unmangle = $(subst ^5E,^,$(subst ^3D,=,$(subst ^3A,:,$(subst ^25,%,$1)))) + +$(www)/http/%: + mkdir -p '$(@D)' + wget 'http://$(call unmangle,$*)' -O '$@' + test -f '$@' && touch '$@' + +$(www)/https/%: + mkdir -p '$(@D)' + wget 'https://$(call unmangle,$*)' -O '$@' + test -f '$@' && touch '$@' + +$(www)/git/%: FORCE + mkdir -p '$(@D)' + gitget checkout 'git://$(call unmangle,$*)' '$@' || { rm -rf -- '$@'; false; } + test -d '$@' || { rm -rf -- '$@'; false; } + + +# Downloaded images + +$(dl-cache)/unzip/Feedicons_v.2/%: $(www)/https/web.archive.org/web/20120514074507/http^3A//www.zeusboxstudio.com/file_download/1/Feedicons_v.2.zip + mkdir -p '$(@D)' + bsdtar xfO $< 'Feedicons v.2/$*' > '$@' +sitestatic/rss.png: $(dl-cache)/unzip/Feedicons_v.2/RSS_16.png + cp $< $@ +sitestatic/rss@2x.png: $(dl-cache)/unzip/Feedicons_v.2/RSS_32.png + pngcrush $< $@ + +$(dl-cache)/unzip/parabola-artwork: $(www)/git/projects.parabola.nu/artwork.git\#branch=official/2013 | $(dl-cache)/unzip + cp -rT '$<' '$@' + make -C '$@' +$(dl-cache)/unzip/parabola-artwork/%: $(dl-cache)/unzip/parabola-artwork + test -e $@ && touch $@ +$(foreach i,$(branding-images),$(eval $i: $$(dl-cache)/unzip/parabola-artwork/$(notdir $i); install -Dm644 $$< $$@)) + +# Non-minimized .js files +sitestatic/bootstrap-typeahead.js: sitestatic/%: $(www)/https/raw.github.com/twitter/bootstrap/v$(bootstrap-ver)/js/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/jquery-$(jquery-ver).js: sitestatic/%: $(www)/http/code.jquery.com/% + cp $< $@ +sitestatic/jquery.tablesorter-$(tablesorter-ver).js: $(www)/https/raw.github.com/Mottie/tablesorter/v$(tablesorter-ver)/js/jquery.tablesorter.js + cp $< $@ +sitestatic/konami.js: sitestatic/%: $(www)/https/raw.github.com/snaptortoise/konami-js/$(konami-ver)/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/homepage.js: sitestatic/bootstrap-typeahead.min.js sitestatic/konami.min.js Makefile.d/homepage.js.in + { \ + echo '/* bootstrap-typeahead.min.js: */' && \ + cat sitestatic/bootstrap-typeahead.min.js && \ + echo && \ + echo '/* konami.min.js: */' && \ + sed -e 's,^\s*,,' -e 's,^return.*,&;,' sitestatic/konami.min.js && \ + echo && \ + echo '/* Main homepage.js content: */' && \ + cat Makefile.d/homepage.js.in ; \ + } > $@ +visualize/static/d3-$(d3-ver).js: %: $(www)/https/raw.github.com/mbostock/d3/v$(d3-ver)/d3.js + cp $< $@ + + +# The minimization processes + +JSMIN = { sed -n '1,/\*\//p' $1; uglifyjs --mangle --compress < $1; } > $2 + +%.min.js: %.js + $(call JSMIN,$<,$@) diff --git a/Makefile.d/bootstrap-typeahead.js.patch b/Makefile.d/bootstrap-typeahead.js.patch new file mode 100644 index 00000000..dfbab80b --- /dev/null +++ b/Makefile.d/bootstrap-typeahead.js.patch @@ -0,0 +1,38 @@ +commit f3e23371fa0473c82c28932e85570d94e5fc232a +Author: Dan McGee <dan@archlinux.org> +Date: Mon Sep 24 20:21:15 2012 -0500 + + Don't auto-select the first item in typeahead + + This assumption was baked into the Twitter bootstrap JS; kill it so it + is still easy to do a freeform search if wanted. + + Signed-off-by: Dan McGee <dan@archlinux.org> + +diff --git a/sitestatic/bootstrap-typeahead.js b/sitestatic/bootstrap-typeahead.js +index c2ccdea..3d355ae 100644 +--- a/sitestatic/bootstrap-typeahead.js ++++ b/sitestatic/bootstrap-typeahead.js +@@ -45,9 +45,11 @@ + + , select: function () { + var val = this.$menu.find('.active').attr('data-value') +- this.$element +- .val(this.updater(val)) +- .change() ++ if (val) { ++ this.$element ++ .val(this.updater(val)) ++ .change() ++ } + return this.hide() + } + +@@ -141,7 +143,6 @@ + return i[0] + }) + +- items.first().addClass('active') + this.$menu.html(items) + return this + } diff --git a/Makefile.d/homepage.js.in b/Makefile.d/homepage.js.in new file mode 100644 index 00000000..2d6f7910 --- /dev/null +++ b/Makefile.d/homepage.js.in @@ -0,0 +1,36 @@ +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '<ul class="pkgsearch-typeahead"></ul>', + items: 10, + updater: function(item) { + $('#pkgsearch-field').val(item); + $('#pkgsearch-form').submit(); + return item; + } + }).attr('autocomplete', 'off'); + $('#pkgsearch-field').keyup(function(e) { + if (e.keyCode === 13 && + $('ul.pkgsearch-typeahead li.active').size() === 0) { + $('#pkgsearch-form').submit(); + } + }); +} + +function setupKonami(image_src) { + var konami = new Konami(function() { + $('#konami').html('<img src="' + image_src + '" alt=""/>'); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} diff --git a/Makefile.d/konami.js.patch b/Makefile.d/konami.js.patch new file mode 100644 index 00000000..f6df91c4 --- /dev/null +++ b/Makefile.d/konami.js.patch @@ -0,0 +1,46 @@ +--- ..//web-cache/www/https/raw.github.com/snaptortoise/konami-js/c0f686e647765860ff4d2fcb7b48122785432b75/konami.js 2015-04-14 17:46:09.372597458 -0400 ++++ sitestatic/konami.js 2015-04-14 22:39:28.549281737 -0400 +@@ -56,7 +56,7 @@ + load: function(link){ + this.orig_keys = this.keys; + konami.addEvent(document,"touchmove",function(e){ +- if(e.touches.length == 1 && konami.iphone.capture==true){ ++ if(e.touches.length == 1 && konami.iphone.capture===true){ + var touch = e.touches[0]; + konami.iphone.stop_x = touch.pageX; + konami.iphone.stop_y = touch.pageY; +@@ -66,7 +66,7 @@ + } + }); + konami.addEvent(document,"touchend",function(evt){ +- if (konami.iphone.tap==true) konami.iphone.check_direction(link); ++ if (konami.iphone.tap===true) konami.iphone.check_direction(link); + },false); + konami.addEvent(document,"touchstart", function(evt){ + konami.iphone.start_x = evt.changedTouches[0].pageX +@@ -76,12 +76,12 @@ + }); + }, + check_direction: function(link){ +- x_magnitude = Math.abs(this.start_x-this.stop_x) +- y_magnitude = Math.abs(this.start_y-this.stop_y) +- x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; +- y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; +- result = (x_magnitude > y_magnitude) ? x : y; +- result = (this.tap==true) ? "TAP" : result; ++ var x_magnitude = Math.abs(this.start_x-this.stop_x) ++ var y_magnitude = Math.abs(this.start_y-this.stop_y) ++ var x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; ++ var y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; ++ var result = (x_magnitude > y_magnitude) ? x : y; ++ result = (this.tap===true) ? "TAP" : result; + + if (result==this.keys[0]) this.keys = this.keys.slice(1,this.keys.length) + if (this.keys.length==0) { +@@ -99,4 +99,4 @@ + } + + return konami; +-} +\ No newline at end of file ++} @@ -1,35 +1 @@ -# License - See LICENSE file. - -# Authors - See AUTHORS file. - -# Dependencies - - python - - mysql-python or python-pysqlite - - Django >= 1.2.X - -# Installation -For a simple testing installation: - - 1. Install dependencies. - $ pacman -S django python-pysqlite sqlite3 - - 2. Copy local_settings.py.example to local_settings.py and modify. - Make sure to uncomment the appropriate db section (either sqlite or mysql). - - 3. Sync the database to create it. - $ python manage.py syncdb - - 4. Load the fixtures to prepopulate some data. - $ python manage.py loaddata arches.json repos.json - - 5. Use the following commands to start a service instance - $ python manage.py runserver - - 6. To optionally populate the database with real data: - $ wget ftp://ftp.archlinux.org/core/os/i686/core.db.tar.gz - $ ./manage.py reporead i686 core.db.tar.gz - - (alter architecture and repo to get x86_64 and extra packages if needed) - +README.md
\ No newline at end of file diff --git a/README.BRANDING b/README.BRANDING new file mode 100644 index 00000000..2dc186b0 --- /dev/null +++ b/README.BRANDING @@ -0,0 +1,74 @@ +It is now fairly easy to re-brand archweb. +Replacing logos is still a bit of work. +Here is a summary of the text files that need to be changed to +re-brand it, from the text side. + +Files used to configure branding/URL stuff +------------------------------------------ + + * `settings.py` + * `templates/templatetags/jinja2.py` + * `main/templatetags/wiki.py` + * `main/templatetags/bugs.py` + +Files with minor Arch stuff that's just easier to patch +------------------------------------------------------- + +`devel/fixtures/staff_groups.json` + * Mentions of Arch in "description" fields + +`templates/packages/flaghelp.html` + * link to "arch-general" mailing list + +`templates/packages/flag.html` + * link to "arch-general" mailing list + +`templates/packages/removed.html` + * link to AUR + +`templates/packages/search.html` + * link to AUR + +`urls.py` + +Files with a significant amount of Arch-specific content: +--------------------------------------------------------- + +`templates/base.html` + * main navbar + * link to `bbs.archlinux.org` + * link to the AUR + * logged in navbar + * link to "arch-dev" mailing list + * link to `stats.archlinux.org/munin` + * copyright statement is Arch-specific. + +`templates/public/index.html` + * The text in the intro box describes Arch Linux. + * sidebar + * Community + * link to `planet.archlinux.org` + * Support + * link to `schwag.archlinux.ca` + * link to `www.zazzle.com/archlinux*` + * link to `www.freewear.org/?page=list_items&org=Archlinux` + * Development + * link to `projects.archlinux.org` ("Official Arch projects") + * More Resources + * link to wiki article "Arch Linux Press Review" + * Below sidebar + * Arch's donate button + * Arch's sponsors + +`templates/public/feeds.html` + * links to AUR + * links to feeds on `bugs.archlinux.org` + +Files with totally Arch-specific content: +----------------------------------------- + + * `templates/public/about.html` + * `templates/public/art.html` + * `templates/public/donate.html` + * `templates/public/download.html` + * `templates/public/svn.html` diff --git a/README.md b/README.md new file mode 100644 index 00000000..ee3c9cca --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# Parabolaweb README + +It is recommended that you just install the (Parabola) package +`parabolaweb-utils`, it + + - depends on the dependencies of parabolaweb (that is, don't use + virtualenv) + - has a `parabolaweb-update` program that does most of the things here + - has a `parabolaweb-changepassword` program that allows system users + to change their parabolaweb password + - has `/etc/uwsgi/parabolaweb.ini.example` + +To run parabolaweb, you can use `./manage testserver` to run a small +HTTP server, or run `systemctl enable --now uwsgi@parabolaweb.socket`, +and stick that behind a proper web server that speaks WSGI (such as +Nginx). + +Following is Archweb's readme, as I figure it might be useful for some people, +but I have given up on maintaining it for parabolaweb. + +# Archweb README + +To get a pretty version of this document, run + + $ markdown README > README.html + +# License + +See LICENSE file. + +# Authors + +See AUTHORS file. + +# Dependencies + +- python2 +- python2-virtualenv + +# Python dependencies + +More detail in `requirements.txt` and `requirements_prod.txt`; it is best to +use virtualenv and pip to handle these. But if you insist on (Arch Linux) +packages, you will probably want the following: + +- django +- python2-psycopg2 +- python2-markdown +- python2-memcached + +# Testing Installation + +1. Run `virtualenv2`. + + cd /path/to/archweb && virtualenv2 ./env/ + +2. Activate the virtualenv. + + source ./env/bin/activate + +2. Install dependencies through `pip`. + + pip install -r requirements.txt + +3. Copy `local_settings.py.example` to `local_settings.py` and modify. + Make sure to uncomment the appropriate database section (either sqlite or + PostgreSQL). + +4. Sync the database to create it. + + ./manage.py syncdb + +5. Migrate changes. + + ./manage.py migrate + +6. Load the fixtures to prepopulate some data. If you don't want some of the + provided data, adjust the file glob accordingly. + + ./manage.py loaddata main/fixtures/*.json + ./manage.py loaddata devel/fixtures/*.json + ./manage.py loaddata mirrors/fixtures/*.json + ./manage.py loaddata releng/fixtures/*.json + +7. Use the following commands to start a service instance + + ./manage.py runserver + +8. To optionally populate the database with real data: + + wget http://mirrors.kernel.org/archlinux/core/os/i686/core.db.tar.gz + ./manage.py reporead i686 core.db.tar.gz + ./manage.py syncisos + +Alter architecture and repo to get x86\_64 and packages from other repos if +needed. + +# Production Installation + +Ask someone who knows, or you are going to be in trouble. + +vim: set syntax=markdown et: @@ -1,4 +0,0 @@ -TODO: - - refactor stats by templates in dashboard, maybe a templatetag - - diff --git a/archweb.wsgi b/archweb.wsgi new file mode 100644 index 00000000..20ec463e --- /dev/null +++ b/archweb.wsgi @@ -0,0 +1,39 @@ +#!/usr/bin/python +import os +import sys +import site + +base_path = os.path.dirname(os.path.realpath(__file__)) + +virtualenv_path = os.path.join(base_path, "env") +if os.path.isdir(virtualenv_path): + site.addsitedir(os.path.join(virtualenv_path, 'lib/python2.7/site-packages')) + sys.path.insert(0, base_path) + +os.environ['DJANGO_SETTINGS_MODULE'] = "settings" + +os.chdir(base_path) + +using_newrelic = False +try: + key_path = os.path.join(base_path, "newrelic.key") + if os.path.exists(key_path): + with open(key_path) as keyfile: + key = keyfile.read().strip() + os.environ["NEW_RELIC_LICENSE_KEY"] = key + + import newrelic.agent + from newrelic.api.exceptions import ConfigurationError + try: + newrelic.agent.initialize(os.path.join(base_path, "newrelic.ini")) + using_newrelic = True + except ConfigurationError: + pass +except ImportError: + pass + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +if using_newrelic: + application = newrelic.agent.wsgi_application()(application) diff --git a/devel/admin.py b/devel/admin.py new file mode 100644 index 00000000..d1729fe3 --- /dev/null +++ b/devel/admin.py @@ -0,0 +1,50 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from django.contrib.auth.models import User + +from .models import UserProfile, StaffGroup, MasterKey, DeveloperKey, PGPSignature + + +class UserProfileInline(admin.StackedInline): + model = UserProfile + + +class UserProfileAdmin(UserAdmin): + inlines = [UserProfileInline] + list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active') + list_filter = ('is_staff', 'is_superuser', 'is_active') + + +class StaffGroupAdmin(admin.ModelAdmin): + list_display = ('name', 'group', 'sort_order', 'member_title', 'slug') + prepopulated_fields = {'slug': ('name',)} + + +class MasterKeyAdmin(admin.ModelAdmin): + list_display = ('pgp_key', 'owner', 'created', 'revoker', 'revoked') + search_fields = ('pgp_key', 'owner__username', 'revoker__username') + date_hierarchy = 'created' + + +class DeveloperKeyAdmin(admin.ModelAdmin): + list_display = ('key', 'parent', 'owner', 'created', 'expires', 'revoked') + search_fields = ('key', 'owner__username') + list_filter = ('owner',) + date_hierarchy = 'created' + + +class PGPSignatureAdmin(admin.ModelAdmin): + list_display = ('signer', 'signee', 'created', 'expires', 'revoked') + search_fields = ('signer', 'signee') + date_hierarchy = 'created' + + +admin.site.unregister(User) +admin.site.register(User, UserProfileAdmin) +admin.site.register(StaffGroup, StaffGroupAdmin) + +admin.site.register(MasterKey, MasterKeyAdmin) +admin.site.register(DeveloperKey, DeveloperKeyAdmin) +admin.site.register(PGPSignature, PGPSignatureAdmin) + +# vim: set ts=4 sw=4 et: diff --git a/devel/fields.py b/devel/fields.py new file mode 100644 index 00000000..dd22a92e --- /dev/null +++ b/devel/fields.py @@ -0,0 +1,28 @@ +from django.db import models +from django.core.validators import RegexValidator + + +class PGPKeyField(models.CharField): + def __init__(self, *args, **kwargs): + super(PGPKeyField, self).__init__(*args, **kwargs) + self.validators.append(RegexValidator(r'^[0-9A-F]{40}$', + "Ensure this value consists of 40 hex characters.", 'hex_char')) + + def to_python(self, value): + if value == '' or value is None: + return None + value = super(PGPKeyField, self).to_python(value) + # remove all spaces + value = value.replace(' ', '') + # prune prefixes, either 0x or 2048R/ type + if value.startswith('0x'): + value = value[2:] + value = value.split('/')[-1] + # make all (hex letters) uppercase + return value.upper() + + def formfield(self, **kwargs): + # override so we don't set max_length form field attribute + return models.Field.formfield(self, **kwargs) + +# vim: set ts=4 sw=4 et: diff --git a/devel/fixtures/staff_groups.json b/devel/fixtures/staff_groups.json new file mode 100644 index 00000000..1f26b54e --- /dev/null +++ b/devel/fixtures/staff_groups.json @@ -0,0 +1,58 @@ +[ +{ + "fields": { + "group": [ + "Hackers" + ], + "description": "This is a list of the current Parabola Hackers. They maintain the [libre] package repository and keep the [core], [extra], and [community] repositories clean of non-Free software, in addition to doing any other developer duties.", + "sort_order": 1, + "member_title": "Hacker", + "slug": "hackers", + "name": "Hackers" + }, + "model": "devel.staffgroup", + "pk": 1 +}, +{ + "fields": { + "group": [ + "Retired Hackers" + ], + "description": "Below you can find a list of ex-hackers (aka project fellows). These folks helped make Parabola what it is today. Thanks!", + "sort_order": 11, + "member_title": "Fellow", + "slug": "hacker-fellows", + "name": "Hacker Fellows" + }, + "model": "devel.staffgroup", + "pk": 3 +}, +{ + "fields": { + "group": [ + "Support Staff" + ], + "description": "This is a list of the current Parabola forum moderators, wiki admins, IRC moderators, mirror maintenance, and everything else that keeps a GNU/Linux distro running smoothly.", + "sort_order": 5, + "member_title": "Staff", + "slug": "support-staff", + "name": "Support Staff" + }, + "model": "devel.staffgroup", + "pk": 5 +}, +{ + "fields": { + "group": [ + "Artists" + ], + "description": "This is a list of the current Parabola Artists. They maintain Parabola Artwork, including digital art, traditional art, skins for applications, customization utilities, and everything else that keeps a GNU/Linux distro for a better visualization and outreach through the free culture.", + "sort_order": 12, + "member_title": "Artist", + "slug": "artists", + "name": "Artists" + }, + "model": "devel.staffgroup", + "pk": 6 +} +] diff --git a/devel/forms.py b/devel/forms.py new file mode 100644 index 00000000..d953c614 --- /dev/null +++ b/devel/forms.py @@ -0,0 +1,104 @@ +import random +from collections import OrderedDict +from string import ascii_letters, digits + +from django import forms +from django.conf import settings +from django.contrib.auth.models import User, Group +from django.contrib.sites.models import Site +from django.core.mail import send_mail +from django.template import loader, Context + +from .models import UserProfile + + +class ProfileForm(forms.Form): + email = forms.EmailField(label='Private email (not shown publicly):', + help_text="Used for out-of-date notifications, etc.") + passwd1 = forms.CharField(label='New Password', required=False, + widget=forms.PasswordInput) + passwd2 = forms.CharField(label='Confirm Password', required=False, + widget=forms.PasswordInput) + + def clean(self): + if self.cleaned_data['passwd1'] != self.cleaned_data['passwd2']: + raise forms.ValidationError('Passwords do not match.') + return self.cleaned_data + + +class UserProfileForm(forms.ModelForm): + def clean_pgp_key(self): + data = self.cleaned_data['pgp_key'] + # strip 0x prefix if provided; store uppercase + if data.startswith('0x'): + data = data[2:] + return data.upper() + + class Meta: + model = UserProfile + exclude = ('allowed_repos', 'user', 'latin_name') + + +class NewUserForm(forms.ModelForm): + username = forms.CharField(max_length=30) + private_email = forms.EmailField() + first_name = forms.CharField(required=False) + last_name = forms.CharField(required=False) + groups = forms.ModelMultipleChoiceField(required=False, + queryset=Group.objects.all()) + + class Meta: + model = UserProfile + exclude = ('picture', 'user') + + def __init__(self, *args, **kwargs): + super(NewUserForm, self).__init__(*args, **kwargs) + # Hack ourself so certain fields appear first + old = self.fields + self.fields = OrderedDict() + keys = ('username', 'private_email', 'first_name', 'last_name', + 'alias', 'public_email') + for key in keys: + self.fields[key] = old[key] + for key, val in old.items(): + if key not in keys: + self.fields[key] = old[key] + + def clean_username(self): + username = self.cleaned_data['username'] + if User.objects.filter(username=username).exists(): + raise forms.ValidationError( + "A user with that username already exists.") + return username + + def save(self, commit=True): + profile = super(NewUserForm, self).save(False) + pwletters = ascii_letters + digits + password = ''.join([random.choice(pwletters) for _ in xrange(8)]) + user = User.objects.create_user(username=self.cleaned_data['username'], + email=self.cleaned_data['private_email'], password=password) + user.first_name = self.cleaned_data['first_name'] + user.last_name = self.cleaned_data['last_name'] + user.save() + # sucks that the MRM.add() method can't take a list directly... we have + # to resort to dirty * magic. + user.groups.add(*self.cleaned_data['groups']) + profile.user = user + if commit: + profile.save() + self.save_m2m() + + template = loader.get_template('devel/new_account.txt') + ctx = Context({ + 'site': Site.objects.get_current(), + 'user': user, + 'password': password, + }) + + send_mail("Your new archweb account", + template.render(ctx), + settings.BRANDING_EMAIL, + [user.email], + fail_silently=False) + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/generate_keyring.py b/devel/management/commands/generate_keyring.py new file mode 100644 index 00000000..9c52dadc --- /dev/null +++ b/devel/management/commands/generate_keyring.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +""" +generate_keyring command + +Assemble a GPG keyring with all known developer keys. + +Usage: ./manage.py generate_keyring <keyserver> <keyring_path> +""" + +from django.core.management.base import BaseCommand, CommandError + +import logging +import subprocess +import sys + +from devel.models import MasterKey, UserProfile + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(BaseCommand): + args = "<keyserver> <keyring_path> [ownertrust_path]" + help = "Assemble a GPG keyring with all known developer keys." + + def handle(self, *args, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + if len(args) < 2: + raise CommandError("keyserver and keyring_path must be provided") + + generate_keyring(args[0], args[1]) + + if len(args) > 2: + generate_ownertrust(args[2]) + + +def generate_keyring(keyserver, keyring): + logger.info("getting all known key IDs") + + # Screw you Django, for not letting one natively do value != <empty string> + key_ids = UserProfile.objects.filter( + pgp_key__isnull=False).extra(where=["pgp_key != ''"]).values_list( + "pgp_key", flat=True) + logger.info("%d keys fetched from user profiles", len(key_ids)) + master_key_ids = MasterKey.objects.values_list("pgp_key", flat=True) + logger.info("%d keys fetched from master keys", len(master_key_ids)) + + # GPG is stupid and interprets any filename without path portion as being + # in ~/.gnupg/. Fake it out if we just get a bare filename. + if '/' not in keyring: + keyring = './%s' % keyring + gpg_cmd = ["gpg", "--no-default-keyring", "--keyring", keyring, + "--keyserver", keyserver, "--recv-keys"] + logger.info("running command: %r", gpg_cmd) + gpg_cmd.extend(key_ids) + gpg_cmd.extend(master_key_ids) + subprocess.check_call(gpg_cmd) + logger.info("keyring at %s successfully updated", keyring) + + +TRUST_LEVELS = { + 'unknown': 0, + 'expired': 1, + 'undefined': 2, + 'never': 3, + 'marginal': 4, + 'fully': 5, + 'ultimate': 6, +} + + +def generate_ownertrust(trust_path): + master_key_ids = MasterKey.objects.values_list("pgp_key", flat=True) + with open(trust_path, "w") as trustfile: + for key_id in master_key_ids: + trustfile.write("%s:%d:\n" % (key_id, TRUST_LEVELS['marginal'])) + logger.info("trust file at %s created or overwritten", trust_path) + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/pgp_import.py b/devel/management/commands/pgp_import.py new file mode 100644 index 00000000..7a124f77 --- /dev/null +++ b/devel/management/commands/pgp_import.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- +""" +pgp_import command + +Import keys and signatures from a given GPG keyring. + +Usage: ./manage.py pgp_import <keyring_path> +""" + +from collections import namedtuple, OrderedDict +from datetime import datetime +import logging +from pytz import utc +import subprocess +import sys + +from django.core.management.base import BaseCommand, CommandError +from django.db import transaction + +from devel.models import DeveloperKey, PGPSignature +from devel.utils import UserFinder + + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(BaseCommand): + args = "<keyring_path>" + help = "Import keys and signatures from a given GPG keyring." + + def handle(self, *args, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + if len(args) < 1: + raise CommandError("keyring_path must be provided") + + import_keys(args[0]) + import_signatures(args[0]) + + +def get_date(epoch_string): + '''Convert a epoch string into a python 'date' object (not datetime).''' + if not epoch_string: + return None + return datetime.utcfromtimestamp(int(epoch_string)).date() + + +def get_datetime(epoch_string): + '''Convert a epoch string into a python 'datetime' object.''' + if not epoch_string: + return None + return datetime.utcfromtimestamp(int(epoch_string)).replace(tzinfo=utc) + + +def call_gpg(keyring, *args): + # GPG is stupid and interprets any filename without path portion as being + # in ~/.gnupg/. Fake it out if we just get a bare filename. + if '/' not in keyring: + keyring = './%s' % keyring + gpg_cmd = ["gpg2", "--no-default-keyring", "--keyring", keyring, + "--with-colons", "--fixed-list-mode"] + gpg_cmd.extend(args) + logger.info("running command: %s", ' '.join(gpg_cmd)) + proc = subprocess.Popen(gpg_cmd, stdout=subprocess.PIPE) + outdata, errdata = proc.communicate() + if proc.returncode != 0: + logger.error(errdata) + raise subprocess.CalledProcessError(proc.returncode, gpg_cmd) + return outdata + + +class KeyData(object): + def __init__(self, key, created, expires): + self.key = key + self.created = get_datetime(created) + self.expires = get_datetime(expires) + self.parent = None + self.revoked = None + self.db_id = None + + +def parse_keydata(data): + keys = OrderedDict() + current_pubkey = None + + # parse all of the output from our successful GPG command + logger.info("parsing command output") + node = None + for line in data.split('\n'): + parts = line.split(':') + if parts[0] == 'pub': + key = parts[4] + current_pubkey = key + keys[key] = KeyData(key, parts[5], parts[6]) + node = parts[0] + elif parts[0] == 'sub': + key = parts[4] + keys[key] = KeyData(key, parts[5], parts[6]) + keys[key].parent = current_pubkey + node = parts[0] + elif parts[0] == 'uid': + node = parts[0] + elif parts[0] == 'rev' and node in ('pub', 'sub'): + keys[current_pubkey].revoked = get_datetime(parts[5]) + + return keys + + +def find_key_owner(key, keys, finder): + '''Recurse up the chain, looking for an owner.''' + if key is None: + return None + owner = finder.find_by_pgp_key(key.key) + if owner: + return owner + if key.parent: + return find_key_owner(keys[key.parent], keys, finder) + return None + + +def import_keys(keyring): + outdata = call_gpg(keyring, "--list-sigs") + keydata = parse_keydata(outdata) + + logger.info("creating or finding %d keys", len(keydata)) + created_ct = updated_ct = 0 + with transaction.atomic(): + finder = UserFinder() + # we are dependent on parents coming before children; parse_keydata + # uses an OrderedDict to ensure this is the case. + for data in keydata.values(): + parent_id = None + if data.parent: + parent_data = keydata.get(data.parent, None) + if parent_data: + parent_id = parent_data.db_id + other = { + 'expires': data.expires, + 'revoked': data.revoked, + 'parent_id': parent_id, + } + dkey, created = DeveloperKey.objects.get_or_create( + key=data.key, created=data.created, defaults=other) + data.db_id = dkey.id + + # set or update any additional data we might need to + needs_save = False + if created: + created_ct += 1 + else: + for k, v in other.items(): + if getattr(dkey, k) != v: + setattr(dkey, k, v) + needs_save = True + if dkey.owner_id is None: + owner = find_key_owner(data, keydata, finder) + if owner is not None: + dkey.owner = owner + needs_save = True + if needs_save: + dkey.save() + updated_ct += 1 + + key_ct = DeveloperKey.objects.all().count() + logger.info("%d total keys in database", key_ct) + logger.info("created %d, updated %d keys", created_ct, updated_ct) + + +class SignatureData(object): + def __init__(self, signer, signee, created): + self.signer = signer + self.signee = signee + self.created = created + self.expires = None + self.revoked = None + + +def parse_sigdata(data): + nodes = {} + edges = [] + current_pubkey = None + + # parse all of the output from our successful GPG command + logger.info("parsing command output") + for line in data.split('\n'): + parts = line.split(':') + if parts[0] == 'pub': + current_pubkey = parts[4] + nodes[current_pubkey] = None + elif parts[0] == 'uid': + uid = parts[9] + # only set uid if this is the first one encountered + if nodes[current_pubkey] is None: + nodes[current_pubkey] = uid + elif parts[0] == 'sig': + signer = parts[4] + created = get_date(parts[5]) + edge = SignatureData(signer, current_pubkey, created) + if parts[6]: + edge.expires = get_date(parts[6]) + edges.append(edge) + elif parts[0] == 'rev': + signer = parts[4] + revoked = get_date(parts[5]) + # revoke any prior edges that match + matches = [e for e in edges if e.signer == signer + and e.signee == current_pubkey] + for edge in matches: + edge.revoked = revoked + + return nodes, edges + + +def import_signatures(keyring): + outdata = call_gpg(keyring, "--list-sigs") + nodes, edges = parse_sigdata(outdata) + + # now prune the data down to what we actually want. + # prune edges not in nodes, remove duplicates, and self-sigs + pruned_edges = {edge for edge in edges + if edge.signer in nodes and edge.signer != edge.signee} + + logger.info("creating or finding up to %d signatures", len(pruned_edges)) + created_ct = updated_ct = 0 + with transaction.atomic(): + for edge in pruned_edges: + sig, created = PGPSignature.objects.get_or_create( + signer=edge.signer, signee=edge.signee, + created=edge.created, expires=edge.expires, + defaults={ 'revoked': edge.revoked }) + if sig.revoked != edge.revoked: + sig.revoked = edge.revoked + sig.save() + updated_ct += 1 + if created: + created_ct += 1 + + sig_ct = PGPSignature.objects.all().count() + logger.info("%d total signatures in database", sig_ct) + logger.info("created %d, updated %d signatures", created_ct, updated_ct) + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/rematch_developers.py b/devel/management/commands/rematch_developers.py new file mode 100644 index 00000000..bbb43df0 --- /dev/null +++ b/devel/management/commands/rematch_developers.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +""" +rematch_developers command + +Match all packages with a packager_str but NULL packager_id to a packager if we +can find one. + +Also, match all flag requests with a NULL user_id that have a user_email +matching up to a developer if we can find one. + +Usage: ./manage.py rematch_developers +""" + +from django.core.management.base import NoArgsCommand +from django.db import transaction + +import sys +import logging + +from devel.utils import UserFinder +from main.models import Package +from packages.models import FlagRequest + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(NoArgsCommand): + help = "Match and map objects in database to developer emails" + + def handle_noargs(self, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + finder = UserFinder() + match_packager(finder) + match_flagrequest(finder) + +@transaction.atomic +def match_packager(finder): + logger.info("getting all unmatched packager strings") + package_count = matched_count = 0 + mapping = {} + + unmatched = Package.objects.filter(packager__isnull=True).values_list( + 'packager_str', flat=True).order_by().distinct() + + logger.info("%d packager strings retrieved", len(unmatched)) + for packager in unmatched: + logger.debug("packager string %s", packager) + user = finder.find(packager) + if user: + mapping[packager] = user + logger.debug(" found user %s" % user.username) + matched_count += 1 + + for packager_str, user in mapping.items(): + package_count += Package.objects.filter(packager__isnull=True, + packager_str=packager_str).update(packager=user) + + logger.info("%d packages updated, %d packager strings matched", + package_count, matched_count) + + +@transaction.atomic +def match_flagrequest(finder): + logger.info("getting all flag request email addresses from unknown users") + req_count = matched_count = 0 + mapping = {} + + unmatched = FlagRequest.objects.filter(user__isnull=True).values_list( + 'user_email', flat=True).order_by().distinct() + + logger.info("%d email addresses retrieved", len(unmatched)) + for user_email in unmatched: + logger.debug("email %s", user_email) + user = finder.find_by_email(user_email) + if user: + mapping[user_email] = user + logger.debug(" found user %s" % user.username) + matched_count += 1 + + for user_email, user in mapping.items(): + req_count += FlagRequest.objects.filter(user__isnull=True, + user_email=user_email).update(user=user) + + logger.info("%d request emails updated, %d emails matched", + req_count, matched_count) + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index 7c468001..c76b5011 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -13,12 +13,10 @@ Example: ./manage.py reporead i686 /tmp/core.db.tar.gz """ -from django.core.management.base import BaseCommand, CommandError -from django.contrib.auth.models import User -from django.db import transaction -from django.db.models import Q - -import codecs +from base64 import b64decode +from collections import defaultdict +from copy import copy +import io import os import re import sys @@ -26,16 +24,26 @@ import tarfile import logging from datetime import datetime from optparse import make_option +from pytz import utc -from logging import ERROR, WARNING, INFO, DEBUG +from django.core.management.base import BaseCommand, CommandError +from django.db import connections, router, transaction +from django.db.utils import IntegrityError +from django.utils.timezone import now + +from devel.utils import UserFinder +from main.models import Arch, Package, PackageFile, Repo +from packages.models import Depend, Conflict, Provision, Replacement, Update +from packages.utils import parse_version -from main.models import Arch, Package, Repo logging.basicConfig( - level=WARNING, + level=logging.WARNING, format='%(asctime)s -> %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', stream=sys.stderr) +TRACE = 5 +logging.addLevelName(TRACE, 'TRACE') logger = logging.getLogger() class Command(BaseCommand): @@ -51,8 +59,6 @@ class Command(BaseCommand): def handle(self, arch=None, filename=None, **options): if not arch: raise CommandError('Architecture is required.') - if not validate_arch(arch): - raise CommandError('Specified architecture %s is not currently known.' % arch) if not filename: raise CommandError('Package database file is required.') filename = os.path.normpath(filename) @@ -61,257 +67,414 @@ class Command(BaseCommand): v = int(options.get('verbosity', 0)) if v == 0: - logger.level = ERROR + logger.level = logging.ERROR elif v == 1: - logger.level = INFO - elif v == 2: - logger.level = DEBUG - - import signal, traceback - handler = lambda sig, stack: traceback.print_stack(stack) - signal.signal(signal.SIGQUIT, handler) - signal.signal(signal.SIGUSR1, handler) + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG return read_repo(arch, filename, options) -class Pkg(object): +class RepoPackage(object): """An interim 'container' object for holding Arch package data.""" - bare = ( 'name', 'base', 'arch', 'desc', 'filename', - 'md5sum', 'url', 'builddate', 'packager' ) - squash = ( 'license', ) + bare = ( 'name', 'base', 'arch', 'filename', + 'md5sum', 'sha256sum', 'url', 'packager' ) number = ( 'csize', 'isize' ) + collections = ( 'depends', 'optdepends', 'makedepends', 'checkdepends', + 'conflicts', 'provides', 'replaces', 'groups', 'license') def __init__(self, repo): self.repo = repo self.ver = None self.rel = None - for k in self.bare + self.squash + self.number: + self.epoch = 0 + self.desc = None + self.pgpsig = None + for k in self.bare + self.number: setattr(self, k, None) + for k in self.collections: + setattr(self, k, ()) + self.builddate = None + self.files = None def populate(self, values): for k, v in values.iteritems(): # ensure we stay under our DB character limit if k in self.bare: setattr(self, k, v[0][:254]) - elif k in self.squash: - setattr(self, k, u', '.join(v)[:254]) elif k in self.number: setattr(self, k, long(v[0])) - elif k == 'force': - setattr(self, k, True) + elif k in ('desc', 'pgpsig'): + # do NOT prune these values at all + if v[0] == None: + v[0] = 'missing' + setattr(self, k, v[0]) elif k == 'version': - ver, rel = v[0].rsplit('-') - setattr(self, 'ver', ver) - setattr(self, 'rel', rel) + self.ver, self.rel, self.epoch = parse_version(v[0]) + elif k == 'builddate': + try: + builddate = datetime.utcfromtimestamp(int(v[0])) + self.builddate = builddate.replace(tzinfo=utc) + except ValueError: + logger.warning( + 'Package %s had unparsable build date %s', + self.name, v[0]) else: - # files, depends, etc. - setattr(self, k, v) - - -def find_user(userstring): - ''' - Attempt to find the corresponding User object for a standard - packager string, e.g. something like - 'A. U. Thor <author@example.com>'. - We start by searching for a matching email address; we then move onto - matching by first/last name. If we cannot find a user, then return None. - ''' - if userstring in find_user.cache: - return find_user.cache[userstring] - matches = re.match(r'^([^<]+)? ?<([^>]*)>', userstring) - if not matches: - return None + # anything left in collections + setattr(self, k, tuple(v)) - user = None - name = matches.group(1) - email = matches.group(2) - - def user_email(): - return User.objects.get(email=email) - def profile_email(): - return User.objects.get(userprofile_user__public_email=email) - def user_name(): - # yes, a bit odd but this is the easiest way since we can't always be - # sure how to split the name. Ensure every 'token' appears in at least - # one of the two name fields. - name_q = Q() - for token in name.split(): - name_q &= (Q(first_name__icontains=token) | - Q(last_name__icontains=token)) - return User.objects.get(name_q) - - for matcher in (user_email, profile_email, user_name): + @property + def files_list(self): + data_file = io.TextIOWrapper(io.BytesIO(self.files), encoding='UTF-8') try: - user = matcher() - break - except (User.DoesNotExist, User.MultipleObjectsReturned): - pass + info = parse_info(data_file) + except UnicodeDecodeError: + logger.warn("Could not correctly decode files list for %s", + self.name) + return None + return info['files'] + + @property + def full_version(self): + '''Very similar to the main.models.Package method.''' + if self.epoch > 0: + return u'%d:%s-%s' % (self.epoch, self.ver, self.rel) + return u'%s-%s' % (self.ver, self.rel) + + +DEPEND_RE = re.compile(r"^(.+?)((>=|<=|=|>|<)(.+))?$") + +def create_depend(package, dep_str, deptype='D'): + depend = Depend(pkg=package, deptype=deptype) + # lop off any description first, don't get confused by epoch + parts = dep_str.split(': ', 1) + if len(parts) > 1: + depend.description = parts[1].strip() + match = DEPEND_RE.match(parts[0].strip()) + if match: + depend.name = match.group(1) + if match.group(3): + depend.comparison = match.group(3) + if match.group(4): + depend.version = match.group(4) + else: + logger.warning('Package %s had unparsable depend string %s', + package.pkgname, dep_str) + return None + return depend + +def create_related(model, package, rel_str, equals_only=False): + related = model(pkg=package) + match = DEPEND_RE.match(rel_str) + if match: + related.name = match.group(1) + if match.group(3): + comp = match.group(3) + if not equals_only: + related.comparison = comp + elif comp != '=': + logger.warning( + 'Package %s had unexpected comparison operator %s for %s in %s', + package.pkgname, comp, model.__name__, rel_str) + if match.group(4): + related.version = match.group(4) + else: + logger.warning('Package %s had unparsable %s string %s', + package.pkgname, model.___name__, rel_str) + return None + return related + - find_user.cache[userstring] = user - return user +def create_multivalued(dbpkg, repopkg, db_attr, repo_attr): + '''Populate the simplest of multivalued attributes. These are those that + only deal with a 'name' attribute, such as licenses, groups, etc. The input + and output objects and attribute names are specified, and everything is + done via getattr().''' + collection = getattr(dbpkg, db_attr) + collection.all().delete() + model = collection.model + new_items = [] + for name in getattr(repopkg, repo_attr): + new_items.append(model(pkg=dbpkg, name=name)) + if new_items: + model.objects.bulk_create(new_items) -# cached mappings of user strings -> User objects so we don't have to do the -# lookup more than strictly necessary. -find_user.cache = {} +finder = UserFinder() def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): + # we reset the flag date only if the upstream version components change; + # e.g. epoch or pkgver, but not pkgrel + if dbpkg.epoch is None or dbpkg.epoch != repopkg.epoch: + dbpkg.flag_date = None + elif dbpkg.pkgver is None or dbpkg.pkgver != repopkg.ver: + dbpkg.flag_date = None + if repopkg.base: dbpkg.pkgbase = repopkg.base else: dbpkg.pkgbase = repopkg.name dbpkg.pkgver = repopkg.ver dbpkg.pkgrel = repopkg.rel - dbpkg.pkgdesc = repopkg.desc - dbpkg.license = repopkg.license + dbpkg.epoch = repopkg.epoch + try: + dbpkg.pkgdesc = repopkg.desc + except AttributeError: + dbpkg.pkgdesc = "missing" dbpkg.url = repopkg.url dbpkg.filename = repopkg.filename dbpkg.compressed_size = repopkg.csize dbpkg.installed_size = repopkg.isize - try: - dbpkg.build_date = datetime.utcfromtimestamp(int(repopkg.builddate)) - except ValueError: - try: - dbpkg.build_date = datetime.strptime(repopkg.builddate, - '%a %b %d %H:%M:%S %Y') - except ValueError: - logger.warning('Package %s had unparsable build date %s' % \ - (repopkg.name, repopkg.builddate)) + dbpkg.build_date = repopkg.builddate dbpkg.packager_str = repopkg.packager # attempt to find the corresponding django user for this string - dbpkg.packager = find_user(repopkg.packager) + dbpkg.packager = finder.find(repopkg.packager) + dbpkg.signature_bytes = b64decode(repopkg.pgpsig.encode('utf-8')) if timestamp: - dbpkg.flag_date = None dbpkg.last_update = timestamp dbpkg.save() populate_files(dbpkg, repopkg, force=force) - dbpkg.packagedepend_set.all().delete() - if 'depends' in repopkg.__dict__: - for y in repopkg.depends: - # make sure we aren't adding self depends.. - # yes *sigh* i have seen them in pkgbuilds - dpname, dpvcmp = re.match(r"([a-z0-9._+-]+)(.*)", y).groups() - if dpname == repopkg.name: - logger.warning('Package %s has a depend on itself' % repopkg.name) - continue - dbpkg.packagedepend_set.create(depname=dpname, depvcmp=dpvcmp) - logger.debug('Added %s as dep for pkg %s' % (dpname, repopkg.name)) + dbpkg.depends.all().delete() + deps = [create_depend(dbpkg, y) for y in repopkg.depends] + deps += [create_depend(dbpkg, y, 'O') for y in repopkg.optdepends] + deps += [create_depend(dbpkg, y, 'M') for y in repopkg.makedepends] + deps += [create_depend(dbpkg, y, 'C') for y in repopkg.checkdepends] + Depend.objects.bulk_create(deps) - dbpkg.packagegroup_set.all().delete() - if 'groups' in repopkg.__dict__: - for y in repopkg.groups: - dbpkg.packagegroup_set.create(name=y) + dbpkg.conflicts.all().delete() + conflicts = [create_related(Conflict, dbpkg, y) for y in repopkg.conflicts] + Conflict.objects.bulk_create(conflicts) + + dbpkg.provides.all().delete() + provides = [create_related(Provision, dbpkg, y, equals_only=True) + for y in repopkg.provides] + Provision.objects.bulk_create(provides) + + dbpkg.replaces.all().delete() + replaces = [create_related(Replacement, dbpkg, y) for y in repopkg.replaces] + Replacement.objects.bulk_create(replaces) + + create_multivalued(dbpkg, repopkg, 'groups', 'groups') + create_multivalued(dbpkg, repopkg, 'licenses', 'license') + + +pkg_same_version = lambda pkg, dbpkg: pkg.ver == dbpkg.pkgver \ + and pkg.rel == dbpkg.pkgrel and pkg.epoch == dbpkg.epoch + + +def delete_pkg_files(dbpkg): + database = router.db_for_write(Package, instance=dbpkg) + cursor = connections[database].cursor() + cursor.execute('DELETE FROM package_files WHERE pkg_id = %s', [dbpkg.id]) + + +def batched_bulk_create(model, all_objects): + cutoff = 10000 + length = len(all_objects) + if length < cutoff: + return model.objects.bulk_create(all_objects) + + def chunks(): + offset = 0 + while offset < length: + yield all_objects[offset:offset + cutoff] + offset += cutoff + + for items in chunks(): + ret = model.objects.bulk_create(items) + + return ret def populate_files(dbpkg, repopkg, force=False): if not force: + if not pkg_same_version(repopkg, dbpkg): + logger.info("DB version (%s) didn't match repo version " + "(%s) for package %s, skipping file list addition", + dbpkg.full_version, repopkg.full_version, dbpkg.pkgname) + return if not dbpkg.files_last_update or not dbpkg.last_update: pass - elif dbpkg.files_last_update > dbpkg.last_update: + elif dbpkg.files_last_update >= dbpkg.last_update: return + # only delete files if we are reading a DB that contains them - if 'files' in repopkg.__dict__: - dbpkg.packagefile_set.all().delete() - logger.info("adding %d files for package %s" % (len(repopkg.files), dbpkg.pkgname)) - for x in repopkg.files: - dbpkg.packagefile_set.create(path=x) - dbpkg.files_last_update = datetime.now() + if repopkg.files: + files = repopkg.files_list + # we had files data, but it couldn't be parsed, so skip + if not files: + return + delete_pkg_files(dbpkg) + logger.info("adding %d files for package %s", + len(files), dbpkg.pkgname) + pkg_files = [] + # sort in normal alpha-order that pacman uses, rather than makepkg's + # default breadth-first, directory-first ordering + for f in sorted(files): + if '/' in f: + dirname, filename = f.rsplit('/', 1) + dirname += '/' + else: + dirname, filename = '', f + if filename == '': + filename = None + pkgfile = PackageFile(pkg=dbpkg, + is_directory=(filename is None), + directory=dirname, + filename=filename) + pkg_files.append(pkgfile) + batched_bulk_create(PackageFile, pkg_files) + dbpkg.files_last_update = now() dbpkg.save() -def db_update(archname, reponame, pkgs, options): - """ - Parses a list and updates the Arch dev database accordingly. - Arguments: - pkgs -- A list of Pkg objects. +def update_common(archname, reponame, pkgs, sanity_check=True): + # If isolation level is repeatable-read, we need to ensure each package + # update starts a new transaction and re-queries the database as + # necessary to guard against simultaneous updates. + with transaction.atomic(): + # force the transaction dirty, even though we will only do reads + transaction.set_dirty() + + repository = Repo.objects.get(name__iexact=reponame) + architecture = Arch.objects.get(name=archname) + # no-arg order_by() removes even the default ordering; we don't need it + dbpkgs = Package.objects.filter( + arch=architecture, repo=repository).order_by() + + logger.info("%d packages in current web DB", len(dbpkgs)) + logger.info("%d packages in new updating DB", len(pkgs)) + if len(dbpkgs): + dbpercent = 100.0 * len(pkgs) / len(dbpkgs) + else: + dbpercent = 0.0 + logger.info("DB package ratio: %.1f%%", dbpercent) + + # Fewer than 20 packages makes the percentage check unreliable, but it + # also means we expect the repo to fluctuate a lot. + msg = "Package database %s (%s) has %.1f%% the number of packages " \ + "the web database" + if not sanity_check: + pass + elif repository.testing or repository.staging: + pass + elif len(dbpkgs) == 0 and len(pkgs) == 0: + pass + elif len(dbpkgs) > 20 and dbpercent < 50.0: + logger.error(msg, reponame, archname, dbpercent) + raise Exception(msg % (reponame, archname, dbpercent)) + elif dbpercent < 75.0: + logger.warning(msg, reponame, archname, dbpercent) + + return dbpkgs + +def db_update(archname, reponame, pkgs, force=False): """ - logger.info('Updating Arch: %s' % archname) - force = options.get('force', False) - filesonly = options.get('filesonly', False) + Parses a list of packages and updates the packages database accordingly. + """ + logger.info('Updating %s (%s)', reponame, archname) + dbpkgs = update_common(archname, reponame, pkgs, True) repository = Repo.objects.get(name__iexact=reponame) - architecture = Arch.objects.get(name__iexact=archname) - dbpkgs = Package.objects.filter(arch=architecture, repo=repository) - # It makes sense to fully evaluate our DB query now because we will - # be using 99% of the objects in our "in both sets" loop. Force eval - # by calling list() on the QuerySet. - list(dbpkgs) + architecture = Arch.objects.get(name=archname) + # This makes our inner loop where we find packages by name *way* more # efficient by not having to go to the database for each package to # SELECT them by name. - dbdict = dict([(pkg.pkgname, pkg) for pkg in dbpkgs]) - - # go go set theory! - # thank you python for having a set class <3 - logger.debug("Creating sets") - dbset = set([pkg.pkgname for pkg in dbpkgs]) - syncset = set([pkg.name for pkg in pkgs]) - logger.info("%d packages in current web DB" % len(dbset)) - logger.info("%d packages in new updating db" % len(syncset)) - # packages in syncdb and not in database (add to database) - logger.debug("Set theory: Packages in syncdb not in database") - in_sync_not_db = syncset - dbset - logger.info("%d packages in sync not db" % len(in_sync_not_db)) + dbdict = {dbpkg.pkgname: dbpkg for dbpkg in dbpkgs} - # Try to catch those random orphaning issues that make Eric so unhappy. - if len(dbset) > 20: - dbpercent = 100.0 * len(syncset) / len(dbset) - else: - # we don't have 20 packages in this repo/arch, so this check could - # produce a lot of false positives (or a div by zero). fake it - dbpercent = 100.0 - logger.info("DB package ratio: %.1f%%" % dbpercent) - if dbpercent < 50.0 and not repository.testing: - logger.error(".db.tar.gz has %.1f%% the number of packages in the web database" % dbpercent) - raise Exception( - 'It looks like the syncdb is less than half the size of the web db. WTF?') - - if dbpercent < 75.0: - logger.warning(".db.tar.gz has %.1f%% the number of packages in the web database." % dbpercent) - - if not filesonly: - # packages in syncdb and not in database (add to database) - logger.debug("Set theory: Packages in syncdb not in database") - for p in [x for x in pkgs if x.name in in_sync_not_db]: - logger.info("Adding package %s", p.name) - pkg = Package(pkgname = p.name, arch = architecture, repo = repository) - populate_pkg(pkg, p, timestamp=datetime.now()) - - # packages in database and not in syncdb (remove from database) - logger.debug("Set theory: Packages in database not in syncdb") - in_db_not_sync = dbset - syncset - for p in in_db_not_sync: - logger.info("Removing package %s from database", p) - Package.objects.get( - pkgname=p, arch=architecture, repo=repository).delete() + dbset = set(dbdict.keys()) + syncset = {pkg.name for pkg in pkgs} + + in_sync_not_db = syncset - dbset + logger.info("%d packages in sync not db", len(in_sync_not_db)) + # packages in syncdb and not in database (add to database) + for pkg in (pkg for pkg in pkgs if pkg.name in in_sync_not_db): + logger.info("Adding package %s", pkg.name) + timestamp = now() + dbpkg = Package(pkgname=pkg.name, arch=architecture, repo=repository, + created=timestamp) + try: + with transaction.atomic(): + populate_pkg(dbpkg, pkg, timestamp=timestamp) + Update.objects.log_update(None, dbpkg) + except IntegrityError: + if architecture.agnostic: + logger.warning("Could not add package %s; " + "not fatal if another thread beat us to it.", + pkg.name) + else: + logger.exception("Could not add package %s", pkg.name) + + # packages in database and not in syncdb (remove from database) + for pkgname in (dbset - syncset): + logger.info("Removing package %s", pkgname) + dbpkg = dbdict[pkgname] + with transaction.atomic(): + Update.objects.log_update(dbpkg, None) + # no race condition here as long as simultaneous threads both + # issue deletes; second delete will be a no-op + delete_pkg_files(dbpkg) + dbpkg.delete() # packages in both database and in syncdb (update in database) - logger.debug("Set theory: Packages in database and syncdb") pkg_in_both = syncset & dbset - for p in [x for x in pkgs if x.name in pkg_in_both]: - logger.debug("Looking for package updates") - dbp = dbdict[p.name] + for pkg in (x for x in pkgs if x.name in pkg_in_both): + logger.debug("Checking package %s", pkg.name) + dbpkg = dbdict[pkg.name] timestamp = None # for a force, we don't want to update the timestamp. # for a non-force, we don't want to do anything at all. - if filesonly: - pass - elif '-'.join((p.ver, p.rel)) == '-'.join((dbp.pkgver, dbp.pkgrel)): - if not force: + if not force and pkg_same_version(pkg, dbpkg): + continue + elif not force: + timestamp = now() + + # The odd select_for_update song and dance here are to ensure + # simultaneous updates don't happen on a package, causing + # files/depends/all related items to be double-imported. + with transaction.atomic(): + dbpkg = Package.objects.select_for_update().get(id=dbpkg.id) + if not force and pkg_same_version(pkg, dbpkg): + logger.debug("Package %s was already updated", pkg.name) continue - else: - timestamp = datetime.now() - if filesonly: - logger.debug("Checking files for package %s in database", p.name) - populate_files(dbp, p) - else: - logger.info("Updating package %s in database", p.name) - populate_pkg(dbp, p, force=force, timestamp=timestamp) + logger.info("Updating package %s", pkg.name) + prevpkg = copy(dbpkg) + populate_pkg(dbpkg, pkg, force=force, timestamp=timestamp) + Update.objects.log_update(prevpkg, dbpkg) + + logger.info('Finished updating arch: %s', archname) + + +def filesonly_update(archname, reponame, pkgs, force=False): + """ + Parses a list of packages and updates the packages database accordingly. + """ + logger.info('Updating files for %s (%s)', reponame, archname) + dbpkgs = update_common(archname, reponame, pkgs, False) + dbdict = {dbpkg.pkgname: dbpkg for dbpkg in dbpkgs} + dbset = set(dbdict.keys()) + + for pkg in (pkg for pkg in pkgs if pkg.name in dbset): + dbpkg = dbdict[pkg.name] + + # The odd select_for_update song and dance here are to ensure + # simultaneous updates don't happen on a package, causing + # files to be double-imported. + with transaction.atomic(): + if not dbpkg.files_last_update or not dbpkg.last_update: + pass + elif not force and dbpkg.files_last_update >= dbpkg.last_update: + logger.debug("Files for %s are up to date", pkg.name) + continue + dbpkg = Package.objects.select_for_update().get(id=dbpkg.id) + logger.debug("Checking files for package %s", pkg.name) + populate_files(dbpkg, pkg, force=force) - logger.info('Finished updating Arch: %s' % archname) + logger.info('Finished updating arch: %s', archname) def parse_info(iofile): @@ -326,7 +489,7 @@ def parse_info(iofile): continue elif line.startswith('%') and line.endswith('%'): blockname = line[1:-1].lower() - logger.debug("Parsing package block %s", blockname) + logger.log(TRACE, "Parsing package block %s", blockname) store[blockname] = [] elif blockname: store[blockname].append(line) @@ -337,7 +500,7 @@ def parse_info(iofile): def parse_repo(repopath): """ - Parses an Arch repo db file, and returns a list of Pkg objects. + Parses an Arch repo db file, and returns a list of RepoPackage objects. Arguments: repopath -- The path of a repository db file. @@ -349,71 +512,95 @@ def parse_repo(repopath): logger.info("Reading repo tarfile %s", repopath) filename = os.path.split(repopath)[1] - m = re.match(r"^(.*)\.(db|files)\.tar\.(.*)$", filename) + m = re.match(r"^(.*)\.(db|files)\.tar(\..*)?$", filename) if m: reponame = m.group(1) else: logger.error("File does not have the proper extension") raise Exception("File does not have the proper extension") - repodb = tarfile.open(repopath,"r:gz") - ## assuming well formed tar, with dir first then files after - ## repo-add enforces this + repodb = tarfile.open(repopath, "r") logger.debug("Starting package parsing") - dbfiles = ('desc', 'depends', 'files') - pkgs = {} + newpkg = lambda: RepoPackage(reponame) + pkgs = defaultdict(newpkg) for tarinfo in repodb.getmembers(): - if tarinfo.isdir(): - continue - elif tarinfo.isreg(): + if tarinfo.isreg(): pkgid, fname = os.path.split(tarinfo.name) - if fname not in dbfiles: - continue - data_file = repodb.extractfile(tarinfo) - data_file = codecs.EncodedFile(data_file, 'utf-8') - try: - data = parse_info(data_file) - p = pkgs.setdefault(pkgid, Pkg(reponame)) - p.populate(data) - except UnicodeDecodeError, e: - logger.warn("Could not correctly decode %s, skipping file" % \ - tarinfo.name) - data_file.close() - - logger.debug("Done parsing file %s", fname) + if fname == 'files': + # don't parse yet for speed and memory consumption reasons + files_data = repodb.extractfile(tarinfo) + pkgs[pkgid].files = files_data.read() + del files_data + elif fname in ('desc', 'depends'): + data_file = repodb.extractfile(tarinfo) + data_file = io.TextIOWrapper(io.BytesIO(data_file.read()), + encoding='UTF-8') + try: + pkgs[pkgid].populate(parse_info(data_file)) + except UnicodeDecodeError: + logger.warn("Could not correctly decode %s, skipping file", + tarinfo.name) + data_file.close() + del data_file + + logger.debug("Done parsing file %s/%s", pkgid, fname) repodb.close() - logger.info("Finished repo parsing, %d total packages" % len(pkgs)) + logger.info("Finished repo parsing, %d total packages", len(pkgs)) return (reponame, pkgs.values()) -def validate_arch(arch): +def locate_arch(arch): "Check if arch is valid." - available_arches = [x.name for x in Arch.objects.all()] - return arch in available_arches + if isinstance(arch, Arch): + return arch + try: + return Arch.objects.get(name=arch) + except Arch.DoesNotExist: + raise CommandError( + 'Specified architecture %s is not currently known.' % arch) -@transaction.commit_on_success -def read_repo(primary_arch, file, options): + +def read_repo(primary_arch, repo_file, options): """ Parses repo.db.tar.gz file and returns exit status. """ - repo, packages = parse_repo(file) + # always returns an Arch object, regardless of what is passed in + primary_arch = locate_arch(primary_arch) + force = options.get('force', False) + filesonly = options.get('filesonly', False) + + repo, packages = parse_repo(repo_file) - # sort packages by arch -- to handle noarch stuff + # group packages by arch -- to handle noarch stuff packages_arches = {} - packages_arches['any'] = [] - packages_arches[primary_arch] = [] + for arch in Arch.objects.filter(agnostic=True): + packages_arches[arch.name] = [] + packages_arches[primary_arch.name] = [] for package in packages: - if package.arch in ('any', primary_arch): + if package.arch in packages_arches: packages_arches[package.arch].append(package) else: - # we don't include mis-arched packages - logger.warning("Package %s arch = %s" % ( - package.name,package.arch)) - logger.info('Starting database updates.') - for (arch, pkgs) in packages_arches.items(): - db_update(arch, repo, pkgs, options) - logger.info('Finished database updates.') + raise Exception( + "Package %s in database %s had wrong architecture %s" % ( + package.name, repo_file, package.arch)) + del packages + + database = router.db_for_write(Package) + connection = connections[database] + if connection.vendor == 'sqlite': + cursor = connection.cursor() + cursor.execute('PRAGMA synchronous = NORMAL') + + logger.info('Starting database updates for %s.', repo_file) + for arch in sorted(packages_arches.keys()): + if filesonly: + filesonly_update(arch, repo, packages_arches[arch], force) + else: + db_update(arch, repo, packages_arches[arch], force) + logger.info('Finished database updates for %s.', repo_file) + connection.commit() + connection.close() return 0 # vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/reporead_inotify.py b/devel/management/commands/reporead_inotify.py new file mode 100644 index 00000000..1422ae26 --- /dev/null +++ b/devel/management/commands/reporead_inotify.py @@ -0,0 +1,215 @@ +# -*- coding: utf-8 -*- +""" +reporead_inotify command + +Watches repo.files.tar.gz files for updates and parses them after a short delay +in order to catch all updates in a single bulk update. + +Usage: ./manage.py reporead_inotify [path_template] + +Where 'path_template' is an optional path_template for finding the +repo.files.tar.gz files. The form is '/srv/ftp/%(repo)s/os/%(arch)s/', which is +also the default template if none is specified. While 'repo' is not required to +be present in the path_template, note that 'arch' is so reporead can function +correctly. +""" + +import logging +import multiprocessing +import os +import pyinotify +import sys +import threading +import time + +from django.core.management.base import BaseCommand, CommandError +from django.db import connection, transaction + +from main.models import Arch, Repo +from .reporead import read_repo + +logging.basicConfig( + level=logging.WARNING, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(BaseCommand): + help = "Watch database files and run an update when necessary." + args = "[path_template]" + + def handle(self, path_template=None, **options): + v = int(options.get('verbosity', 0)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + if not path_template: + path_template = '/srv/ftp/%(repo)s/os/%(arch)s/' + self.path_template = path_template + + notifier = self.setup_notifier() + # this thread is done using the database; all future access is done in + # the spawned read_repo() processes, so close the otherwise completely + # idle connection. + connection.close() + + logger.info('Entering notifier loop') + notifier.loop() + + logger.info('Cancelling remaining threads...') + for thread in threading.enumerate(): + if hasattr(thread, 'cancel'): + thread.cancel() + + @transaction.atomic + def setup_notifier(self): + '''Set up and configure the inotify machinery and logic. + This takes the provided or default path_template and builds a list of + directories we need to watch for database updates. It then validates + and passes these on to the various pyinotify pieces as necessary and + finally builds and returns a notifier object.''' + transaction.commit_manually() + arches = Arch.objects.filter(agnostic=False) + repos = Repo.objects.all() + transaction.set_dirty() + arch_path_map = {arch: None for arch in arches} + all_paths = set() + total_paths = 0 + for arch in arches: + combos = ({ 'repo': repo.name.lower(), 'arch': arch.name } + for repo in repos) + # take a python format string and generate all unique combinations + # of directories from it; using set() ensures we filter it down + paths = {self.path_template % values for values in combos} + total_paths += len(paths) + all_paths |= paths + arch_path_map[arch] = paths + + logger.info('Watching %d total paths', total_paths) + logger.debug(all_paths) + + # sanity check- basically ensure every path we created from the + # template mapped to only one architecture + if total_paths != len(all_paths): + raise CommandError('path template did not uniquely ' + 'determine architecture for each file') + + # A proper atomic replacement of the database as done by rsync is type + # IN_MOVED_TO. repo-add/remove will finish with a IN_CLOSE_WRITE. + mask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_MOVED_TO + + manager = pyinotify.WatchManager() + for name in all_paths: + manager.add_watch(name, mask) + + handler = EventHandler(arch_paths=arch_path_map) + return pyinotify.Notifier(manager, handler) + + +class Database(object): + '''A object representing a pacman database on the filesystem. It stores + various bits of metadata and state representing the file path, when we last + updated, how long our delay is before performing the update, whether we are + updating now, etc.''' + def __init__(self, arch, path, delay=60.0, nice=3): + self.arch = arch + self.path = path + self.delay = delay + self.nice = nice + self.mtime = None + self.last_import = None + self.update_thread = None + self.updating = False + self.run_again = False + self.lock = threading.Lock() + + def _start_update_countdown(self): + self.update_thread = threading.Timer(self.delay, self.update) + logger.info('Starting %.1f second countdown to update %s', + self.delay, self.path) + self.update_thread.start() + + def queue_for_update(self, mtime): + logger.debug('Queueing database %s...', self.path) + with self.lock: + self.mtime = mtime + if self.updating: + # store the fact that we will need to run it again + self.run_again = True + return + if self.update_thread: + self.update_thread.cancel() + self.update_thread = None + self._start_update_countdown() + + def update(self): + logger.debug('Updating database %s...', self.path) + with self.lock: + self.last_import = time.time() + self.updating = True + + try: + # invoke reporead's primary method. we do this in a separate + # process for memory conservation purposes; these processes grow + # rather large so it is best to free up the memory ASAP. + def run(): + if self.nice != 0: + os.nice(self.nice) + read_repo(self.arch, self.path, {}) + + process = multiprocessing.Process(target=run) + process.start() + process.join() + finally: + logger.debug('Done updating database %s.', self.path) + with self.lock: + self.update_thread = None + self.updating = False + if self.run_again: + self.run_again = False + self._start_update_countdown() + + +class EventHandler(pyinotify.ProcessEvent): + '''Our main event handler which listens for database change events. Because + we are watching the whole directory, we filter down and only look at those + events dealing with files databases.''' + + def my_init(self, **kwargs): + self.databases = {} + self.arch_lookup = {} + + # we really want a single path to arch mapping, so massage the data + arch_paths = kwargs['arch_paths'] + for arch, paths in arch_paths.items(): + self.arch_lookup.update((path.rstrip('/'), arch) for path in paths) + + def process_default(self, event): + '''Primary event processing function which kicks off reporead timer + threads if a files database was updated.''' + name = event.name + if not name: + return + # screen to only the files we care about, skipping temp files + if name.endswith('.files.tar.gz') and not name.startswith('.'): + path = event.pathname + stat = os.stat(path) + database = self.databases.get(path, None) + if database is None: + arch = self.arch_lookup.get(event.path, None) + if arch is None: + logger.warning( + 'Could not determine arch for %s, skipping update', + path) + return + database = Database(arch, path) + self.databases[path] = database + database.queue_for_update(stat.st_mtime) + + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/update_types_permissions.py b/devel/management/commands/update_types_permissions.py new file mode 100644 index 00000000..ac8fcfa5 --- /dev/null +++ b/devel/management/commands/update_types_permissions.py @@ -0,0 +1,23 @@ +from django.core.management.base import BaseCommand +from django.apps import apps +from django.contrib.auth.management import create_permissions +from django.contrib.contenttypes.management import update_contenttypes + + +class Command(BaseCommand): + args = '<app app ...>' + help = 'reloads permissions for specified apps, or all apps if no args are specified' + + def handle(self, *args, **options): + if not args: + app_configs = apps.get_app_configs() + else: + app_configs = [] + for arg in args: + apps.append(apps.get_app_config(arg)) + + for app_config in app_configs: + update_contenttypes(app_config, options.get('verbosity', 2)) + create_permissions(app_config, options.get('verbosity', 22)) + +# vim: set ts=4 sw=4 et: diff --git a/devel/migrations/0001_initial.py b/devel/migrations/0001_initial.py new file mode 100644 index 00000000..3dd3582b --- /dev/null +++ b/devel/migrations/0001_initial.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import pytz + +from django.db import models, migrations +import django_countries.fields +import django.db.models.deletion +from django.conf import settings +import devel.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='DeveloperKey', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('key', devel.fields.PGPKeyField(unique=True, max_length=40, verbose_name=b'PGP key fingerprint')), + ('created', models.DateTimeField()), + ('expires', models.DateTimeField(null=True, blank=True)), + ('revoked', models.DateTimeField(null=True, blank=True)), + ('owner', models.ForeignKey(related_name=b'all_keys', to=settings.AUTH_USER_MODEL, help_text=b'The developer this key belongs to', null=True)), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='devel.DeveloperKey', null=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MasterKey', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pgp_key', devel.fields.PGPKeyField(help_text=b'consists of 40 hex digits; use `gpg --fingerprint`', max_length=40, verbose_name=b'PGP key fingerprint')), + ('created', models.DateField()), + ('revoked', models.DateField(null=True, blank=True)), + ('owner', models.ForeignKey(related_name=b'masterkey_owner', to=settings.AUTH_USER_MODEL, help_text=b'The developer holding this master key')), + ('revoker', models.ForeignKey(related_name=b'masterkey_revoker', to=settings.AUTH_USER_MODEL, help_text=b'The developer holding the revocation certificate')), + ], + options={ + 'ordering': ('created',), + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PGPSignature', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('signer', devel.fields.PGPKeyField(max_length=40, verbose_name=b'Signer key fingerprint', db_index=True)), + ('signee', devel.fields.PGPKeyField(max_length=40, verbose_name=b'Signee key fingerprint', db_index=True)), + ('created', models.DateField()), + ('expires', models.DateField(null=True, blank=True)), + ('revoked', models.DateField(null=True, blank=True)), + ], + options={ + 'ordering': ('signer', 'signee'), + 'get_latest_by': 'created', + 'verbose_name': 'PGP signature', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('notify', models.BooleanField(default=True, help_text=b"When enabled, send user 'flag out-of-date' notifications", verbose_name=b'Send notifications')), + ('time_zone', models.CharField(default=b'UTC', help_text=b'Used for developer clock page', max_length=100, choices=[(z, z) for z in pytz.common_timezones])), + ('alias', models.CharField(help_text=b'Required field', max_length=50)), + ('public_email', models.CharField(help_text=b'Required field', max_length=50)), + ('other_contact', models.CharField(max_length=100, null=True, blank=True)), + ('pgp_key', devel.fields.PGPKeyField(help_text=b'consists of 40 hex digits; use `gpg --fingerprint`', max_length=40, null=True, verbose_name=b'PGP key fingerprint', blank=True)), + ('website', models.CharField(max_length=200, null=True, blank=True)), + ('yob', models.IntegerField(null=True, verbose_name=b'Year of birth', blank=True)), + ('country', django_countries.fields.CountryField(blank=True, max_length=2)), + ('location', models.CharField(max_length=50, null=True, blank=True)), + ('languages', models.CharField(max_length=50, null=True, blank=True)), + ('interests', models.CharField(max_length=255, null=True, blank=True)), + ('occupation', models.CharField(max_length=50, null=True, blank=True)), + ('roles', models.CharField(max_length=255, null=True, blank=True)), + ('favorite_distros', models.CharField(max_length=255, null=True, blank=True)), + ('picture', models.FileField(default=b'devs/silhouette.png', help_text=b'Ideally 125px by 125px', upload_to=b'devs')), + ('latin_name', models.CharField(help_text=b'Latin-form name; used only for non-Latin full names', max_length=255, null=True, blank=True)), + ('last_modified', models.DateTimeField(editable=False)), + ('allowed_repos', models.ManyToManyField(to='main.Repo', blank=True)), + ('user', models.OneToOneField(related_name=b'userprofile', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'get_latest_by': 'last_modified', + 'verbose_name': 'additional profile data', + 'verbose_name_plural': 'additional profile data', + 'db_table': 'user_profiles', + }, + bases=(models.Model,), + ), + ] diff --git a/devel/migrations/0002_staffgroup.py b/devel/migrations/0002_staffgroup.py new file mode 100644 index 00000000..5679e6a3 --- /dev/null +++ b/devel/migrations/0002_staffgroup.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0001_initial'), + ('devel', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='StaffGroup', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=100)), + ('slug', models.SlugField(unique=True, max_length=100)), + ('sort_order', models.PositiveIntegerField()), + ('member_title', models.CharField(max_length=100)), + ('description', models.TextField(blank=True)), + ('group', models.OneToOneField(to='auth.Group')), + ], + options={ + 'ordering': ('sort_order',), + }, + bases=(models.Model,), + ), + ] diff --git a/__init__.py b/devel/migrations/__init__.py index e69de29b..e69de29b 100644 --- a/__init__.py +++ b/devel/migrations/__init__.py diff --git a/devel/models.py b/devel/models.py index e69de29b..b05800a5 100644 --- a/devel/models.py +++ b/devel/models.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +import pytz + +from django.core.urlresolvers import reverse +from django.db import models +from django.db.models.signals import pre_save +from django.contrib.auth.models import User, Group +from django_countries.fields import CountryField + +from .fields import PGPKeyField +from main.utils import make_choice, set_created_field + + +class UserProfile(models.Model): + notify = models.BooleanField( + "Send notifications", + default=True, + help_text="When enabled, send user 'flag out-of-date' notifications") + time_zone = models.CharField( + max_length=100, + choices=make_choice(pytz.common_timezones), + default="UTC", + help_text="Used for developer clock page") + alias = models.CharField( + max_length=50, + help_text="Required field") + public_email = models.CharField( + max_length=50, + help_text="Required field") + other_contact = models.CharField(max_length=100, null=True, blank=True) + pgp_key = PGPKeyField(max_length=40, null=True, blank=True, + verbose_name="PGP key fingerprint", + help_text="consists of 40 hex digits; use `gpg --fingerprint`") + website = models.CharField(max_length=200, null=True, blank=True) + yob = models.IntegerField("Year of birth", null=True, blank=True) + country = CountryField(blank=True) + location = models.CharField(max_length=50, null=True, blank=True) + languages = models.CharField(max_length=50, null=True, blank=True) + interests = models.CharField(max_length=255, null=True, blank=True) + occupation = models.CharField(max_length=50, null=True, blank=True) + roles = models.CharField(max_length=255, null=True, blank=True) + favorite_distros = models.CharField(max_length=255, null=True, blank=True) + picture = models.FileField(upload_to='devs', default='devs/silhouette.png', + help_text="Ideally 125px by 125px") + user = models.OneToOneField(User, related_name='userprofile') + allowed_repos = models.ManyToManyField('main.Repo', blank=True) + latin_name = models.CharField(max_length=255, null=True, blank=True, + help_text="Latin-form name; used only for non-Latin full names") + last_modified = models.DateTimeField(editable=False) + + class Meta: + db_table = 'user_profiles' + get_latest_by = 'last_modified' + verbose_name = 'additional profile data' + verbose_name_plural = 'additional profile data' + + def get_absolute_url(self): + user = self.user + group = StaffGroup.objects.filter(group=user.groups.all()).first() + if group: + return '%s#%s' % (group.get_absolute_url(), user.username) + return None + + +class StaffGroup(models.Model): + name = models.CharField(max_length=100) + slug = models.SlugField(max_length=100, unique=True) + group = models.OneToOneField(Group) + sort_order = models.PositiveIntegerField() + member_title = models.CharField(max_length=100) + description = models.TextField(blank=True) + + class Meta: + ordering = ('sort_order',) + + def __unicode__(self): + return self.name + + def get_absolute_url(self): + return reverse('people', args=[self.slug]) + + +class MasterKey(models.Model): + owner = models.ForeignKey(User, related_name='masterkey_owner', + help_text="The developer holding this master key") + revoker = models.ForeignKey(User, related_name='masterkey_revoker', + help_text="The developer holding the revocation certificate") + pgp_key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", + help_text="consists of 40 hex digits; use `gpg --fingerprint`") + created = models.DateField() + revoked = models.DateField(null=True, blank=True) + + class Meta: + ordering = ('created',) + get_latest_by = 'created' + + def __unicode__(self): + return u'%s, created %s' % ( + self.owner.get_full_name(), self.created) + + +class DeveloperKey(models.Model): + owner = models.ForeignKey(User, related_name='all_keys', null=True, + help_text="The developer this key belongs to") + key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", + unique=True) + created = models.DateTimeField() + expires = models.DateTimeField(null=True, blank=True) + revoked = models.DateTimeField(null=True, blank=True) + parent = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) + + def __unicode__(self): + return self.key + + +class PGPSignature(models.Model): + signer = PGPKeyField(max_length=40, verbose_name="Signer key fingerprint", + db_index=True) + signee = PGPKeyField(max_length=40, verbose_name="Signee key fingerprint", + db_index=True) + created = models.DateField() + expires = models.DateField(null=True, blank=True) + revoked = models.DateField(null=True, blank=True) + + class Meta: + ordering = ('signer', 'signee') + get_latest_by = 'created' + verbose_name = 'PGP signature' + + def __unicode__(self): + return u'%s → %s' % (self.signer, self.signee) + + +pre_save.connect(set_created_field, sender=UserProfile, + dispatch_uid="devel.models") + +# vim: set ts=4 sw=4 et: diff --git a/devel/reports.py b/devel/reports.py new file mode 100644 index 00000000..66fbd627 --- /dev/null +++ b/devel/reports.py @@ -0,0 +1,198 @@ +from datetime import timedelta +import pytz + +from django.db.models import F +from django.template.defaultfilters import filesizeformat +from django.utils.timezone import now + +from .models import DeveloperKey, UserProfile +from main.models import PackageFile +from packages.models import PackageRelation, Depend + +class DeveloperReport(object): + def __init__(self, slug, name, desc, packages_func, + names=None, attrs=None, personal=True): + self.slug = slug + self.name = name + self.description = desc + self.packages = packages_func + self.names = names + self.attrs = attrs + self.personal = personal + + +def old(packages, username): + cutoff = now() - timedelta(days=365 * 2) + return packages.filter( + build_date__lt=cutoff).order_by('build_date') + + +def outofdate(packages, username): + cutoff = now() - timedelta(days=30) + return packages.filter( + flag_date__lt=cutoff).order_by('flag_date') + + +def big(packages, username): + cutoff = 50 * 1024 * 1024 + packages = packages.filter( + compressed_size__gte=cutoff).order_by('-compressed_size') + # Format the compressed and installed sizes with MB/GB/etc suffixes + for package in packages: + package.compressed_size_pretty = filesizeformat( + package.compressed_size) + package.installed_size_pretty = filesizeformat( + package.installed_size) + return packages + + +def badcompression(packages, username): + cutoff = 0.90 * F('installed_size') + packages = packages.filter(compressed_size__gt=25*1024, + installed_size__gt=25*1024, + compressed_size__gte=cutoff).order_by('-compressed_size') + + # Format the compressed and installed sizes with MB/GB/etc suffixes + for package in packages: + package.compressed_size_pretty = filesizeformat( + package.compressed_size) + package.installed_size_pretty = filesizeformat( + package.installed_size) + ratio = package.compressed_size / float(package.installed_size) + package.ratio = '%.3f' % ratio + package.compress_type = package.filename.split('.')[-1] + + return packages + + +def uncompressed_man(packages, username): + # checking for all '.0'...'.9' + '.n' extensions + bad_files = PackageFile.objects.filter(is_directory=False, + directory__contains='/man/', + filename__regex=r'\.[0-9n]').exclude( + filename__endswith='.gz').exclude( + filename__endswith='.xz').exclude( + filename__endswith='.bz2').exclude( + filename__endswith='.html') + if username: + pkg_ids = set(packages.values_list('id', flat=True)) + bad_files = bad_files.filter(pkg__in=pkg_ids) + bad_files = bad_files.values_list( + 'pkg_id', flat=True).order_by().distinct() + return packages.filter(id__in=set(bad_files)) + + +def uncompressed_info(packages, username): + # we don't worry about looking for '*.info-1', etc., given that an + # uncompressed root page probably exists in the package anyway + bad_files = PackageFile.objects.filter(is_directory=False, + directory__endswith='/info/', filename__endswith='.info') + if username: + pkg_ids = set(packages.values_list('id', flat=True)) + bad_files = bad_files.filter(pkg__in=pkg_ids) + bad_files = bad_files.values_list( + 'pkg_id', flat=True).order_by().distinct() + return packages.filter(id__in=set(bad_files)) + + +def unneeded_orphans(packages, username): + owned = PackageRelation.objects.all().values('pkgbase') + required = Depend.objects.all().values('name') + # The two separate calls to exclude is required to do the right thing + return packages.exclude(pkgbase__in=owned).exclude( + pkgname__in=required) + + +def mismatched_signature(packages, username): + filtered = [] + packages = packages.select_related( + 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) + known_keys = DeveloperKey.objects.select_related( + 'owner').filter(owner__isnull=False) + known_keys = {dk.key: dk for dk in known_keys} + for package in packages: + bad = False + sig = package.signature + dev_key = known_keys.get(sig.key_id, None) + if dev_key: + package.sig_by = dev_key.owner + if dev_key.owner_id != package.packager_id: + bad = True + else: + package.sig_by = sig.key_id + bad = True + + if bad: + filtered.append(package) + return filtered + + +def signature_time(packages, username): + cutoff = timedelta(hours=24) + filtered = [] + packages = packages.select_related( + 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) + for package in packages: + sig = package.signature + sig_date = sig.creation_time.replace(tzinfo=pytz.utc) + package.sig_date = sig_date.date() + if sig_date > package.build_date + cutoff: + filtered.append(package) + + return filtered + + +REPORT_OLD = DeveloperReport('old', 'Old', + 'Packages last built more than two years ago', old) + +REPORT_OUTOFDATE = DeveloperReport('long-out-of-date', 'Long Out-of-date', + 'Packages marked out-of-date more than 30 days ago', outofdate) + +REPORT_BIG = DeveloperReport('big', 'Big', + 'Packages with compressed size > 50 MiB', big, + ['Compressed Size', 'Installed Size'], + ['compressed_size_pretty', 'installed_size_pretty']) + +REPORT_BADCOMPRESS = DeveloperReport('badcompression', 'Bad Compression', + 'Packages > 25 KiB with a compression ratio < 10%', badcompression, + ['Compressed Size', 'Installed Size', 'Ratio', 'Type'], + ['compressed_size_pretty', 'installed_size_pretty','ratio', 'compress_type']) + +REPORT_MAN = DeveloperReport('uncompressed-man', 'Uncompressed Manpages', + 'Packages with uncompressed manpages', uncompressed_man) + +REPORT_INFO = DeveloperReport('uncompressed-info', 'Uncompressed Info Pages', + 'Packages with uncompressed info pages', uncompressed_info) + +REPORT_ORPHANS = DeveloperReport('unneeded-orphans', 'Unneeded Orphans', + 'Packages that have no maintainer and are not required by any ' + + 'other package in any repository', unneeded_orphans, + personal=False) + +REPORT_SIGNATURE = DeveloperReport('mismatched-signature', + 'Mismatched Signatures', + 'Packages where the signing key is unknown or signer != packager', + mismatched_signature, + ['Signed By', 'Packager'], + ['sig_by', 'packager']) + +REPORT_SIG_TIME = DeveloperReport('signature-time', 'Signature Time', + 'Packages where the signature timestamp is more than 24 hours ' + + 'after the build timestamp', + signature_time, + ['Signature Date', 'Packager'], + ['sig_date', 'packager']) + + +def available_reports(): + return ( + REPORT_OLD, + REPORT_OUTOFDATE, + REPORT_BIG, + REPORT_BADCOMPRESS, + REPORT_MAN, + REPORT_INFO, + REPORT_ORPHANS, + REPORT_SIGNATURE, + REPORT_SIG_TIME, + ) diff --git a/devel/tests.py b/devel/tests.py index 682f3d92..5c736a30 100644 --- a/devel/tests.py +++ b/devel/tests.py @@ -1,8 +1,10 @@ +from django.contrib.auth.models import User from django.test import TestCase +from .utils import UserFinder +from .models import UserProfile class DevelTest(TestCase): - def test_index(self): response = self.client.get('/devel/') self.assertEqual(response.status_code, 302) @@ -10,13 +12,6 @@ class DevelTest(TestCase): self.assertEqual(response['location'], 'http://testserver/login/?next=/devel/') - def test_notify(self): - response = self.client.get('/devel/notify/') - self.assertEqual(response.status_code, 302) - self.assertEqual(response.has_header('Location'), True) - self.assertEqual(response['location'], - 'http://testserver/login/?next=/devel/notify/') - def test_profile(self): response = self.client.get('/devel/profile/') self.assertEqual(response.status_code, 302) @@ -33,7 +28,88 @@ class DevelTest(TestCase): def test_mirrors(self): response = self.client.get('/mirrors/') - self.assertEqual(response.status_code, 302) - self.assertEqual(response.has_header('Location'), True) - self.assertEqual(response['location'], - 'http://testserver/login/?next=/mirrors/') + self.assertEqual(response.status_code, 200) + +class FindUserTest(TestCase): + + def setUp(self): + self.finder = UserFinder() + + self.user1 = User.objects.create(username="joeuser", first_name="Joe", + last_name="User", email="user1@example.com") + self.user2 = User.objects.create(username="john", first_name="John", + last_name="", email="user2@example.com") + self.user3 = User.objects.create(username="bjones", first_name="Bob", + last_name="Jones", email="user3@example.com") + + for user in (self.user1, self.user2, self.user3): + email_addr = "%s@awesome.com" % user.username + UserProfile.objects.create(user=user, public_email=email_addr) + + self.user4 = User.objects.create(username="tim1", first_name="Tim", + last_name="One", email="tim@example.com") + self.user5 = User.objects.create(username="tim2", first_name="Tim", + last_name="Two", email="timtwo@example.com") + + def test_not_matching(self): + self.assertIsNone(self.finder.find(None)) + self.assertIsNone(self.finder.find("")) + self.assertIsNone(self.finder.find("Bogus")) + self.assertIsNone(self.finder.find("Bogus <invalid")) + self.assertIsNone(self.finder.find("Bogus User <bogus@example.com>")) + self.assertIsNone(self.finder.find("<bogus@example.com>")) + self.assertIsNone(self.finder.find("bogus@example.com")) + self.assertIsNone(self.finder.find("Unknown Packager")) + + def test_by_email(self): + self.assertEqual(self.user1, + self.finder.find("XXX YYY <user1@example.com>")) + self.assertEqual(self.user2, + self.finder.find("YYY ZZZ <user2@example.com>")) + + def test_by_profile_email(self): + self.assertEqual(self.user1, + self.finder.find("XXX <joeuser@awesome.com>")) + self.assertEqual(self.user2, + self.finder.find("YYY <john@awesome.com>")) + self.assertEqual(self.user3, + self.finder.find("ZZZ <bjones@awesome.com>")) + + def test_by_name(self): + self.assertEqual(self.user1, + self.finder.find("Joe User <joe@differentdomain.com>")) + self.assertEqual(self.user1, + self.finder.find("Joe User")) + self.assertEqual(self.user2, + self.finder.find("John <john@differentdomain.com>")) + self.assertEqual(self.user2, + self.finder.find("John")) + self.assertEqual(self.user3, + self.finder.find("Bob Jones <bjones AT Arch Linux DOT org>")) + + def test_by_invalid(self): + self.assertEqual(self.user1, + self.finder.find("Joe User <user1@example.com")) + self.assertEqual(self.user1, + self.finder.find("Joe 'nickname' User <user1@example.com")) + self.assertEqual(self.user1, + self.finder.find("Joe \"nickname\" User <user1@example.com")) + self.assertEqual(self.user1, + self.finder.find("Joe User <joe@differentdomain.com")) + + def test_cache(self): + # simply look two of them up, but then do it repeatedly + for _ in range(5): + self.assertEqual(self.user1, + self.finder.find("XXX YYY <user1@example.com>")) + self.assertEqual(self.user3, + self.finder.find("Bob Jones <bjones AT Arch Linux DOT org>")) + + def test_ambiguous(self): + self.assertEqual(self.user4, + self.finder.find("Tim One <tim@anotherdomain.com>")) + self.assertEqual(self.user5, + self.finder.find("Tim Two <tim@anotherdomain.com>")) + self.assertIsNone(self.finder.find("Tim <tim@anotherdomain.com>")) + +# vim: set ts=4 sw=4 et: diff --git a/devel/urls.py b/devel/urls.py new file mode 100644 index 00000000..472c6456 --- /dev/null +++ b/devel/urls.py @@ -0,0 +1,15 @@ +from django.conf.urls import patterns + +urlpatterns = patterns('devel.views', + (r'^admin_log/$','admin_log'), + (r'^admin_log/(?P<username>.*)/$','admin_log'), + (r'^clock/$', 'clock', {}, 'devel-clocks'), + (r'^$', 'index', {}, 'devel-index'), + (r'^stats/$', 'stats', {}, 'devel-stats'), + (r'^newuser/$', 'new_user_form'), + (r'^profile/$', 'change_profile'), + (r'^reports/(?P<report_name>.*)/(?P<username>.*)/$', 'report'), + (r'^reports/(?P<report_name>.*)/$', 'report'), +) + +# vim: set ts=4 sw=4 et: diff --git a/devel/utils.py b/devel/utils.py index abfdabe5..e745c7a9 100644 --- a/devel/utils.py +++ b/devel/utils.py @@ -1,12 +1,21 @@ +import re + +from django.conf import settings from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.db import connection +from django.db.models import Count, Q +from devel.models import UserProfile from main.utils import cache_function +from main.models import Package from packages.models import PackageRelation -@cache_function(300) +@cache_function(283) def get_annotated_maintainers(): - maintainers = User.objects.filter(is_active=True).order_by( + profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') + maintainers = User.objects.filter( + is_active=True, userprofile__id__in=profile_ids).order_by( 'first_name', 'last_name') # annotate the maintainers with # of maintained and flagged packages @@ -28,10 +37,159 @@ SELECT pr.user_id, COUNT(*), COUNT(p.flag_date) pkg_count[k] = total flag_count[k] = flagged + update_count = Package.objects.values_list('packager').order_by( + 'packager').annotate(Count('packager')) + update_count = dict(update_count) + for m in maintainers: m.package_count = pkg_count.get(m.id, 0) m.flagged_count = flag_count.get(m.id, 0) + m.updated_count = update_count.get(m.id, 0) + + # force non-QS context, otherwise pickling doesn't work + return list(maintainers) + + +def ignore_does_not_exist(func): + def new_func(*args, **kwargs): + try: + return func(*args, **kwargs) + except (ObjectDoesNotExist, MultipleObjectsReturned): + return None + return new_func + + +class UserFinder(object): + def __init__(self): + self.cache = {} + self.username_cache = {} + self.email_cache = {} + self.pgp_cache = {} + + @staticmethod + @ignore_does_not_exist + def user_email(name, email): + if email: + return User.objects.get(email=email) + return None + + @staticmethod + @ignore_does_not_exist + def username_email(name, email): + if email and '@' in email: + # split email addr at '@' symbol, ensure domain matches + # or is a subdomain of parabola.nu + username, domain = email.split('@', 1) + if re.match(settings.DOMAIN_RE, domain): + return User.objects.get(username=username) + return None + + @staticmethod + @ignore_does_not_exist + def profile_email(name, email): + if email: + return User.objects.get(userprofile__public_email=email) + return None + + @staticmethod + @ignore_does_not_exist + def user_name(name, email): + # yes, a bit odd but this is the easiest way since we can't always be + # sure how to split the name. Ensure every 'token' appears in at least + # one of the two name fields. + if not name: + return None + name_q = Q() + for token in name.split(): + # ignore quoted parts; e.g. nicknames in strings + if re.match(r'^[\'"].*[\'"]$', token): + continue + name_q &= (Q(first_name__icontains=token) | + Q(last_name__icontains=token)) + return User.objects.get(name_q) + + def find(self, userstring): + ''' + Attempt to find the corresponding User object for a standard + packager string, e.g. something like + 'A. U. Thor <author@example.com>'. + We start by searching for a matching email address; we then move onto + matching by first/last name. If we cannot find a user, then return None. + ''' + if not userstring: + return None + if userstring in self.cache: + return self.cache[userstring] + + name = email = None + + matches = re.match(r'^([^<]+)? ?<([^>]*)>?', userstring) + if not matches: + name = userstring.strip() + else: + name = matches.group(1) + email = matches.group(2) + + user = None + find_methods = (self.user_email, self.profile_email, + self.username_email, self.user_name) + for matcher in find_methods: + user = matcher(name, email) + if user is not None: + break + + self.cache[userstring] = user + self.email_cache[email] = user + return user + + def find_by_username(self, username): + if not username: + return None + if username in self.username_cache: + return self.username_cache[username] + + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + user = None + + self.username_cache[username] = user + return user + + def find_by_email(self, email): + if not email: + return None + if email in self.email_cache: + return self.email_cache[email] + + user = self.user_email(None, email) + if user is None: + user = self.profile_email(None, email) + if user is None: + user = self.username_email(None, email) + + self.email_cache[email] = user + return user + + def find_by_pgp_key(self, pgp_key): + if not pgp_key: + return None + if pgp_key in self.pgp_cache: + return self.pgp_cache[pgp_key] + + try: + user = User.objects.get( + userprofile__pgp_key__endswith=pgp_key) + except User.DoesNotExist: + user = None + + self.pgp_cache[pgp_key] = user + return user - return maintainers + def clear_cache(self): + self.cache = {} + self.username_cache = {} + self.email_cache = {} + self.pgp_cache = {} # vim: set ts=4 sw=4 et: diff --git a/devel/views.py b/devel/views.py index 577a00c4..66f6a965 100644 --- a/devel/views.py +++ b/devel/views.py @@ -1,114 +1,230 @@ -from django import forms +from datetime import timedelta +import operator +import time + from django.http import HttpResponseRedirect -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import \ + login_required, permission_required, user_passes_test +from django.contrib import admin +from django.contrib.admin.models import LogEntry, ADDITION from django.contrib.auth.models import User -from django.contrib.sites.models import Site -from django.core.mail import send_mail +from django.contrib.contenttypes.models import ContentType +from django.db import transaction +from django.db.models import Count, Max +from django.http import Http404 +from django.shortcuts import get_object_or_404, render from django.views.decorators.cache import never_cache -from django.views.generic.simple import direct_to_template +from django.utils.encoding import force_unicode +from django.utils.http import http_date +from django.utils.timezone import now -from main.models import Package, Todolist, TodolistPkg +from .forms import ProfileForm, UserProfileForm, NewUserForm +from .models import UserProfile +from .reports import available_reports +from main.models import Package from main.models import Arch, Repo -from main.models import UserProfile -from packages.models import PackageRelation +from news.models import News +from packages.models import PackageRelation, Signoff, FlagRequest +from packages.utils import get_signoff_groups +from todolists.models import TodolistPackage +from todolists.utils import get_annotated_todolists from .utils import get_annotated_maintainers -import random -from string import ascii_letters, digits @login_required -@never_cache def index(request): - '''the Developer dashboard''' - inner_q = PackageRelation.objects.filter(user=request.user).values('pkgbase') - flagged = Package.objects.select_related('arch', 'repo').filter(flag_date__isnull=False) - flagged = flagged.filter(pkgbase__in=inner_q).order_by('pkgname') + """The developer dashboard.""" + if request.user.is_authenticated(): + inner_q = PackageRelation.objects.filter(user=request.user) + else: + inner_q = PackageRelation.objects.none() + inner_q = inner_q.values('pkgbase') + + flagged = Package.objects.normal().filter( + flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') + + todopkgs = TodolistPackage.objects.select_related( + 'todolist', 'pkg', 'arch', 'repo').exclude( + status=TodolistPackage.COMPLETE).filter(removed__isnull=True) + todopkgs = todopkgs.filter(pkgbase__in=inner_q).order_by( + 'todolist__name', 'pkgname') + + todolists = get_annotated_todolists(incomplete_only=True) + + signoffs = sorted(get_signoff_groups(user=request.user), + key=operator.attrgetter('pkgbase')) + + page_dict = { + 'todos': todolists, + 'flagged': flagged, + 'todopkgs': todopkgs, + 'signoffs': signoffs, + 'reports': available_reports(), + } - todopkgs = TodolistPkg.objects.select_related( - 'pkg', 'pkg__arch', 'pkg__repo').filter(complete=False) - todopkgs = todopkgs.filter(pkg__pkgbase__in=inner_q).order_by( - 'list__name', 'pkg__pkgname') + return render(request, 'devel/index.html', page_dict) + + +@login_required +def stats(request): + """The second half of the dev dashboard.""" + arches = Arch.objects.all().annotate( + total_ct=Count('packages'), flagged_ct=Count('packages__flag_date')) + repos = Repo.objects.all().annotate( + total_ct=Count('packages'), flagged_ct=Count('packages__flag_date')) + # the join is huge unless we do this separately, so merge the result here + repo_maintainers = dict(Repo.objects.order_by().filter( + userprofile__user__is_active=True).values_list('id').annotate( + Count('userprofile'))) + for repo in repos: + repo.maintainer_ct = repo_maintainers.get(repo.id, 0) maintainers = get_annotated_maintainers() + maintained = PackageRelation.objects.filter( + type=PackageRelation.MAINTAINER).values('pkgbase') + total_orphans = Package.objects.exclude(pkgbase__in=maintained).count() + total_flagged_orphans = Package.objects.filter( + flag_date__isnull=False).exclude(pkgbase__in=maintained).count() + total_updated = Package.objects.filter(packager__isnull=True).count() + orphan = { + 'package_count': total_orphans, + 'flagged_count': total_flagged_orphans, + 'updated_count': total_updated, + } + page_dict = { - 'todos': Todolist.objects.incomplete().order_by('-date_added'), - 'repos': Repo.objects.all(), - 'arches': Arch.objects.all(), + 'arches': arches, + 'repos': repos, 'maintainers': maintainers, - 'flagged' : flagged, - 'todopkgs' : todopkgs, - } + 'orphan': orphan, + } + + return render(request, 'devel/stats.html', page_dict) - return direct_to_template(request, 'devel/index.html', page_dict) @login_required -def change_notify(request): - maint = User.objects.get(username=request.user.username) - notify = request.POST.get('notify', 'no') - prof = maint.get_profile() - prof.notify = (notify == 'yes') - prof.save() - return HttpResponseRedirect('/devel/') - -class ProfileForm(forms.Form): - email = forms.EmailField(label='E-mail Address') - passwd1 = forms.CharField(label='New Password', required=False, - widget=forms.PasswordInput) - passwd2 = forms.CharField(label='Confirm Password', required=False, - widget=forms.PasswordInput) - - def clean(self): - if self.cleaned_data['passwd1'] != self.cleaned_data['passwd2']: - raise forms.ValidationError('Passwords do not match.') - return self.cleaned_data +def clock(request): + devs = User.objects.filter(is_active=True).order_by( + 'first_name', 'last_name').select_related('userprofile') + + latest_news = dict(News.objects.filter( + author__is_active=True).values_list('author').order_by( + ).annotate(last_post=Max('postdate'))) + latest_package = dict(Package.objects.filter( + packager__is_active=True).values_list('packager').order_by( + ).annotate(last_build=Max('build_date'))) + latest_signoff = dict(Signoff.objects.filter( + user__is_active=True).values_list('user').order_by( + ).annotate(last_signoff=Max('created'))) + # The extra() bit ensures we can use our 'user_id IS NOT NULL' index + latest_flagreq = dict(FlagRequest.objects.filter( + user__is_active=True).extra( + where=['user_id IS NOT NULL']).values_list('user_id').order_by( + ).annotate(last_flagrequest=Max('created'))) + latest_log = dict(LogEntry.objects.filter( + user__is_active=True).values_list('user').order_by( + ).annotate(last_log=Max('action_time'))) + + for dev in devs: + dates = [ + latest_news.get(dev.id, None), + latest_package.get(dev.id, None), + latest_signoff.get(dev.id, None), + latest_flagreq.get(dev.id, None), + latest_log.get(dev.id, None), + dev.last_login, + ] + dates = [d for d in dates if d is not None] + if dates: + dev.last_action = max(dates) + else: + dev.last_action = None + + current_time = now() + page_dict = { + 'developers': devs, + 'utc_now': current_time, + } + + response = render(request, 'devel/clock.html', page_dict) + if not response.has_header('Expires'): + expire_time = current_time.replace(second=0, microsecond=0) + expire_time += timedelta(minutes=1) + expire_time = time.mktime(expire_time.timetuple()) + response['Expires'] = http_date(expire_time) + return response + @login_required @never_cache def change_profile(request): + profile, _ = UserProfile.objects.get_or_create(user=request.user) if request.POST: form = ProfileForm(request.POST) - if form.is_valid(): + profile_form = UserProfileForm(request.POST, request.FILES, + instance=profile) + if form.is_valid() and profile_form.is_valid(): request.user.email = form.cleaned_data['email'] if form.cleaned_data['passwd1']: request.user.set_password(form.cleaned_data['passwd1']) - request.user.save() + with transaction.atomic(): + request.user.save() + profile_form.save() return HttpResponseRedirect('/devel/') else: form = ProfileForm(initial={'email': request.user.email}) - return direct_to_template(request, 'devel/profile.html', {'form': form}) - -class NewUserForm(forms.ModelForm): - class Meta: - model = UserProfile - exclude = ('picture', 'user') - username = forms.CharField(max_length=30) - email = forms.EmailField() - first_name = forms.CharField(required=False) - last_name = forms.CharField(required=False) - - def save(self): - profile = forms.ModelForm.save(self, False) - pwletters = ascii_letters + digits - pw = ''.join([random.choice(pwletters) for i in xrange(8)]) - user = User.objects.create_user(username=self.cleaned_data['username'], - email=self.cleaned_data['email'], password=pw) - user.first_name = self.cleaned_data['first_name'] - user.last_name = self.cleaned_data['last_name'] - user.save() - profile.user = user - profile.save() - domain = Site.objects.get_current().domain - - send_mail("Your new archweb account", - """You can now log into: -https://%s/login/ -with these login details: -Username: %s -Password: %s""" % (domain, user.username, pw), - 'Arch Website Notification <nobody@archlinux.org>', - [user.email], - fail_silently=False) + profile_form = UserProfileForm(instance=profile) + return render(request, 'devel/profile.html', + {'form': form, 'profile_form': profile_form}) + + +@login_required +def report(request, report_name, username=None): + available = {report.slug: report for report in available_reports()} + report = available.get(report_name, None) + if report is None: + raise Http404 + + packages = Package.objects.normal() + user = None + if username: + user = get_object_or_404(User, username=username, is_active=True) + maintained = PackageRelation.objects.filter(user=user, + type=PackageRelation.MAINTAINER).values('pkgbase') + packages = packages.filter(pkgbase__in=maintained) + + maints = User.objects.filter(id__in=PackageRelation.objects.filter( + type=PackageRelation.MAINTAINER).values('user')) + + packages = report.packages(packages, username) + arches = {pkg.arch for pkg in packages} + repos = {pkg.repo for pkg in packages} + context = { + 'all_maintainers': maints, + 'title': report.description, + 'report': report, + 'maintainer': user, + 'packages': packages, + 'arches': sorted(arches), + 'repos': sorted(repos), + 'column_names': report.names, + 'column_attrs': report.attrs, + } + return render(request, 'devel/packages.html', context) + + +def log_addition(request, obj): + """Cribbed from ModelAdmin.log_addition.""" + LogEntry.objects.log_action( + user_id = request.user.pk, + content_type_id = ContentType.objects.get_for_model(obj).pk, + object_id = obj.pk, + object_repr = force_unicode(obj), + action_flag = ADDITION, + change_message = "Added via Create New User form." + ) + @permission_required('auth.add_user') @never_cache @@ -116,7 +232,9 @@ def new_user_form(request): if request.POST: form = NewUserForm(request.POST) if form.is_valid(): - form.save() + with transaction.atomic(): + form.save() + log_addition(request, form.instance.user) return HttpResponseRedirect('/admin/auth/user/%d/' % \ form.instance.user.id) else: @@ -131,6 +249,19 @@ def new_user_form(request): 'title': 'Create User', 'submit_text': 'Create User' } - return direct_to_template(request, 'general_form.html', context) + return render(request, 'general_form.html', context) + + +@user_passes_test(lambda u: u.is_superuser) +def admin_log(request, username=None): + user = None + if username: + user = get_object_or_404(User, username=username) + context = { + 'title': "Admin Action Log", + 'log_user': user, + } + context.update(admin.site.each_context()) + return render(request, 'devel/admin_log.html', context) # vim: set ts=4 sw=4 et: @@ -1,40 +1,69 @@ -import datetime +from datetime import datetime, time +from pytz import utc +from django.conf import settings +from django.contrib.sites.models import Site from django.contrib.syndication.views import Feed +from django.db import connection from django.db.models import Q -from django.utils.hashcompat import md5_constructor +from django.utils.feedgenerator import Rss201rev2Feed from django.views.decorators.http import condition from main.models import Arch, Repo, Package from news.models import News +from releng.models import Release + + +class BatchWritesWrapper(object): + def __init__(self, outfile): + self.outfile = outfile + self.buf = [] + + def write(self, s): + buf = self.buf + buf.append(s) + if len(buf) >= 40: + self.outfile.write(''.join(buf)) + self.buf = [] + + def flush(self): + self.outfile.write(''.join(self.buf)) + self.outfile.flush() + + +class FasterRssFeed(Rss201rev2Feed): + def write(self, outfile, encoding): + ''' + Batch the underlying 'write' calls on the outfile because Python's + default saxutils XmlGenerator is a POS that insists on unbuffered + write/flush calls. This sucks when it is making 1-byte calls to write + '>' closing tags and over 1600 write calls in our package feed. + ''' + wrapper = BatchWritesWrapper(outfile) + super(FasterRssFeed, self).write(wrapper, encoding) + wrapper.flush() -def package_etag(request, *args, **kwargs): - latest = Package.objects.latest('last_update') - if latest: - return md5_constructor( - str(kwargs) + str(latest.last_update)).hexdigest() - return None def package_last_modified(request, *args, **kwargs): - # we could break this down based on the request url, but it would probably - # cost us more in query time to do so. - latest = Package.objects.latest('last_update') - if latest: - return latest.last_update - return None + cursor = connection.cursor() + cursor.execute("SELECT MAX(last_update) FROM packages") + return cursor.fetchone()[0] + class PackageFeed(Feed): + feed_type = FasterRssFeed + link = '/packages/' - title_template = 'feeds/packages_title.html' - description_template = 'feeds/packages_description.html' def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=package_etag, last_modified_func=package_last_modified) + wrapper = condition(last_modified_func=package_last_modified) return wrapper(super(PackageFeed, self).__call__)(request, *args, **kwargs) + __name__ = 'package_feed' + def get_object(self, request, arch='', repo=''): obj = dict() - qs = Package.objects.select_related('arch', 'repo').order_by('-last_update') + qs = Package.objects.normal().order_by('-last_update') if arch != '': # feed for a single arch, also include 'any' packages everywhere @@ -43,22 +72,26 @@ class PackageFeed(Feed): obj['arch'] = a if repo != '': # feed for a single arch AND repo - r = Repo.objects.get(name=repo) + r = Repo.objects.get(name__iexact=repo) qs = qs.filter(repo=r) obj['repo'] = r + else: + qs = qs.filter(repo__staging=False) obj['qs'] = qs[:50] return obj def title(self, obj): - s = 'Arch Linux: Recent package updates' - if 'repo' in obj: + s = settings.BRANDING_DISTRONAME+': Recent package updates' + if 'repo' in obj and 'arch' in obj: s += ' (%s [%s])' % (obj['arch'].name, obj['repo'].name.lower()) + elif 'repo' in obj: + s += ' [%s]' % (obj['repo'].name.lower()) elif 'arch' in obj: s += ' (%s)' % (obj['arch'].name) return s def description(self, obj): - s = 'Recently updated packages in the Arch Linux package repositories' + s = 'Recently updated packages in the '+settings.BRANDING_DISTRONAME+' package repositories' if 'arch' in obj: s += ' for the \'%s\' architecture' % obj['arch'].name.lower() if not obj['arch'].agnostic: @@ -68,47 +101,122 @@ class PackageFeed(Feed): s += '.' return s + subtitle = description + def items(self, obj): return obj['qs'] + item_guid_is_permalink = False + + def item_guid(self, item): + # http://diveintomark.org/archives/2004/05/28/howto-atom-id + date = item.last_update + return 'tag:%s,%s:%s%s' % (Site.objects.get_current().domain, + date.strftime('%Y-%m-%d'), item.get_absolute_url(), + date.strftime('%Y%m%d%H%M')) + def item_pubdate(self, item): return item.last_update + def item_title(self, item): + return '%s %s %s' % (item.pkgname, item.full_version, item.arch.name) + + def item_description(self, item): + return item.pkgdesc + def item_categories(self, item): return (item.repo.name, item.arch.name) -def news_etag(request, *args, **kwargs): - latest = News.objects.latest('last_modified') - if latest: - return md5_constructor(str(latest.last_modified)).hexdigest() - return None +def news_last_modified(request, *args, **kwargs): + cursor = connection.cursor() + cursor.execute("SELECT MAX(last_modified) FROM news") + return cursor.fetchone()[0] -def news_last_modified(request): - latest = News.objects.latest('last_modified') - if latest: - return latest.last_modified - return None class NewsFeed(Feed): - title = 'Arch Linux: Recent news updates' + feed_type = FasterRssFeed + + title = settings.BRANDING_DISTRONAME+': Recent news updates' link = '/news/' - description = 'The latest and greatest news from the Arch Linux distribution.' - title_template = 'feeds/news_title.html' - description_template = 'feeds/news_description.html' + description = 'The latest and greatest news from the '+settings.BRANDING_DISTRONAME+' distribution.' + subtitle = description def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=news_etag, last_modified_func=news_last_modified) + wrapper = condition(last_modified_func=news_last_modified) return wrapper(super(NewsFeed, self).__call__)(request, *args, **kwargs) + __name__ = 'news_feed' + def items(self): - return News.objects.select_related('author').order_by('-postdate', '-id')[:10] + return News.objects.select_related('author').order_by( + '-postdate', '-id')[:10] + + item_guid_is_permalink = False + + def item_guid(self, item): + return item.guid def item_pubdate(self, item): - d = item.postdate - return datetime.datetime(d.year, d.month, d.day) + return item.postdate + + def item_updateddate(self, item): + return item.last_modified def item_author_name(self, item): return item.author.get_full_name() + def item_title(self, item): + return item.title + + def item_description(self, item): + return item.html() + + +class ReleaseFeed(Feed): + feed_type = FasterRssFeed + + title = settings.BRANDING_DISTRONAME+': Releases' + link = '/download/' + description = 'Release ISOs' + subtitle = description + + __name__ = 'release_feed' + + def items(self): + return Release.objects.filter(available=True)[:10] + + def item_title(self, item): + return item.version + + def item_description(self, item): + return item.info_html() + + def item_pubdate(self, item): + return datetime.combine(item.release_date, time()).replace(tzinfo=utc) + + def item_updateddate(self, item): + return item.last_modified + + item_guid_is_permalink = False + + def item_guid(self, item): + # http://diveintomark.org/archives/2004/05/28/howto-atom-id + date = item.release_date + return 'tag:%s,%s:%s' % (Site.objects.get_current().domain, + date.strftime('%Y-%m-%d'), item.get_absolute_url()) + + def item_enclosure_url(self, item): + domain = Site.objects.get_current().domain + proto = 'https' + return "%s://%s/%s.torrent" % (proto, domain, item.iso_url()) + + def item_enclosure_length(self, item): + if item.torrent_data: + torrent = item.torrent() + return torrent['file_length'] or "" + return "" + + item_enclosure_mime_type = 'application/x-bittorrent' + # vim: set ts=4 sw=4 et: diff --git a/local_settings.py.example b/local_settings.py.example index 9af4ebc8..f5d23c89 100644 --- a/local_settings.py.example +++ b/local_settings.py.example @@ -1,42 +1,74 @@ -### Django settings for archlinux project. - ## Debug settings -DEBUG = False +DEBUG = False # If you are running without another HTTP server, must be true +TEMPLATE_DEBUG = False +DEBUG_TOOLBAR = False # Must install package django-debug-toolbar to use + +## For django debug toolbar +INTERNAL_IPS = ('127.0.0.1',) ## Notification admins ADMINS = ( # ('Joe Admin', 'joeadmin@example.com'), ) -## Sqlite Database settings -#DATABASE_ENGINE = 'sqlite3' -#DATABASE_NAME = 'archweb.db' +## PostgreSQL Database settings +#DATABASES = { +# 'default': { +# 'ENGINE' : 'django.db.backends.postgresql_psycopg2', +# 'NAME' : 'parabola', +# 'USER' : 'parabola', +# 'PASSWORD': 'parabola', +# 'HOST' : '', +# 'PORT' : '', +# }, +#} ## MySQL Database settings -#DATABASE_ENGINE = 'mysql' -#DATABASE_NAME = 'archlinux' -#DATABASE_USER = 'archlinux' -#DATABASE_PASSWORD = 'archlinux' -#DATABASE_HOST = '' -#DATABASE_PORT = '' +#DATABASES = { +# 'default': { +# 'ENGINE' : 'django.db.backends.mysql', +# 'NAME' : 'parabola', +# 'USER' : 'parabola', +# 'PASSWORD': 'parabola', +# 'HOST' : '', +# 'PORT' : '', +# # InnoDB WILL NOT work +# 'OPTIONS' : {'init_command': 'SET storage_engine=MyISAM'}, +# }, +#} -## Define cache middleware settings -CACHE_BACKEND = 'memcached://127.0.0.1:11211' -CACHE_MIDDLEWARE_SECONDS = 900 -CACHE_MIDDLEWARE_KEY_PREFIX = 'arch' +## Sqlite Database settings +DATABASES = { + 'default': { + 'ENGINE' : 'django.db.backends.sqlite3', + 'NAME' : 'database.db', + }, +} -## location for saving dev pictures -MEDIA_ROOT = '/var/www/archlinux/htdocs/img/' +## Define cache settings +CACHES = { + 'default': { + 'BACKEND' : 'django.core.cache.backends.dummy.DummyCache', + #'BACKEND' : 'django.core.cache.backends.memcached.MemcachedCache', + #'LOCATION': '127.0.0.1:11211', + } +} -## web url for serving image files -MEDIA_URL = 'http://www.archlinux.org/img/' +## Use secure session cookies? Make this true if you want all +## logged-in actions to take place over HTTPS only. If developing +## locally, you will want to use False. +SESSION_COOKIE_SECURE = False + +## location for saving dev pictures (the 'devs' folder should be inside of this) +MEDIA_ROOT = '/srv/http/web-uploads' + +## web url for serving image files (the 'devs' folder should be inside of this) +MEDIA_URL = '/img/' ## Make this unique, and don't share it with anybody. SECRET_KEY = '00000000000000000000000000000000000000000000000' -#dummy cache -if DEBUG: - CACHE_BACKEND = 'dummy:///' +## CDN settings +CDN_ENABLED = False # vim: set ts=4 sw=4 et: - diff --git a/main/admin.py b/main/admin.py index 5dffb431..ec2b5bc8 100644 --- a/main/admin.py +++ b/main/admin.py @@ -1,37 +1,35 @@ from django.contrib import admin -from django.contrib.auth.models import User -from django.contrib.auth.admin import UserAdmin -from main.models import Arch, Donor, Package, Repo, UserProfile +from main.models import Arch, Donor, Package, Repo + class DonorAdmin(admin.ModelAdmin): + list_display = ('name', 'visible', 'created') + list_filter = ('visible', 'created') search_fields = ('name',) + exclude = ('created',) + class ArchAdmin(admin.ModelAdmin): - list_display = ('name', 'agnostic') + list_display = ('name', 'agnostic', 'required_signoffs') list_filter = ('agnostic',) search_fields = ('name',) + class RepoAdmin(admin.ModelAdmin): - list_display = ('name', 'testing', 'bugs_project', 'svn_root') - list_filter = ('testing',) + list_display = ('name', 'testing', 'staging', 'bugs_project', + 'bugs_category', 'svn_root') + list_filter = ('testing', 'staging') search_fields = ('name',) + class PackageAdmin(admin.ModelAdmin): - list_display = ('pkgname', 'repo', 'arch', 'last_update') + list_display = ('pkgname', 'full_version', 'repo', 'arch', 'packager', + 'last_update', 'build_date') list_filter = ('repo', 'arch') - search_fields = ('pkgname',) - -admin.site.unregister(User) -class UserProfileInline(admin.StackedInline): - model = UserProfile - -class UserProfileAdmin(UserAdmin): - inlines = [UserProfileInline] - list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active') - list_filter = ('is_staff', 'is_superuser', 'is_active') + search_fields = ('pkgname', 'pkgbase', 'pkgdesc') + date_hierarchy = 'build_date' -admin.site.register(User, UserProfileAdmin) admin.site.register(Donor, DonorAdmin) admin.site.register(Package, PackageAdmin) diff --git a/main/context_processors.py b/main/context_processors.py index a60d4e63..96a45dcf 100644 --- a/main/context_processors.py +++ b/main/context_processors.py @@ -1,4 +1,19 @@ def secure(request): return {'secure': request.is_secure()} +def branding(request): + from django.conf import settings + return { + 'BUGTRACKER_URL': settings.BUGTRACKER_URL, + 'MAILMAN_BASE_URL': settings.MAILMAN_BASE_URL, + 'PROJECTS_URL': settings.PROJECTS_URL, + + 'BRANDING_APPNAME': settings.BRANDING_APPNAME, + 'BRANDING_DISTRONAME': settings.BRANDING_DISTRONAME, + 'BRANDING_SHORTNAME': settings.BRANDING_SHORTNAME, + 'BRANDING_WIKINAME': settings.BRANDING_WIKINAME, + 'BRANDING_EMAIL': settings.BRANDING_EMAIL, + 'BRANDING_OSEARCH_TAGS': settings.BRANDING_OSEARCH_TAGS, + } + # vim: set ts=4 sw=4 et: diff --git a/main/fields.py b/main/fields.py new file mode 100644 index 00000000..53494772 --- /dev/null +++ b/main/fields.py @@ -0,0 +1,13 @@ +from django.db import models + + +class PositiveBigIntegerField(models.BigIntegerField): + def get_internal_type(self): + return "BigIntegerField" + + def formfield(self, **kwargs): + defaults = { 'min_value': 0 } + defaults.update(kwargs) + return super(PositiveBigIntegerField, self).formfield(**defaults) + +# vim: set ts=4 sw=4 et: diff --git a/main/fixtures/arches.json b/main/fixtures/arches.json index 6334c2d3..1ece16c9 100644 --- a/main/fixtures/arches.json +++ b/main/fixtures/arches.json @@ -1,26 +1,29 @@ [ - { - "pk": 1, - "model": "main.arch", - "fields": { - "agnostic": true, - "name": "any" - } - }, - { - "pk": 2, - "model": "main.arch", - "fields": { - "agnostic": false, - "name": "i686" - } - }, - { - "pk": 3, - "model": "main.arch", - "fields": { - "agnostic": false, - "name": "x86_64" - } +{ + "pk": 1, + "model": "main.arch", + "fields": { + "agnostic": true, + "name": "any", + "required_signoffs": 2 } +}, +{ + "pk": 2, + "model": "main.arch", + "fields": { + "agnostic": false, + "name": "i686", + "required_signoffs": 1 + } +}, +{ + "pk": 3, + "model": "main.arch", + "fields": { + "agnostic": false, + "name": "x86_64", + "required_signoffs": 2 + } +} ] diff --git a/main/fixtures/groups.json b/main/fixtures/groups.json new file mode 100644 index 00000000..fd36e38c --- /dev/null +++ b/main/fixtures/groups.json @@ -0,0 +1,512 @@ +[ +{ + "fields": { + "name": "Hackers", + "permissions": [ + [ + "change_package", + "main", + "package" + ], + [ + "add_news", + "news", + "news" + ], + [ + "change_news", + "news", + "news" + ], + [ + "add_signoff", + "packages", + "signoff" + ], + [ + "change_signoff", + "packages", + "signoff" + ], + [ + "add_signoffspecification", + "packages", + "signoffspecification" + ], + [ + "change_signoffspecification", + "packages", + "signoffspecification" + ], + [ + "add_todolist", + "todolists", + "todolist" + ], + [ + "change_todolist", + "todolists", + "todolist" + ], + [ + "add_todolistpackage", + "todolists", + "todolistpackage" + ], + [ + "change_todolistpackage", + "todolists", + "todolistpackage" + ], + [ + "delete_todolistpackage", + "todolists", + "todolistpackage" + ] + ] + }, + "model": "auth.group", + "pk": 1 +}, +{ + "fields": { + "name": "Trusted Users", + "permissions": [ + [ + "change_package", + "main", + "package" + ], + [ + "add_signoff", + "packages", + "signoff" + ], + [ + "change_signoff", + "packages", + "signoff" + ], + [ + "add_signoffspecification", + "packages", + "signoffspecification" + ], + [ + "change_signoffspecification", + "packages", + "signoffspecification" + ], + [ + "add_todolist", + "todolists", + "todolist" + ], + [ + "change_todolist", + "todolists", + "todolist" + ], + [ + "add_todolistpackage", + "todolists", + "todolistpackage" + ], + [ + "change_todolistpackage", + "todolists", + "todolistpackage" + ], + [ + "delete_todolistpackage", + "todolists", + "todolistpackage" + ] + ] + }, + "model": "auth.group", + "pk": 2 +}, +{ + "fields": { + "name": "Mirror Maintainers", + "permissions": [ + [ + "add_mirror", + "mirrors", + "mirror" + ], + [ + "change_mirror", + "mirrors", + "mirror" + ], + [ + "delete_mirror", + "mirrors", + "mirror" + ], + [ + "add_mirrorprotocol", + "mirrors", + "mirrorprotocol" + ], + [ + "change_mirrorprotocol", + "mirrors", + "mirrorprotocol" + ], + [ + "add_mirrorrsync", + "mirrors", + "mirrorrsync" + ], + [ + "change_mirrorrsync", + "mirrors", + "mirrorrsync" + ], + [ + "delete_mirrorrsync", + "mirrors", + "mirrorrsync" + ], + [ + "add_mirrorurl", + "mirrors", + "mirrorurl" + ], + [ + "change_mirrorurl", + "mirrors", + "mirrorurl" + ], + [ + "delete_mirrorurl", + "mirrors", + "mirrorurl" + ] + ] + }, + "model": "auth.group", + "pk": 3 +}, +{ + "fields": { + "name": "User Admins", + "permissions": [ + [ + "add_user", + "auth", + "user" + ], + [ + "change_user", + "auth", + "user" + ], + [ + "change_staffgroup", + "devel", + "staffgroup" + ], + [ + "add_userprofile", + "devel", + "userprofile" + ], + [ + "change_userprofile", + "devel", + "userprofile" + ] + ] + }, + "model": "auth.group", + "pk": 4 +}, +{ + "fields": { + "name": "Release Engineering", + "permissions": [ + [ + "add_architecture", + "releng", + "architecture" + ], + [ + "change_architecture", + "releng", + "architecture" + ], + [ + "delete_architecture", + "releng", + "architecture" + ], + [ + "add_bootloader", + "releng", + "bootloader" + ], + [ + "change_bootloader", + "releng", + "bootloader" + ], + [ + "delete_bootloader", + "releng", + "bootloader" + ], + [ + "add_boottype", + "releng", + "boottype" + ], + [ + "change_boottype", + "releng", + "boottype" + ], + [ + "delete_boottype", + "releng", + "boottype" + ], + [ + "add_clockchoice", + "releng", + "clockchoice" + ], + [ + "change_clockchoice", + "releng", + "clockchoice" + ], + [ + "delete_clockchoice", + "releng", + "clockchoice" + ], + [ + "add_filesystem", + "releng", + "filesystem" + ], + [ + "change_filesystem", + "releng", + "filesystem" + ], + [ + "delete_filesystem", + "releng", + "filesystem" + ], + [ + "add_hardwaretype", + "releng", + "hardwaretype" + ], + [ + "change_hardwaretype", + "releng", + "hardwaretype" + ], + [ + "delete_hardwaretype", + "releng", + "hardwaretype" + ], + [ + "add_installtype", + "releng", + "installtype" + ], + [ + "change_installtype", + "releng", + "installtype" + ], + [ + "delete_installtype", + "releng", + "installtype" + ], + [ + "add_iso", + "releng", + "iso" + ], + [ + "change_iso", + "releng", + "iso" + ], + [ + "delete_iso", + "releng", + "iso" + ], + [ + "add_isotype", + "releng", + "isotype" + ], + [ + "change_isotype", + "releng", + "isotype" + ], + [ + "delete_isotype", + "releng", + "isotype" + ], + [ + "add_module", + "releng", + "module" + ], + [ + "change_module", + "releng", + "module" + ], + [ + "delete_module", + "releng", + "module" + ], + [ + "add_release", + "releng", + "release" + ], + [ + "change_release", + "releng", + "release" + ], + [ + "delete_release", + "releng", + "release" + ], + [ + "add_source", + "releng", + "source" + ], + [ + "change_source", + "releng", + "source" + ], + [ + "delete_source", + "releng", + "source" + ], + [ + "add_test", + "releng", + "test" + ], + [ + "change_test", + "releng", + "test" + ], + [ + "delete_test", + "releng", + "test" + ] + ] + }, + "model": "auth.group", + "pk": 5 +}, +{ + "fields": { + "name": "Package Relation Maintainers", + "permissions": [ + [ + "add_packagerelation", + "packages", + "packagerelation" + ], + [ + "change_packagerelation", + "packages", + "packagerelation" + ], + [ + "delete_packagerelation", + "packages", + "packagerelation" + ] + ] + }, + "model": "auth.group", + "pk": 6 +}, +{ + "fields": { + "name": "Download Page Releases", + "permissions": [ + [ + "add_release", + "releng", + "release" + ], + [ + "change_release", + "releng", + "release" + ], + [ + "delete_release", + "releng", + "release" + ] + ] + }, + "model": "auth.group", + "pk": 8 +}, +{ + "fields": { + "name": "Retired Hackers", + "permissions": [] + }, + "model": "auth.group", + "pk": 9 +}, +{ + "fields": { + "name": "Retired Trusted Users", + "permissions": [] + }, + "model": "auth.group", + "pk": 10 +}, +{ + "fields": { + "name": "Support Staff", + "permissions": [] + }, + "model": "auth.group", + "pk": 11 +}, +{ + "fields": { + "name": "Artists", + "permissions": [] + }, + "model": "auth.group", + "pk": 12 +} +] diff --git a/main/fixtures/mirrorprotocols.json b/main/fixtures/mirrorprotocols.json deleted file mode 100644 index 9e8932a8..00000000 --- a/main/fixtures/mirrorprotocols.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "pk": 2, - "model": "main.mirrorprotocol", - "fields": { - "protocol": "ftp" - } - }, - { - "pk": 1, - "model": "main.mirrorprotocol", - "fields": { - "protocol": "http" - } - }, - { - "pk": 3, - "model": "main.mirrorprotocol", - "fields": { - "protocol": "rsync" - } - } -] diff --git a/main/fixtures/repos.json b/main/fixtures/repos.json index bc474d3e..a6f564b7 100644 --- a/main/fixtures/repos.json +++ b/main/fixtures/repos.json @@ -3,60 +3,144 @@ "pk": 5, "model": "main.repo", "fields": { - "svn_root": "community", - "testing": false, + "bugs_category": 33, + "staging": false, "name": "Community", - "bugs_project": 5 + "bugs_project": 5, + "svn_root": "community", + "testing": false } }, { - "pk": 6, + "pk": 11, "model": "main.repo", "fields": { + "bugs_category": 41, + "staging": true, + "name": "Community-Staging", + "bugs_project": 5, "svn_root": "community", - "testing": true, + "testing": false + } + }, + { + "pk": 6, + "model": "main.repo", + "fields": { + "bugs_category": 41, + "staging": false, "name": "Community-Testing", - "bugs_project": 5 + "bugs_project": 5, + "svn_root": "community", + "testing": true } }, { "pk": 1, "model": "main.repo", "fields": { - "svn_root": "packages", - "testing": false, + "bugs_category": 31, + "staging": false, "name": "Core", - "bugs_project": 1 + "bugs_project": 1, + "svn_root": "packages", + "testing": false } }, { "pk": 2, "model": "main.repo", "fields": { - "svn_root": "packages", - "testing": false, + "bugs_category": 2, + "staging": false, "name": "Extra", - "bugs_project": 1 + "bugs_project": 1, + "svn_root": "packages", + "testing": false + } + }, + { + "pk": 13, + "model": "main.repo", + "fields": { + "bugs_category": 10, + "staging": true, + "name": "Gnome-Unstable", + "bugs_project": 1, + "svn_root": "packages", + "testing": false + } + }, + { + "pk": 12, + "model": "main.repo", + "fields": { + "bugs_category": 10, + "staging": true, + "name": "KDE-Unstable", + "bugs_project": 1, + "svn_root": "packages", + "testing": false } }, { "pk": 7, "model": "main.repo", "fields": { - "svn_root": "community", - "testing": false, + "bugs_category": 46, + "staging": false, "name": "Multilib", - "bugs_project": 5 + "bugs_project": 5, + "svn_root": "community", + "testing": false } }, { - "pk": 3, + "pk": 14, + "model": "main.repo", + "fields": { + "bugs_category": 46, + "staging": true, + "name": "Multilib-Staging", + "bugs_project": 5, + "svn_root": "community", + "testing": false + } + }, + { + "pk": 8, + "model": "main.repo", + "fields": { + "bugs_category": 46, + "staging": false, + "name": "Multilib-Testing", + "bugs_project": 5, + "svn_root": "community", + "testing": true + } + }, + { + "pk": 10, "model": "main.repo", "fields": { + "bugs_category": 10, + "staging": true, + "name": "Staging", + "bugs_project": 1, "svn_root": "packages", - "testing": true, + "testing": false + } + }, + { + "pk": 3, + "model": "main.repo", + "fields": { + "bugs_category": 10, + "staging": false, "name": "Testing", - "bugs_project": 1 + "bugs_project": 1, + "svn_root": "packages", + "testing": true } } ] diff --git a/main/fixtures/test_packages.json b/main/fixtures/test_packages.json deleted file mode 100644 index bc3be6d1..00000000 --- a/main/fixtures/test_packages.json +++ /dev/null @@ -1,11118 +0,0 @@ -[ - { - "pk": "1", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities to download and work with the Arch Build System (ABS)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "abs", - "arch": 2, - "pkgver": "2.0" - } - }, - { - "pk": "2", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library for filesystem ACL support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "acl", - "arch": 2, - "pkgver": "2.2.47" - } - }, - { - "pk": "3", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers for atl2 ethernet card", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "atl2", - "arch": 2, - "pkgver": "2.0.4" - } - }, - { - "pk": "4", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Extended attribute support library for ACL support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "attr", - "arch": 2, - "pkgver": "2.4.41" - } - }, - { - "pk": "5", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU tool for automatically configuring source code", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "autoconf", - "arch": 2, - "pkgver": "2.61" - } - }, - { - "pk": "6", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU tool for automatically creating Makefiles", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "automake", - "arch": 2, - "pkgver": "1.10.1" - } - }, - { - "pk": "7", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU Bourne Again shell", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "bash", - "arch": 2, - "pkgver": "3.2.033" - } - }, - { - "pk": "8", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "firmware extractor for the bcm43xx kernel module", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "bcm43xx-fwcutter", - "arch": 2, - "pkgver": "006" - } - }, - { - "pk": "9", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A complete 8086 assembler and loader", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "bin86", - "arch": 2, - "pkgver": "0.16.17" - } - }, - { - "pk": "10", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A set of programs to assemble and manipulate binary and object files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "binutils", - "arch": 2, - "pkgver": "2.18" - } - }, - { - "pk": "11", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU general-purpose parser generator", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "bison", - "arch": 2, - "pkgver": "2.3" - } - }, - { - "pk": "12", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Layer2 ethernet bridging for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "bridge-utils", - "arch": 2, - "pkgver": "1.2" - } - }, - { - "pk": "13", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A high-quality data compression program", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "bzip2", - "arch": 2, - "pkgver": "1.0.4" - } - }, - { - "pk": "14", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "capi utils for isdn cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "capi4k-utils", - "arch": 2, - "pkgver": "050718" - } - }, - { - "pk": "15", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The basic file, shell and text manipulation utilities of the GNU operating system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "coreutils", - "arch": 2, - "pkgver": "6.10" - } - }, - { - "pk": "16", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool to copy files into or out of a cpio or tar archive", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "cpio", - "arch": 2, - "pkgver": "2.9" - } - }, - { - "pk": "17", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Password Checking Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "cracklib", - "arch": 2, - "pkgver": "2.8.10" - } - }, - { - "pk": "18", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Userspace setup tool for transparent encryption of block devices using the Linux 2.6 cryptoapi", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "cryptsetup", - "arch": 2, - "pkgver": "1.0.6" - } - }, - { - "pk": "19", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "csup - cvsup rewritten in C", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "csup", - "arch": 2, - "pkgver": "20060318" - } - }, - { - "pk": "20", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A POSIX compliant shell that aims to be as small as possible", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "dash", - "arch": 2, - "pkgver": "0.5.4" - } - }, - { - "pk": "21", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Berkeley DB embedded database system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "db", - "arch": 2, - "pkgver": "4.6.21" - } - }, - { - "pk": "22", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Dillon's Cron Daemon", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "dcron", - "arch": 2, - "pkgver": "3.2" - } - }, - { - "pk": "23", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Device mapper userspace library and tools.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "device-mapper", - "arch": 2, - "pkgver": "1.02.24" - } - }, - { - "pk": "24", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A DHCP client daemon", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "dhcpcd", - "arch": 2, - "pkgver": "3.2.1" - } - }, - { - "pk": "25", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool to display dialog boxes from shell scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "dialog", - "arch": 2, - "pkgver": "1.1_20071028" - } - }, - { - "pk": "26", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility programs used for creating patch files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "diffutils", - "arch": 2, - "pkgver": "2.8.1" - } - }, - { - "pk": "27", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Data migration API", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "dmapi", - "arch": 2, - "pkgver": "2.2.8" - } - }, - { - "pk": "28", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Device mapper RAID interface", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "dmraid", - "arch": 2, - "pkgver": "1.0.0.rc14" - } - }, - { - "pk": "29", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Various DNS utilities - dig host nslookup nsupdate", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "dnsutils", - "arch": 2, - "pkgver": "9.4.2" - } - }, - { - "pk": "30", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "DOS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "dosfstools", - "arch": 2, - "pkgver": "2.11" - } - }, - { - "pk": "31", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Ext2 filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "e2fsprogs", - "arch": 2, - "pkgver": "1.40.8" - } - }, - { - "pk": "32", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A POSIX-compliant line editor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "ed", - "arch": 2, - "pkgver": "0.9" - } - }, - { - "pk": "33", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A new API to format and send structured log messages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "eventlog", - "arch": 2, - "pkgver": "0.2.5" - } - }, - { - "pk": "34", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Gives a fake root environment, useful for building packages as a non-privileged user", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "fakeroot", - "arch": 2, - "pkgver": "1.9.3" - } - }, - { - "pk": "35", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "File type identification utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "file", - "arch": 2, - "pkgver": "4.23" - } - }, - { - "pk": "36", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Base filesystem", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "filesystem", - "arch": 2, - "pkgver": "2008.03" - } - }, - { - "pk": "37", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU utilities to locate files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "findutils", - "arch": 2, - "pkgver": "4.2.33" - } - }, - { - "pk": "38", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool for generating text-scanning programs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "flex", - "arch": 2, - "pkgver": "2.5.33" - } - }, - { - "pk": "39", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library that makes it possible to implement a filesystem in a userspace program.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "fuse", - "arch": 2, - "pkgver": "2.7.3" - } - }, - { - "pk": "40", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Gnu version of awk", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "gawk", - "arch": 2, - "pkgver": "3.1.6" - } - }, - { - "pk": "41", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU Compiler Collection", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "gcc", - "arch": 2, - "pkgver": "4.3.0" - } - }, - { - "pk": "42", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Runtime libraries shipped by GCC for C and C++ languages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "gcc-libs", - "arch": 2, - "pkgver": "4.3.0" - } - }, - { - "pk": "43", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU database library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "gdbm", - "arch": 2, - "pkgver": "1.8.3" - } - }, - { - "pk": "44", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Program to compress initramfs images", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "gen-init-cpio", - "arch": 2, - "pkgver": "2.6.17" - } - }, - { - "pk": "45", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU internationalization library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "gettext", - "arch": 2, - "pkgver": "0.17" - } - }, - { - "pk": "46", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Common C routines used by GTK+ 2.4 and other libs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "glib2", - "arch": 2, - "pkgver": "2.16.2" - } - }, - { - "pk": "47", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU C Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "9", - "pkgname": "glibc", - "arch": 2, - "pkgver": "2.7" - } - }, - { - "pk": "48", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A free library for arbitrary precision arithmetic", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "gmp", - "arch": 2, - "pkgver": "4.2.2" - } - }, - { - "pk": "49", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A mouse server for the console and xterm", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "7", - "pkgname": "gpm", - "arch": 2, - "pkgver": "1.20.1" - } - }, - { - "pk": "50", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A string search utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "grep", - "arch": 2, - "pkgver": "2.5.3" - } - }, - { - "pk": "51", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU troff text-formatting system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "groff", - "arch": 2, - "pkgver": "1.19.2" - } - }, - { - "pk": "52", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU multiboot boot loader", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "12", - "pkgname": "grub", - "arch": 2, - "pkgver": "0.97" - } - }, - { - "pk": "53", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU compression utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "gzip", - "arch": 2, - "pkgver": "1.3.12" - } - }, - { - "pk": "54", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A shell utility for manipulating Linux IDE drive\/driver parameters", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "hdparm", - "arch": 2, - "pkgver": "8.6" - } - }, - { - "pk": "55", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Heimdal Kerberos V5 libraries", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "heimdal", - "arch": 2, - "pkgver": "1.0.1" - } - }, - { - "pk": "56", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Hardware detection script with loading modules and mkinitcpio.conf \/ rc.conf support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "hwdetect", - "arch": 2, - "pkgver": "0.9" - } - }, - { - "pk": "57", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility for bonding ethernet interfaces", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "ifenslave", - "arch": 2, - "pkgver": "1.1.0" - } - }, - { - "pk": "58", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "System initialization\/bootup scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "initscripts", - "arch": 2, - "pkgver": "2008.03" - } - }, - { - "pk": "59", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "IP Routing Utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "iproute", - "arch": 2, - "pkgver": "2.6.24_rc7" - } - }, - { - "pk": "60", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A Linux kernel packet control tool", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "iptables", - "arch": 2, - "pkgver": "1.4.0" - } - }, - { - "pk": "61", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "IP Configuration Utilities (and Ping)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "iputils", - "arch": 2, - "pkgver": "20070202" - } - }, - { - "pk": "62", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW2100", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw2100-fw", - "arch": 2, - "pkgver": "1.3" - } - }, - { - "pk": "63", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW2200", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw2200-fw", - "arch": 2, - "pkgver": "3.0" - } - }, - { - "pk": "64", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Driver for the Intel PRO\/Wireless 3945ABG miniPCI express adapter", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "8", - "pkgname": "ipw3945", - "arch": 2, - "pkgver": "1.2.2" - } - }, - { - "pk": "65", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW3945", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw3945-ucode", - "arch": 2, - "pkgver": "1.14.2" - } - }, - { - "pk": "66", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Regulatory daemon for IPW3945", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "ipw3945d", - "arch": 2, - "pkgver": "1.7.22" - } - }, - { - "pk": "67", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "User space administration programs and tools for ISDN", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "isdn4k-utils", - "arch": 2, - "pkgver": "3.2p1" - } - }, - { - "pk": "68", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel wireless firmware for IPW3945 (iwlwifi driver)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "iwlwifi-3945-ucode", - "arch": 2, - "pkgver": "2.14.1.5" - } - }, - { - "pk": "69", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel wireless firmware for IPW4965 (iwlwifi driver)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "iwlwifi-4965-ucode", - "arch": 2, - "pkgver": "4.44.1.20" - } - }, - { - "pk": "70", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "JFS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "jfsutils", - "arch": 2, - "pkgver": "1.1.12" - } - }, - { - "pk": "71", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Keytable files and keyboard utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "kbd", - "arch": 2, - "pkgver": "1.14.1.20080309" - } - }, - { - "pk": "72", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Kernel headers sanitized for use in userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "kernel-headers", - "arch": 2, - "pkgver": "2.6.24.3" - } - }, - { - "pk": "73", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Linux Kernel and modules", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "kernel26", - "arch": 2, - "pkgver": "2.6.24.4" - } - }, - { - "pk": "74", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a minimal libc made for early-userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "klibc", - "arch": 2, - "pkgver": "1.5" - } - }, - { - "pk": "75", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Extra apps for klibc early-userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "klibc-extras", - "arch": 2, - "pkgver": "2.4" - } - }, - { - "pk": "76", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Keytable files and keyboard utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "klibc-kbd", - "arch": 2, - "pkgver": "1.15.20080312" - } - }, - { - "pk": "77", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing modules from the Linux kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "klibc-module-init-tools", - "arch": 2, - "pkgver": "3.2.2" - } - }, - { - "pk": "78", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "udevd compiled under klibc", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "klibc-udev", - "arch": 2, - "pkgver": "116" - } - }, - { - "pk": "79", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A terminal based program for viewing text files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "less", - "arch": 2, - "pkgver": "418" - } - }, - { - "pk": "80", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "library that can create and read several streaming archive formats", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "libarchive", - "arch": 2, - "pkgver": "2.4.17" - } - }, - { - "pk": "81", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "URL based download library, forked from libfetch", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "libdownload", - "arch": 2, - "pkgver": "1.3" - } - }, - { - "pk": "82", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "libelf is a free ELF object file access library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "libelf", - "arch": 2, - "pkgver": "0.8.10" - } - }, - { - "pk": "83", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "libevent", - "arch": 2, - "pkgver": "1.3e" - } - }, - { - "pk": "84", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a general purpose crypto library based on the code used", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1.1", - "pkgname": "libgcrypt", - "arch": 2, - "pkgver": "1.4.0" - } - }, - { - "pk": "85", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Support library for libgcrypt", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "libgpg-error", - "arch": 2, - "pkgver": "1.6" - } - }, - { - "pk": "86", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "LDAP client libraries", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "libldap", - "arch": 2, - "pkgver": "2.3.39" - } - }, - { - "pk": "87", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A system-independent interface for user-level packet capture", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "libpcap", - "arch": 2, - "pkgver": "0.9.8" - } - }, - { - "pk": "88", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Cyrus Simple Authentication Service Layer (SASL) library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "libsasl", - "arch": 2, - "pkgver": "2.1.22" - } - }, - { - "pk": "89", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A generic library support script", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "libtool", - "arch": 2, - "pkgver": "2.2" - } - }, - { - "pk": "90", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library to enable user space application programs to communicate with USB devices", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "libusb", - "arch": 2, - "pkgver": "0.1.12" - } - }, - { - "pk": "91", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The standard licenses distribution package", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "licenses", - "arch": 2, - "pkgver": "2.3" - } - }, - { - "pk": "92", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A bootloader for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "lilo", - "arch": 2, - "pkgver": "22.8" - } - }, - { - "pk": "93", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A text WWW browser, similar to Lynx", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "links", - "arch": 2, - "pkgver": "2.1pre33" - } - }, - { - "pk": "94", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers and tools to support ATM networking under Linux.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "linux-atm", - "arch": 2, - "pkgver": "2.4.1" - } - }, - { - "pk": "95", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Rotates system logs automatically", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "logrotate", - "arch": 2, - "pkgver": "3.7.5" - } - }, - { - "pk": "96", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Logical Volume Manager 2 utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "lvm2", - "arch": 2, - "pkgver": "2.02.33" - } - }, - { - "pk": "97", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a portable lossless data compression library written in ANSI C", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "lzo2", - "arch": 2, - "pkgver": "2.02" - } - }, - { - "pk": "98", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "m4 macro processor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "m4", - "arch": 2, - "pkgver": "1.4.10" - } - }, - { - "pk": "99", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Madwifi drivers for Atheros wireless chipsets. For stock arch 2.6 kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "madwifi", - "arch": 2, - "pkgver": "0.9.4.3382" - } - }, - { - "pk": "100", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Userspace tools of madwifi drivers for Atheros wireless chipsets.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "madwifi-utils", - "arch": 2, - "pkgver": "0.9.4.3382" - } - }, - { - "pk": "101", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A commandline utility for sending email", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "mailx", - "arch": 2, - "pkgver": "8.1.1" - } - }, - { - "pk": "102", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU make utility to maintain groups of programs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "make", - "arch": 2, - "pkgver": "3.81" - } - }, - { - "pk": "103", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility for reading man pages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "man", - "arch": 2, - "pkgver": "1.6f" - } - }, - { - "pk": "104", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Linux man pages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "man-pages", - "arch": 2, - "pkgver": "2.79" - } - }, - { - "pk": "105", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool for managing\/monitoring Linux md device arrays, also known as Software RAID", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "mdadm", - "arch": 2, - "pkgver": "2.6.4" - } - }, - { - "pk": "106", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Advanced, modular initramfs image creation utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "mkinitcpio", - "arch": 2, - "pkgver": "0.5.18.1" - } - }, - { - "pk": "107", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Faster merging drop-in for slocate", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "mlocate", - "arch": 2, - "pkgver": "0.18" - } - }, - { - "pk": "108", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing modules from the Linux kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "module-init-tools", - "arch": 2, - "pkgver": "3.2.2" - } - }, - { - "pk": "109", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "multiple-precision floating-point library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "mpfr", - "arch": 2, - "pkgver": "2.3.1" - } - }, - { - "pk": "110", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Pico editor clone with enhancements", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "nano", - "arch": 2, - "pkgver": "2.0.7" - } - }, - { - "pk": "111", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A System V Release 4.0 curses emulation library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "ncurses", - "arch": 2, - "pkgver": "5.6" - } - }, - { - "pk": "112", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Module for NDIS (Windows Network Drivers) drivers supplied by vendors. For stock arch 2.6 kernel.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "ndiswrapper", - "arch": 2, - "pkgver": "1.52" - } - }, - { - "pk": "113", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Binaries for ndiswrapper module", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "ndiswrapper-utils", - "arch": 2, - "pkgver": "1.52" - } - }, - { - "pk": "114", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Configuration tools for Linux networking", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "13", - "pkgname": "net-tools", - "arch": 2, - "pkgver": "1.60" - } - }, - { - "pk": "115", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Network configuration and profile scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "netcfg", - "arch": 2, - "pkgver": "2.0.6" - } - }, - { - "pk": "116", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A telnet client (and server)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "7", - "pkgname": "netkit-telnet", - "arch": 2, - "pkgver": "0.17" - } - }, - { - "pk": "117", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Support programs for Network File Systems", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "nfs-utils", - "arch": 2, - "pkgver": "1.1.0" - } - }, - { - "pk": "118", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library to help mapping IDs, mainly for NFSv4", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "nfsidmap", - "arch": 2, - "pkgver": "0.20" - } - }, - { - "pk": "119", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Third generation Linux NTFS driver", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "ntfs-3g", - "arch": 2, - "pkgver": "1.2310" - } - }, - { - "pk": "120", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "NTFS Resizing Tool", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "ntfsprogs", - "arch": 2, - "pkgver": "2.0.0" - } - }, - { - "pk": "121", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A Secure SHell server\/client", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "openssh", - "arch": 2, - "pkgver": "4.7p1" - } - }, - { - "pk": "122", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Open Source toolkit for Secure Sockets Layer and Transport Layer Security", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "openssl", - "arch": 2, - "pkgver": "0.9.8g" - } - }, - { - "pk": "123", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Open Source implementation of IPsec for the Linux operating system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "openswan", - "arch": 2, - "pkgver": "2.4.11" - } - }, - { - "pk": "124", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "An easy-to-use, robust, and highly configurable VPN (Virtual Private Network)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "openvpn", - "arch": 2, - "pkgver": "2.0.9" - } - }, - { - "pk": "125", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library-based package manager with dependency support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "pacman", - "arch": 2, - "pkgver": "3.1.4" - } - }, - { - "pk": "126", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "PAM (Pluggable Authentication Modules) library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "pam", - "arch": 2, - "pkgver": "0.99.9.0" - } - }, - { - "pk": "127", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility to apply patch files to original sources", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "patch", - "arch": 2, - "pkgver": "2.5.4" - } - }, - { - "pk": "128", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "PCI bus configuration space access library and tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "pciutils", - "arch": 2, - "pkgver": "2.2.8" - } - }, - { - "pk": "129", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing PCMCIA cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "pcmciautils", - "arch": 2, - "pkgver": "014" - } - }, - { - "pk": "130", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library that implements Perl 5-style regular expressions", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "pcre", - "arch": 2, - "pkgver": "7.6" - } - }, - { - "pk": "131", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Practical Extraction and Report Language", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "perl", - "arch": 2, - "pkgver": "5.10.0" - } - }, - { - "pk": "132", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A system for managing library compile\/link flags", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "pkgconfig", - "arch": 2, - "pkgver": "0.22" - } - }, - { - "pk": "133", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A commandline option parser", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "popt", - "arch": 2, - "pkgver": "1.10.6" - } - }, - { - "pk": "134", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "RPC connection manager", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "portmap", - "arch": 2, - "pkgver": "6.0" - } - }, - { - "pk": "135", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A daemon which implements the PPP protocol for dial-up networking", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "6", - "pkgname": "ppp", - "arch": 2, - "pkgver": "2.4.4" - } - }, - { - "pk": "136", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Client for the proprietary Microsoft Point-to-Point Tunneling Protocol, PPTP.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "pptpclient", - "arch": 2, - "pkgver": "1.7.1" - } - }, - { - "pk": "137", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Displays useful information from \/proc", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "procinfo", - "arch": 2, - "pkgver": "19" - } - }, - { - "pk": "138", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for monitoring your system and processes on your system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "procps", - "arch": 2, - "pkgver": "3.2.7" - } - }, - { - "pk": "139", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Miscellaneous procfs tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "psmisc", - "arch": 2, - "pkgver": "22.6" - } - }, - { - "pk": "140", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU readline library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "7", - "pkgname": "readline", - "arch": 2, - "pkgver": "5.2" - } - }, - { - "pk": "141", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Reiserfs utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "reiserfsprogs", - "arch": 2, - "pkgver": "3.6.20" - } - }, - { - "pk": "142", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Roaring Penguin's Point-to-Point Protocol over Ethernet client", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "rp-pppoe", - "arch": 2, - "pkgver": "3.8" - } - }, - { - "pk": "143", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers for rt2500 chipset wireless cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "21", - "pkgname": "rt2500", - "arch": 2, - "pkgver": "1.1.0_B4" - } - }, - { - "pk": "144", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the rt2x00 wireless drivers", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "rt2x00-rt61-fw", - "arch": 2, - "pkgver": "1.2" - } - }, - { - "pk": "145", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the rt2x00 wireless drivers", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "rt2x00-rt71w-fw", - "arch": 2, - "pkgver": "1.8" - } - }, - { - "pk": "146", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "An utility similar to hdparm but for SCSI devices", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "sdparm", - "arch": 2, - "pkgver": "1.02" - } - }, - { - "pk": "147", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU stream editor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "sed", - "arch": 2, - "pkgver": "4.1.5" - } - }, - { - "pk": "148", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Shadow password file utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "shadow", - "arch": 2, - "pkgver": "4.0.18.2" - } - }, - { - "pk": "149", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Give certain users the ability to run some commands as root", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "sudo", - "arch": 2, - "pkgver": "1.6.9p12" - } - }, - { - "pk": "150", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "System Utilities Based on Sysfs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "sysfsutils", - "arch": 2, - "pkgver": "2.1.0" - } - }, - { - "pk": "151", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Next-generation syslogd with advanced networking and filtering capabilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "syslog-ng", - "arch": 2, - "pkgver": "2.0.6" - } - }, - { - "pk": "152", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Linux System V Init", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "sysvinit", - "arch": 2, - "pkgver": "2.86" - } - }, - { - "pk": "153", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility used to store, backup, and transport files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "tar", - "arch": 2, - "pkgver": "1.19" - } - }, - { - "pk": "154", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Monitors and Controls incoming TCP connections", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "8", - "pkgname": "tcp_wrappers", - "arch": 2, - "pkgver": "7.6" - } - }, - { - "pk": "155", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities to work with and produce manuals, ASCII text, and on-line documentation from a single source file", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "texinfo", - "arch": 2, - "pkgver": "4.11" - } - }, - { - "pk": "156", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "OpenSource module for Texas Instruments ACX100\/ACX111 wireless chips. For stock arch 2.6 kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "tiacx", - "arch": 2, - "pkgver": "20080210" - } - }, - { - "pk": "157", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for Texas Instruments ACX100\/ACX111 wireless chips.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "tiacx-firmware", - "arch": 2, - "pkgver": "2" - } - }, - { - "pk": "158", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Sources for time zone and daylight saving time data", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "tzdata", - "arch": 2, - "pkgver": "2008b" - } - }, - { - "pk": "159", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The userspace dev tools (udev)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "udev", - "arch": 2, - "pkgver": "119" - } - }, - { - "pk": "160", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "USB Device Utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "5", - "pkgname": "usbutils", - "arch": 2, - "pkgver": "0.73" - } - }, - { - "pk": "161", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Miscellaneous system utilities for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "util-linux-ng", - "arch": 2, - "pkgver": "2.13.0.1" - } - }, - { - "pk": "162", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a highly configurable, improved version of the vi text editor (basic version)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "vi", - "arch": 2, - "pkgver": "7.1.267" - } - }, - { - "pk": "163", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "VPN client for cisco3000 VPN Concentrators", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "vpnc", - "arch": 2, - "pkgver": "0.5.1" - } - }, - { - "pk": "164", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A network utility to retrieve files from the Web", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "wget", - "arch": 2, - "pkgver": "1.11" - } - }, - { - "pk": "165", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility to show the full path of commands", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "which", - "arch": 2, - "pkgver": "2.19" - } - }, - { - "pk": "166", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "wireless_tools", - "arch": 2, - "pkgver": "29" - } - }, - { - "pk": "167", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Lan usb modules. For kernel26.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "15", - "pkgname": "wlan-ng26", - "arch": 2, - "pkgver": "0.2.8" - } - }, - { - "pk": "168", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Lan userspace tools.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "wlan-ng26-utils", - "arch": 2, - "pkgver": "0.2.8" - } - }, - { - "pk": "169", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility providing key negotiation for WPA wireless networks", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "wpa_supplicant", - "arch": 2, - "pkgver": "0.5.10" - } - }, - { - "pk": "170", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "XFS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "1", - "pkgname": "xfsprogs", - "arch": 2, - "pkgver": "2.9.7" - } - }, - { - "pk": "171", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "xinetd is a secure replacement for inetd", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "3", - "pkgname": "xinetd", - "arch": 2, - "pkgver": "2.3.14" - } - }, - { - "pk": "172", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the in-kernel26 zd1211rw wireless driver", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "2", - "pkgname": "zd1211-firmware", - "arch": 2, - "pkgver": "1.4" - } - }, - { - "pk": "173", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A compression\/decompression Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:02:44", - "repo": 1, - "pkgrel": "4", - "pkgname": "zlib", - "arch": 2, - "pkgver": "1.2.3" - } - }, - { - "pk": "174", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities to download and work with the Arch Build System (ABS)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "abs", - "arch": 3, - "pkgver": "2.0" - } - }, - { - "pk": "175", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library for filesystem ACL support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "acl", - "arch": 3, - "pkgver": "2.2.47" - } - }, - { - "pk": "176", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers for atl2 ethernet card", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "atl2", - "arch": 3, - "pkgver": "2.0.4" - } - }, - { - "pk": "177", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Extended attribute support library for ACL support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "attr", - "arch": 3, - "pkgver": "2.4.41" - } - }, - { - "pk": "178", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU tool for automatically configuring source code", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "autoconf", - "arch": 3, - "pkgver": "2.61" - } - }, - { - "pk": "179", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU tool for automatically creating Makefiles", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "automake", - "arch": 3, - "pkgver": "1.10.1" - } - }, - { - "pk": "180", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU Bourne Again shell", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "bash", - "arch": 3, - "pkgver": "3.2.033" - } - }, - { - "pk": "181", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "firmware extractor for the bcm43xx kernel module", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "bcm43xx-fwcutter", - "arch": 3, - "pkgver": "006" - } - }, - { - "pk": "182", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A complete 8086 assembler and loader", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "bin86", - "arch": 3, - "pkgver": "0.16.17" - } - }, - { - "pk": "183", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A set of programs to assemble and manipulate binary and object files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "binutils", - "arch": 3, - "pkgver": "2.18" - } - }, - { - "pk": "184", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU general-purpose parser generator", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "bison", - "arch": 3, - "pkgver": "2.3" - } - }, - { - "pk": "185", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Layer2 ethernet bridging for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "bridge-utils", - "arch": 3, - "pkgver": "1.2" - } - }, - { - "pk": "186", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A high-quality data compression program", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "bzip2", - "arch": 3, - "pkgver": "1.0.4" - } - }, - { - "pk": "187", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "capi utils for isdn cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "capi4k-utils", - "arch": 3, - "pkgver": "050718" - } - }, - { - "pk": "188", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The basic file, shell and text manipulation utilities of the GNU operating system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "coreutils", - "arch": 3, - "pkgver": "6.10" - } - }, - { - "pk": "189", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool to copy files into or out of a cpio or tar archive", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "cpio", - "arch": 3, - "pkgver": "2.9" - } - }, - { - "pk": "190", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Password Checking Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "cracklib", - "arch": 3, - "pkgver": "2.8.10" - } - }, - { - "pk": "191", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Userspace setup tool for transparent encryption of block devices using the Linux 2.6 cryptoapi", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "cryptsetup", - "arch": 3, - "pkgver": "1.0.6" - } - }, - { - "pk": "192", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "csup - cvsup rewritten in C", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "csup", - "arch": 3, - "pkgver": "20060318" - } - }, - { - "pk": "193", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A POSIX compliant shell that aims to be as small as possible", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "dash", - "arch": 3, - "pkgver": "0.5.4" - } - }, - { - "pk": "194", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Berkeley DB embedded database system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "db", - "arch": 3, - "pkgver": "4.6.21" - } - }, - { - "pk": "195", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Dillon's Cron Daemon", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "dcron", - "arch": 3, - "pkgver": "3.2" - } - }, - { - "pk": "196", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Device mapper userspace library and tools.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "device-mapper", - "arch": 3, - "pkgver": "1.02.24" - } - }, - { - "pk": "197", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A DHCP client daemon", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "dhcpcd", - "arch": 3, - "pkgver": "3.2.1" - } - }, - { - "pk": "198", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool to display dialog boxes from shell scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "dialog", - "arch": 3, - "pkgver": "1.1_20071028" - } - }, - { - "pk": "199", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility programs used for creating patch files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "diffutils", - "arch": 3, - "pkgver": "2.8.1" - } - }, - { - "pk": "200", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Data migration API", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "dmapi", - "arch": 3, - "pkgver": "2.2.8" - } - }, - { - "pk": "201", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Device mapper RAID interface", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "dmraid", - "arch": 3, - "pkgver": "1.0.0.rc14" - } - }, - { - "pk": "202", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Various DNS utilities - dig host nslookup nsupdate", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "dnsutils", - "arch": 3, - "pkgver": "9.4.2" - } - }, - { - "pk": "203", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "DOS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "dosfstools", - "arch": 3, - "pkgver": "2.11" - } - }, - { - "pk": "204", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Ext2 filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "e2fsprogs", - "arch": 3, - "pkgver": "1.40.8" - } - }, - { - "pk": "205", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A POSIX-compliant line editor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "ed", - "arch": 3, - "pkgver": "0.9" - } - }, - { - "pk": "206", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A new API to format and send structured log messages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "eventlog", - "arch": 3, - "pkgver": "0.2.5" - } - }, - { - "pk": "207", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Gives a fake root environment, useful for building packages as a non-privileged user", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "fakeroot", - "arch": 3, - "pkgver": "1.9.3" - } - }, - { - "pk": "208", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "File type identification utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "file", - "arch": 3, - "pkgver": "4.23" - } - }, - { - "pk": "209", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Base filesystem", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "filesystem", - "arch": 3, - "pkgver": "2008.03" - } - }, - { - "pk": "210", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU utilities to locate files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "findutils", - "arch": 3, - "pkgver": "4.2.33" - } - }, - { - "pk": "211", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool for generating text-scanning programs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "flex", - "arch": 3, - "pkgver": "2.5.33" - } - }, - { - "pk": "212", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library that makes it possible to implement a filesystem in a userspace program.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "fuse", - "arch": 3, - "pkgver": "2.7.3" - } - }, - { - "pk": "213", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Gnu version of awk", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "gawk", - "arch": 3, - "pkgver": "3.1.6" - } - }, - { - "pk": "214", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The GNU Compiler Collection", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "gcc", - "arch": 3, - "pkgver": "4.3.0" - } - }, - { - "pk": "215", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Runtime libraries shipped by GCC for C and C++ languages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "gcc-libs", - "arch": 3, - "pkgver": "4.3.0" - } - }, - { - "pk": "216", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU database library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "gdbm", - "arch": 3, - "pkgver": "1.8.3" - } - }, - { - "pk": "217", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Program to compress initramfs images", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "gen-init-cpio", - "arch": 3, - "pkgver": "2.6.17" - } - }, - { - "pk": "218", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU internationalization library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "gettext", - "arch": 3, - "pkgver": "0.17" - } - }, - { - "pk": "219", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Common C routines used by GTK+ 2.4 and other libs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "glib2", - "arch": 3, - "pkgver": "2.16.3" - } - }, - { - "pk": "220", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU C Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "9", - "pkgname": "glibc", - "arch": 3, - "pkgver": "2.7" - } - }, - { - "pk": "221", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A free library for arbitrary precision arithmetic", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "gmp", - "arch": 3, - "pkgver": "4.2.2" - } - }, - { - "pk": "222", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A mouse server for the console and xterm", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "7", - "pkgname": "gpm", - "arch": 3, - "pkgver": "1.20.1" - } - }, - { - "pk": "223", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A string search utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "grep", - "arch": 3, - "pkgver": "2.5.3" - } - }, - { - "pk": "224", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU troff text-formatting system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "groff", - "arch": 3, - "pkgver": "1.19.2" - } - }, - { - "pk": "225", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A GNU multiboot boot loader", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "12", - "pkgname": "grub", - "arch": 3, - "pkgver": "0.97" - } - }, - { - "pk": "226", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU compression utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "gzip", - "arch": 3, - "pkgver": "1.3.12" - } - }, - { - "pk": "227", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A shell utility for manipulating Linux IDE drive\/driver parameters", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "hdparm", - "arch": 3, - "pkgver": "8.6" - } - }, - { - "pk": "228", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Heimdal Kerberos V5 libraries", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "heimdal", - "arch": 3, - "pkgver": "1.0.1" - } - }, - { - "pk": "229", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Hardware detection script with loading modules and mkinitcpio.conf \/ rc.conf support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "hwdetect", - "arch": 3, - "pkgver": "0.9" - } - }, - { - "pk": "230", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility for bonding ethernet interfaces", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "ifenslave", - "arch": 3, - "pkgver": "1.1.0" - } - }, - { - "pk": "231", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "System initialization\/bootup scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "initscripts", - "arch": 3, - "pkgver": "2008.03" - } - }, - { - "pk": "232", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "IP Routing Utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "iproute", - "arch": 3, - "pkgver": "2.6.24_rc7" - } - }, - { - "pk": "233", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A Linux kernel packet control tool", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "iptables", - "arch": 3, - "pkgver": "1.4.0" - } - }, - { - "pk": "234", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "IP Configuration Utilities (and Ping)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "iputils", - "arch": 3, - "pkgver": "20070202" - } - }, - { - "pk": "235", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW2100", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw2100-fw", - "arch": 3, - "pkgver": "1.3" - } - }, - { - "pk": "236", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW2200", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw2200-fw", - "arch": 3, - "pkgver": "3.0" - } - }, - { - "pk": "237", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Driver for the Intel PRO\/Wireless 3945ABG miniPCI express adapter", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "8", - "pkgname": "ipw3945", - "arch": 3, - "pkgver": "1.2.2" - } - }, - { - "pk": "238", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel Centrino Drivers firmware for IPW3945", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "ipw3945-ucode", - "arch": 3, - "pkgver": "1.14.2" - } - }, - { - "pk": "239", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Regulatory daemon for IPW3945", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "ipw3945d", - "arch": 3, - "pkgver": "1.7.22" - } - }, - { - "pk": "240", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "User space administration programs and tools for ISDN", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "isdn4k-utils", - "arch": 3, - "pkgver": "3.2p1" - } - }, - { - "pk": "241", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel wireless firmware for IPW3945 (iwlwifi driver)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "iwlwifi-3945-ucode", - "arch": 3, - "pkgver": "2.14.1.5" - } - }, - { - "pk": "242", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Intel wireless firmware for IPW4965 (iwlwifi driver)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "iwlwifi-4965-ucode", - "arch": 3, - "pkgver": "4.44.1.20" - } - }, - { - "pk": "243", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "JFS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "jfsutils", - "arch": 3, - "pkgver": "1.1.12" - } - }, - { - "pk": "244", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Keytable files and keyboard utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "kbd", - "arch": 3, - "pkgver": "1.14.1.20080309" - } - }, - { - "pk": "245", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Kernel headers sanitized for use in userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "kernel-headers", - "arch": 3, - "pkgver": "2.6.24.3" - } - }, - { - "pk": "246", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Linux Kernel and modules", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "kernel26", - "arch": 3, - "pkgver": "2.6.24.4" - } - }, - { - "pk": "247", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a minimal libc made for early-userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "klibc", - "arch": 3, - "pkgver": "1.5" - } - }, - { - "pk": "248", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Extra apps for klibc early-userspace", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "klibc-extras", - "arch": 3, - "pkgver": "2.4" - } - }, - { - "pk": "249", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Keytable files and keyboard utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "klibc-kbd", - "arch": 3, - "pkgver": "1.15.20080312" - } - }, - { - "pk": "250", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing modules from the Linux kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "klibc-module-init-tools", - "arch": 3, - "pkgver": "3.2.2" - } - }, - { - "pk": "251", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "udevd compiled under klibc", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "klibc-udev", - "arch": 3, - "pkgver": "116" - } - }, - { - "pk": "252", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A terminal based program for viewing text files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "less", - "arch": 3, - "pkgver": "418" - } - }, - { - "pk": "253", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "library that can create and read several streaming archive formats", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "libarchive", - "arch": 3, - "pkgver": "2.4.17" - } - }, - { - "pk": "254", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "URL based download library, forked from libfetch", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "libdownload", - "arch": 3, - "pkgver": "1.3" - } - }, - { - "pk": "255", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "libelf is a free ELF object file access library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3.1", - "pkgname": "libelf", - "arch": 3, - "pkgver": "0.8.10" - } - }, - { - "pk": "256", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "libevent", - "arch": 3, - "pkgver": "1.3e" - } - }, - { - "pk": "257", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a general purpose crypto library based on the code used", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "libgcrypt", - "arch": 3, - "pkgver": "1.4.0" - } - }, - { - "pk": "258", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Support library for libgcrypt", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "libgpg-error", - "arch": 3, - "pkgver": "1.6" - } - }, - { - "pk": "259", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "LDAP client libraries", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "libldap", - "arch": 3, - "pkgver": "2.3.39" - } - }, - { - "pk": "260", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A system-independent interface for user-level packet capture", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "libpcap", - "arch": 3, - "pkgver": "0.9.8" - } - }, - { - "pk": "261", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Cyrus Simple Authentication Service Layer (SASL) library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "libsasl", - "arch": 3, - "pkgver": "2.1.22" - } - }, - { - "pk": "262", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A generic library support script", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "libtool", - "arch": 3, - "pkgver": "2.2" - } - }, - { - "pk": "263", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library to enable user space application programs to communicate with USB devices", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "libusb", - "arch": 3, - "pkgver": "0.1.12" - } - }, - { - "pk": "264", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The standard licenses distribution package", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "licenses", - "arch": 3, - "pkgver": "2.3" - } - }, - { - "pk": "265", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A bootloader for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "lilo", - "arch": 3, - "pkgver": "22.8" - } - }, - { - "pk": "266", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A text WWW browser, similar to Lynx", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "links", - "arch": 3, - "pkgver": "2.1pre33" - } - }, - { - "pk": "267", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers and tools to support ATM networking under Linux.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "linux-atm", - "arch": 3, - "pkgver": "2.4.1" - } - }, - { - "pk": "268", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Rotates system logs automatically", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "logrotate", - "arch": 3, - "pkgver": "3.7.5" - } - }, - { - "pk": "269", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Logical Volume Manager 2 utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "lvm2", - "arch": 3, - "pkgver": "2.02.33" - } - }, - { - "pk": "270", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a portable lossless data compression library written in ANSI C", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "lzo2", - "arch": 3, - "pkgver": "2.02" - } - }, - { - "pk": "271", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "m4 macro processor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "m4", - "arch": 3, - "pkgver": "1.4.10" - } - }, - { - "pk": "272", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Madwifi drivers for Atheros wireless chipsets. For stock arch 2.6 kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "madwifi", - "arch": 3, - "pkgver": "0.9.4.3382" - } - }, - { - "pk": "273", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Userspace tools of madwifi drivers for Atheros wireless chipsets.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "madwifi-utils", - "arch": 3, - "pkgver": "0.9.4.3382" - } - }, - { - "pk": "274", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A commandline utility for sending email", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "mailx", - "arch": 3, - "pkgver": "8.1.1" - } - }, - { - "pk": "275", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU make utility to maintain groups of programs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "make", - "arch": 3, - "pkgver": "3.81" - } - }, - { - "pk": "276", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility for reading man pages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "man", - "arch": 3, - "pkgver": "1.6f" - } - }, - { - "pk": "277", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Linux man pages", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "man-pages", - "arch": 3, - "pkgver": "2.79" - } - }, - { - "pk": "278", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A tool for managing\/monitoring Linux md device arrays, also known as Software RAID", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "mdadm", - "arch": 3, - "pkgver": "2.6.4" - } - }, - { - "pk": "279", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Advanced, modular initramfs image creation utility", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "mkinitcpio", - "arch": 3, - "pkgver": "0.5.18.1" - } - }, - { - "pk": "280", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Faster merging drop-in for slocate", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "mlocate", - "arch": 3, - "pkgver": "0.18" - } - }, - { - "pk": "281", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing modules from the Linux kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "module-init-tools", - "arch": 3, - "pkgver": "3.2.2" - } - }, - { - "pk": "282", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "multiple-precision floating-point library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "mpfr", - "arch": 3, - "pkgver": "2.3.1" - } - }, - { - "pk": "283", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Pico editor clone with enhancements", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "nano", - "arch": 3, - "pkgver": "2.0.7" - } - }, - { - "pk": "284", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A System V Release 4.0 curses emulation library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "ncurses", - "arch": 3, - "pkgver": "5.6" - } - }, - { - "pk": "285", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Module for NDIS (Windows Network Drivers) drivers supplied by vendors. For stock arch 2.6 kernel.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "ndiswrapper", - "arch": 3, - "pkgver": "1.52" - } - }, - { - "pk": "286", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Binaries for ndiswrapper module", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "ndiswrapper-utils", - "arch": 3, - "pkgver": "1.52" - } - }, - { - "pk": "287", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Configuration tools for Linux networking", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "13", - "pkgname": "net-tools", - "arch": 3, - "pkgver": "1.60" - } - }, - { - "pk": "288", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Network configuration and profile scripts", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "netcfg", - "arch": 3, - "pkgver": "2.0.6" - } - }, - { - "pk": "289", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A telnet client (and server)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "7", - "pkgname": "netkit-telnet", - "arch": 3, - "pkgver": "0.17" - } - }, - { - "pk": "290", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Support programs for Network File Systems", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "nfs-utils", - "arch": 3, - "pkgver": "1.1.0" - } - }, - { - "pk": "291", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Library to help mapping IDs, mainly for NFSv4", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "nfsidmap", - "arch": 3, - "pkgver": "0.20" - } - }, - { - "pk": "292", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Third generation Linux NTFS driver", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "ntfs-3g", - "arch": 3, - "pkgver": "1.2310" - } - }, - { - "pk": "293", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "NTFS Resizing Tool", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "ntfsprogs", - "arch": 3, - "pkgver": "2.0.0" - } - }, - { - "pk": "294", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A Secure SHell server\/client", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "openssh", - "arch": 3, - "pkgver": "4.7p1" - } - }, - { - "pk": "295", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The Open Source toolkit for Secure Sockets Layer and Transport Layer Security", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "openssl", - "arch": 3, - "pkgver": "0.9.8g" - } - }, - { - "pk": "296", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Open Source implementation of IPsec for the Linux operating system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "openswan", - "arch": 3, - "pkgver": "2.4.11" - } - }, - { - "pk": "297", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "An easy-to-use, robust, and highly configurable VPN (Virtual Private Network)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "openvpn", - "arch": 3, - "pkgver": "2.0.9" - } - }, - { - "pk": "298", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library-based package manager with dependency support", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "pacman", - "arch": 3, - "pkgver": "3.1.4" - } - }, - { - "pk": "299", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "PAM (Pluggable Authentication Modules) library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "pam", - "arch": 3, - "pkgver": "0.99.9.0" - } - }, - { - "pk": "300", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility to apply patch files to original sources", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "patch", - "arch": 3, - "pkgver": "2.5.4" - } - }, - { - "pk": "301", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "PCI bus configuration space access library and tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "pciutils", - "arch": 3, - "pkgver": "2.2.8" - } - }, - { - "pk": "302", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for inserting and removing PCMCIA cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "pcmciautils", - "arch": 3, - "pkgver": "014" - } - }, - { - "pk": "303", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A library that implements Perl 5-style regular expressions", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "pcre", - "arch": 3, - "pkgver": "7.6" - } - }, - { - "pk": "304", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Practical Extraction and Report Language", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "perl", - "arch": 3, - "pkgver": "5.10.0" - } - }, - { - "pk": "305", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A system for managing library compile\/link flags", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "pkgconfig", - "arch": 3, - "pkgver": "0.22" - } - }, - { - "pk": "306", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A commandline option parser", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "popt", - "arch": 3, - "pkgver": "1.10.6" - } - }, - { - "pk": "307", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "RPC connection manager", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "portmap", - "arch": 3, - "pkgver": "6.0" - } - }, - { - "pk": "308", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A daemon which implements the PPP protocol for dial-up networking", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "6", - "pkgname": "ppp", - "arch": 3, - "pkgver": "2.4.4" - } - }, - { - "pk": "309", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Client for the proprietary Microsoft Point-to-Point Tunneling Protocol, PPTP.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "pptpclient", - "arch": 3, - "pkgver": "1.7.1" - } - }, - { - "pk": "310", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Displays useful information from \/proc", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "procinfo", - "arch": 3, - "pkgver": "19" - } - }, - { - "pk": "311", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities for monitoring your system and processes on your system", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "procps", - "arch": 3, - "pkgver": "3.2.7" - } - }, - { - "pk": "312", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Miscellaneous procfs tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "psmisc", - "arch": 3, - "pkgver": "22.6" - } - }, - { - "pk": "313", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU readline library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "7", - "pkgname": "readline", - "arch": 3, - "pkgver": "5.2" - } - }, - { - "pk": "314", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Reiserfs utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "reiserfsprogs", - "arch": 3, - "pkgver": "3.6.20" - } - }, - { - "pk": "315", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Roaring Penguin's Point-to-Point Protocol over Ethernet client", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "rp-pppoe", - "arch": 3, - "pkgver": "3.8" - } - }, - { - "pk": "316", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Drivers for rt2500 chipset wireless cards", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "21", - "pkgname": "rt2500", - "arch": 3, - "pkgver": "1.1.0_B4" - } - }, - { - "pk": "317", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the rt2x00 wireless drivers", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "rt2x00-rt61-fw", - "arch": 3, - "pkgver": "1.2" - } - }, - { - "pk": "318", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the rt2x00 wireless drivers", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "rt2x00-rt71w-fw", - "arch": 3, - "pkgver": "1.8" - } - }, - { - "pk": "319", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "An utility similar to hdparm but for SCSI devices", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "sdparm", - "arch": 3, - "pkgver": "1.02" - } - }, - { - "pk": "320", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "GNU stream editor", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "sed", - "arch": 3, - "pkgver": "4.1.5" - } - }, - { - "pk": "321", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Shadow password file utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "shadow", - "arch": 3, - "pkgver": "4.0.18.2" - } - }, - { - "pk": "322", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Give certain users the ability to run some commands as root", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "sudo", - "arch": 3, - "pkgver": "1.6.9p12" - } - }, - { - "pk": "323", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "System Utilities Based on Sysfs", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "sysfsutils", - "arch": 3, - "pkgver": "2.1.0" - } - }, - { - "pk": "324", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Next-generation syslogd with advanced networking and filtering capabilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "syslog-ng", - "arch": 3, - "pkgver": "2.0.6" - } - }, - { - "pk": "325", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Linux System V Init", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "sysvinit", - "arch": 3, - "pkgver": "2.86" - } - }, - { - "pk": "326", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utility used to store, backup, and transport files", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "tar", - "arch": 3, - "pkgver": "1.19" - } - }, - { - "pk": "327", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Monitors and Controls incoming TCP connections", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "8", - "pkgname": "tcp_wrappers", - "arch": 3, - "pkgver": "7.6" - } - }, - { - "pk": "328", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Utilities to work with and produce manuals, ASCII text, and on-line documentation from a single source file", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "texinfo", - "arch": 3, - "pkgver": "4.11" - } - }, - { - "pk": "329", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "OpenSource module for Texas Instruments ACX100\/ACX111 wireless chips. For stock arch 2.6 kernel", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "tiacx", - "arch": 3, - "pkgver": "20080210" - } - }, - { - "pk": "330", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for Texas Instruments ACX100\/ACX111 wireless chips.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "tiacx-firmware", - "arch": 3, - "pkgver": "2" - } - }, - { - "pk": "331", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Sources for time zone and daylight saving time data", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "tzdata", - "arch": 3, - "pkgver": "2008b" - } - }, - { - "pk": "332", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "The userspace dev tools (udev)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "udev", - "arch": 3, - "pkgver": "119" - } - }, - { - "pk": "333", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "USB Device Utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "5", - "pkgname": "usbutils", - "arch": 3, - "pkgver": "0.73" - } - }, - { - "pk": "334", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Miscellaneous system utilities for Linux", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "util-linux-ng", - "arch": 3, - "pkgver": "2.13.0.1" - } - }, - { - "pk": "335", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "a highly configurable, improved version of the vi text editor (basic version)", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "vi", - "arch": 3, - "pkgver": "7.1.267" - } - }, - { - "pk": "336", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "VPN client for cisco3000 VPN Concentrators", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "vpnc", - "arch": 3, - "pkgver": "0.5.1" - } - }, - { - "pk": "337", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A network utility to retrieve files from the Web", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "wget", - "arch": 3, - "pkgver": "1.11" - } - }, - { - "pk": "338", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility to show the full path of commands", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "which", - "arch": 3, - "pkgver": "2.19" - } - }, - { - "pk": "339", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Tools", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "wireless_tools", - "arch": 3, - "pkgver": "29" - } - }, - { - "pk": "340", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Lan usb modules. For kernel26.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "15", - "pkgname": "wlan-ng26", - "arch": 3, - "pkgver": "0.2.8" - } - }, - { - "pk": "341", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Wireless Lan userspace tools.", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "wlan-ng26-utils", - "arch": 3, - "pkgver": "0.2.8" - } - }, - { - "pk": "342", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A utility providing key negotiation for WPA wireless networks", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "wpa_supplicant", - "arch": 3, - "pkgver": "0.5.10" - } - }, - { - "pk": "343", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "XFS filesystem utilities", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "1", - "pkgname": "xfsprogs", - "arch": 3, - "pkgver": "2.9.7" - } - }, - { - "pk": "344", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "xinetd is a secure replacement for inetd", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "3", - "pkgname": "xinetd", - "arch": 3, - "pkgver": "2.3.14" - } - }, - { - "pk": "345", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "Firmware for the in-kernel26 zd1211rw wireless driver", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "2", - "pkgname": "zd1211-firmware", - "arch": 3, - "pkgver": "1.4" - } - }, - { - "pk": "346", - "model": "main.package", - "fields": { - "maintainer": 1, - "pkgdesc": "A compression\/decompression Library", - "url": "", - "needupdate": 0, - "last_update": "2008-04-18 03:03:05", - "repo": 1, - "pkgrel": "4", - "pkgname": "zlib", - "arch": 3, - "pkgver": "1.2.3" - } - }, - { - "pk": "1", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 1 - } - }, - { - "pk": "2", - "model": "main.packagedepend", - "fields": { - "depname": "rsync", - "depvcmp": "", - "pkg": 1 - } - }, - { - "pk": "3", - "model": "main.packagedepend", - "fields": { - "depname": "attr", - "depvcmp": ">=2.4.41", - "pkg": 2 - } - }, - { - "pk": "4", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.4-1", - "pkg": 3 - } - }, - { - "pk": "5", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<2.6.25", - "pkg": 3 - } - }, - { - "pk": "6", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 4 - } - }, - { - "pk": "7", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 5 - } - }, - { - "pk": "8", - "model": "main.packagedepend", - "fields": { - "depname": "m4", - "depvcmp": "", - "pkg": 5 - } - }, - { - "pk": "9", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 5 - } - }, - { - "pk": "10", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 5 - } - }, - { - "pk": "11", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 6 - } - }, - { - "pk": "12", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 6 - } - }, - { - "pk": "13", - "model": "main.packagedepend", - "fields": { - "depname": "readline", - "depvcmp": ">=5.2", - "pkg": 7 - } - }, - { - "pk": "14", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 7 - } - }, - { - "pk": "15", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 8 - } - }, - { - "pk": "16", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 9 - } - }, - { - "pk": "17", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7", - "pkg": 10 - } - }, - { - "pk": "18", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 11 - } - }, - { - "pk": "19", - "model": "main.packagedepend", - "fields": { - "depname": "m4", - "depvcmp": "", - "pkg": 11 - } - }, - { - "pk": "20", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 12 - } - }, - { - "pk": "21", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 13 - } - }, - { - "pk": "22", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 14 - } - }, - { - "pk": "23", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 14 - } - }, - { - "pk": "24", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7-7", - "pkg": 15 - } - }, - { - "pk": "25", - "model": "main.packagedepend", - "fields": { - "depname": "shadow", - "depvcmp": ">=4.0.18.2-2", - "pkg": 15 - } - }, - { - "pk": "26", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": ">=0.99.9.0-2", - "pkg": 15 - } - }, - { - "pk": "27", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": ">=2.2.45-2", - "pkg": 15 - } - }, - { - "pk": "28", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 16 - } - }, - { - "pk": "29", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 17 - } - }, - { - "pk": "30", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 18 - } - }, - { - "pk": "31", - "model": "main.packagedepend", - "fields": { - "depname": "libgcrypt", - "depvcmp": "", - "pkg": 18 - } - }, - { - "pk": "32", - "model": "main.packagedepend", - "fields": { - "depname": "popt", - "depvcmp": "", - "pkg": 18 - } - }, - { - "pk": "33", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 18 - } - }, - { - "pk": "34", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 19 - } - }, - { - "pk": "35", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 19 - } - }, - { - "pk": "36", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 19 - } - }, - { - "pk": "37", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 21 - } - }, - { - "pk": "38", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 21 - } - }, - { - "pk": "39", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 22 - } - }, - { - "pk": "40", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 23 - } - }, - { - "pk": "41", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 24 - } - }, - { - "pk": "42", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 25 - } - }, - { - "pk": "43", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 26 - } - }, - { - "pk": "44", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 27 - } - }, - { - "pk": "45", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 28 - } - }, - { - "pk": "46", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8e", - "pkg": 29 - } - }, - { - "pk": "47", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 30 - } - }, - { - "pk": "48", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 31 - } - }, - { - "pk": "49", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 32 - } - }, - { - "pk": "50", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 33 - } - }, - { - "pk": "51", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 34 - } - }, - { - "pk": "52", - "model": "main.packagedepend", - "fields": { - "depname": "filesystem", - "depvcmp": "", - "pkg": 34 - } - }, - { - "pk": "53", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 34 - } - }, - { - "pk": "54", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 34 - } - }, - { - "pk": "55", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 35 - } - }, - { - "pk": "56", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 35 - } - }, - { - "pk": "57", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 37 - } - }, - { - "pk": "58", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 38 - } - }, - { - "pk": "59", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 38 - } - }, - { - "pk": "60", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 39 - } - }, - { - "pk": "61", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 40 - } - }, - { - "pk": "62", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 40 - } - }, - { - "pk": "63", - "model": "main.packagedepend", - "fields": { - "depname": "binutils", - "depvcmp": ">=2.18-3", - "pkg": 41 - } - }, - { - "pk": "64", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": ">=4.3.0", - "pkg": 41 - } - }, - { - "pk": "65", - "model": "main.packagedepend", - "fields": { - "depname": "mpfr", - "depvcmp": ">=2.3.1", - "pkg": 41 - } - }, - { - "pk": "66", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7", - "pkg": 42 - } - }, - { - "pk": "67", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 43 - } - }, - { - "pk": "68", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 44 - } - }, - { - "pk": "69", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 45 - } - }, - { - "pk": "70", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": "", - "pkg": 45 - } - }, - { - "pk": "71", - "model": "main.packagedepend", - "fields": { - "depname": "pcre", - "depvcmp": ">=7.6-3", - "pkg": 46 - } - }, - { - "pk": "72", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 47 - } - }, - { - "pk": "73", - "model": "main.packagedepend", - "fields": { - "depname": "kernel-headers", - "depvcmp": ">=2.6.24.3", - "pkg": 47 - } - }, - { - "pk": "74", - "model": "main.packagedepend", - "fields": { - "depname": "tzdata", - "depvcmp": "", - "pkg": 47 - } - }, - { - "pk": "75", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 48 - } - }, - { - "pk": "76", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 49 - } - }, - { - "pk": "77", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 50 - } - }, - { - "pk": "78", - "model": "main.packagedepend", - "fields": { - "depname": "pcre", - "depvcmp": "", - "pkg": 50 - } - }, - { - "pk": "79", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 51 - } - }, - { - "pk": "80", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 51 - } - }, - { - "pk": "81", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 52 - } - }, - { - "pk": "82", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 52 - } - }, - { - "pk": "83", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 52 - } - }, - { - "pk": "84", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 53 - } - }, - { - "pk": "85", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 53 - } - }, - { - "pk": "86", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 54 - } - }, - { - "pk": "87", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 55 - } - }, - { - "pk": "88", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 55 - } - }, - { - "pk": "89", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 55 - } - }, - { - "pk": "90", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 56 - } - }, - { - "pk": "91", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 56 - } - }, - { - "pk": "92", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 56 - } - }, - { - "pk": "93", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 56 - } - }, - { - "pk": "94", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 56 - } - }, - { - "pk": "95", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 57 - } - }, - { - "pk": "96", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "97", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "98", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "99", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "100", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "101", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "102", - "model": "main.packagedepend", - "fields": { - "depname": "udev", - "depvcmp": ">=118", - "pkg": 58 - } - }, - { - "pk": "103", - "model": "main.packagedepend", - "fields": { - "depname": "net-tools", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "104", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 58 - } - }, - { - "pk": "105", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 59 - } - }, - { - "pk": "106", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 60 - } - }, - { - "pk": "107", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 61 - } - }, - { - "pk": "108", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 62 - } - }, - { - "pk": "109", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 63 - } - }, - { - "pk": "110", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 64 - } - }, - { - "pk": "111", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 64 - } - }, - { - "pk": "112", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 64 - } - }, - { - "pk": "113", - "model": "main.packagedepend", - "fields": { - "depname": "ipw3945-ucode", - "depvcmp": "", - "pkg": 64 - } - }, - { - "pk": "114", - "model": "main.packagedepend", - "fields": { - "depname": "ipw3945d", - "depvcmp": "", - "pkg": 64 - } - }, - { - "pk": "115", - "model": "main.packagedepend", - "fields": { - "depname": "udev", - "depvcmp": "", - "pkg": 65 - } - }, - { - "pk": "116", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 66 - } - }, - { - "pk": "117", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 67 - } - }, - { - "pk": "118", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 70 - } - }, - { - "pk": "119", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 71 - } - }, - { - "pk": "120", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 73 - } - }, - { - "pk": "121", - "model": "main.packagedepend", - "fields": { - "depname": "module-init-tools", - "depvcmp": "", - "pkg": 73 - } - }, - { - "pk": "122", - "model": "main.packagedepend", - "fields": { - "depname": "mkinitcpio", - "depvcmp": ">=0.5.18", - "pkg": 73 - } - }, - { - "pk": "123", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 75 - } - }, - { - "pk": "124", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 76 - } - }, - { - "pk": "125", - "model": "main.packagedepend", - "fields": { - "depname": "kbd", - "depvcmp": "", - "pkg": 76 - } - }, - { - "pk": "126", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 77 - } - }, - { - "pk": "127", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 78 - } - }, - { - "pk": "128", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 78 - } - }, - { - "pk": "129", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 79 - } - }, - { - "pk": "130", - "model": "main.packagedepend", - "fields": { - "depname": "file", - "depvcmp": "", - "pkg": 79 - } - }, - { - "pk": "131", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 80 - } - }, - { - "pk": "132", - "model": "main.packagedepend", - "fields": { - "depname": "bzip2", - "depvcmp": "", - "pkg": 80 - } - }, - { - "pk": "133", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": "", - "pkg": 80 - } - }, - { - "pk": "134", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 81 - } - }, - { - "pk": "135", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 82 - } - }, - { - "pk": "136", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 83 - } - }, - { - "pk": "137", - "model": "main.packagedepend", - "fields": { - "depname": "libgpg-error", - "depvcmp": ">=1.6", - "pkg": 84 - } - }, - { - "pk": "138", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 85 - } - }, - { - "pk": "139", - "model": "main.packagedepend", - "fields": { - "depname": "libsasl", - "depvcmp": "", - "pkg": 86 - } - }, - { - "pk": "140", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8f", - "pkg": 86 - } - }, - { - "pk": "141", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 87 - } - }, - { - "pk": "142", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 88 - } - }, - { - "pk": "143", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 89 - } - }, - { - "pk": "144", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 90 - } - }, - { - "pk": "145", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 92 - } - }, - { - "pk": "146", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 92 - } - }, - { - "pk": "147", - "model": "main.packagedepend", - "fields": { - "depname": "bzip2", - "depvcmp": "", - "pkg": 93 - } - }, - { - "pk": "148", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 93 - } - }, - { - "pk": "149", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 93 - } - }, - { - "pk": "150", - "model": "main.packagedepend", - "fields": { - "depname": "gpm", - "depvcmp": "", - "pkg": 93 - } - }, - { - "pk": "151", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 94 - } - }, - { - "pk": "152", - "model": "main.packagedepend", - "fields": { - "depname": "popt", - "depvcmp": "", - "pkg": 95 - } - }, - { - "pk": "153", - "model": "main.packagedepend", - "fields": { - "depname": "cron", - "depvcmp": "", - "pkg": 95 - } - }, - { - "pk": "154", - "model": "main.packagedepend", - "fields": { - "depname": "gzip", - "depvcmp": "", - "pkg": 95 - } - }, - { - "pk": "155", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": ">=1.02.22", - "pkg": 96 - } - }, - { - "pk": "156", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 97 - } - }, - { - "pk": "157", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 98 - } - }, - { - "pk": "158", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 98 - } - }, - { - "pk": "159", - "model": "main.packagedepend", - "fields": { - "depname": "madwifi-utils", - "depvcmp": "", - "pkg": 99 - } - }, - { - "pk": "160", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 99 - } - }, - { - "pk": "161", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 99 - } - }, - { - "pk": "162", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 100 - } - }, - { - "pk": "163", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 101 - } - }, - { - "pk": "164", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 102 - } - }, - { - "pk": "165", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 102 - } - }, - { - "pk": "166", - "model": "main.packagedepend", - "fields": { - "depname": "groff", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "167", - "model": "main.packagedepend", - "fields": { - "depname": "less", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "168", - "model": "main.packagedepend", - "fields": { - "depname": "gzip", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "169", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "170", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "171", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "172", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 103 - } - }, - { - "pk": "173", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 105 - } - }, - { - "pk": "174", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-5", - "pkg": 106 - } - }, - { - "pk": "175", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-extras", - "depvcmp": ">=2.4", - "pkg": 106 - } - }, - { - "pk": "176", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-udev", - "depvcmp": ">=116-3", - "pkg": 106 - } - }, - { - "pk": "177", - "model": "main.packagedepend", - "fields": { - "depname": "gen-init-cpio", - "depvcmp": "", - "pkg": 106 - } - }, - { - "pk": "178", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-module-init-tools", - "depvcmp": "", - "pkg": 106 - } - }, - { - "pk": "179", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 106 - } - }, - { - "pk": "180", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 106 - } - }, - { - "pk": "181", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-kbd", - "depvcmp": "", - "pkg": 106 - } - }, - { - "pk": "182", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 107 - } - }, - { - "pk": "183", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 108 - } - }, - { - "pk": "184", - "model": "main.packagedepend", - "fields": { - "depname": "gmp", - "depvcmp": ">=4.2.2", - "pkg": 109 - } - }, - { - "pk": "185", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 110 - } - }, - { - "pk": "186", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 110 - } - }, - { - "pk": "187", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 111 - } - }, - { - "pk": "188", - "model": "main.packagedepend", - "fields": { - "depname": "ndiswrapper-utils", - "depvcmp": "=1.52", - "pkg": 112 - } - }, - { - "pk": "189", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 112 - } - }, - { - "pk": "190", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 112 - } - }, - { - "pk": "191", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 113 - } - }, - { - "pk": "192", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 113 - } - }, - { - "pk": "193", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 114 - } - }, - { - "pk": "194", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 115 - } - }, - { - "pk": "195", - "model": "main.packagedepend", - "fields": { - "depname": "wpa_supplicant", - "depvcmp": "", - "pkg": 115 - } - }, - { - "pk": "196", - "model": "main.packagedepend", - "fields": { - "depname": "net-tools", - "depvcmp": "", - "pkg": 115 - } - }, - { - "pk": "197", - "model": "main.packagedepend", - "fields": { - "depname": "mktemp", - "depvcmp": "", - "pkg": 115 - } - }, - { - "pk": "198", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 116 - } - }, - { - "pk": "199", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 117 - } - }, - { - "pk": "200", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 117 - } - }, - { - "pk": "201", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 117 - } - }, - { - "pk": "202", - "model": "main.packagedepend", - "fields": { - "depname": "portmap", - "depvcmp": "", - "pkg": 117 - } - }, - { - "pk": "203", - "model": "main.packagedepend", - "fields": { - "depname": "nfsidmap", - "depvcmp": "", - "pkg": 117 - } - }, - { - "pk": "204", - "model": "main.packagedepend", - "fields": { - "depname": "libevent", - "depvcmp": ">=1.3e", - "pkg": 117 - } - }, - { - "pk": "205", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 118 - } - }, - { - "pk": "206", - "model": "main.packagedepend", - "fields": { - "depname": "libldap", - "depvcmp": "", - "pkg": 118 - } - }, - { - "pk": "207", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 119 - } - }, - { - "pk": "208", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 120 - } - }, - { - "pk": "209", - "model": "main.packagedepend", - "fields": { - "depname": "fuse", - "depvcmp": "", - "pkg": 120 - } - }, - { - "pk": "210", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 120 - } - }, - { - "pk": "211", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8g", - "pkg": 121 - } - }, - { - "pk": "212", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 121 - } - }, - { - "pk": "213", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 121 - } - }, - { - "pk": "214", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 121 - } - }, - { - "pk": "215", - "model": "main.packagedepend", - "fields": { - "depname": "heimdal", - "depvcmp": "", - "pkg": 121 - } - }, - { - "pk": "216", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 122 - } - }, - { - "pk": "217", - "model": "main.packagedepend", - "fields": { - "depname": "iproute", - "depvcmp": "", - "pkg": 123 - } - }, - { - "pk": "218", - "model": "main.packagedepend", - "fields": { - "depname": "gmp", - "depvcmp": "", - "pkg": 123 - } - }, - { - "pk": "219", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 123 - } - }, - { - "pk": "220", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 124 - } - }, - { - "pk": "221", - "model": "main.packagedepend", - "fields": { - "depname": "lzo2", - "depvcmp": "", - "pkg": 124 - } - }, - { - "pk": "222", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 125 - } - }, - { - "pk": "223", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 125 - } - }, - { - "pk": "224", - "model": "main.packagedepend", - "fields": { - "depname": "libarchive", - "depvcmp": ">=2.4.17", - "pkg": 125 - } - }, - { - "pk": "225", - "model": "main.packagedepend", - "fields": { - "depname": "libdownload", - "depvcmp": ">=1.3", - "pkg": 125 - } - }, - { - "pk": "226", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 126 - } - }, - { - "pk": "227", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 126 - } - }, - { - "pk": "228", - "model": "main.packagedepend", - "fields": { - "depname": "cracklib", - "depvcmp": "", - "pkg": 126 - } - }, - { - "pk": "229", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 127 - } - }, - { - "pk": "230", - "model": "main.packagedepend", - "fields": { - "depname": "ed", - "depvcmp": "", - "pkg": 127 - } - }, - { - "pk": "231", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 128 - } - }, - { - "pk": "232", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 129 - } - }, - { - "pk": "233", - "model": "main.packagedepend", - "fields": { - "depname": "sysfsutils", - "depvcmp": "", - "pkg": 129 - } - }, - { - "pk": "234", - "model": "main.packagedepend", - "fields": { - "depname": "module-init-tools", - "depvcmp": ">=3.2pre9", - "pkg": 129 - } - }, - { - "pk": "235", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 130 - } - }, - { - "pk": "236", - "model": "main.packagedepend", - "fields": { - "depname": "gdbm", - "depvcmp": "", - "pkg": 131 - } - }, - { - "pk": "237", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 131 - } - }, - { - "pk": "238", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 131 - } - }, - { - "pk": "239", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 131 - } - }, - { - "pk": "240", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 131 - } - }, - { - "pk": "241", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 132 - } - }, - { - "pk": "242", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 133 - } - }, - { - "pk": "243", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 134 - } - }, - { - "pk": "244", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 135 - } - }, - { - "pk": "245", - "model": "main.packagedepend", - "fields": { - "depname": "libpcap", - "depvcmp": ">=0.9.8", - "pkg": 135 - } - }, - { - "pk": "246", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 136 - } - }, - { - "pk": "247", - "model": "main.packagedepend", - "fields": { - "depname": "ppp", - "depvcmp": "", - "pkg": 136 - } - }, - { - "pk": "248", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 137 - } - }, - { - "pk": "249", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 137 - } - }, - { - "pk": "250", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 137 - } - }, - { - "pk": "251", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 138 - } - }, - { - "pk": "252", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 139 - } - }, - { - "pk": "253", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 139 - } - }, - { - "pk": "254", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 140 - } - }, - { - "pk": "255", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 140 - } - }, - { - "pk": "256", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 141 - } - }, - { - "pk": "257", - "model": "main.packagedepend", - "fields": { - "depname": "ppp", - "depvcmp": "", - "pkg": 142 - } - }, - { - "pk": "258", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 143 - } - }, - { - "pk": "259", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 143 - } - }, - { - "pk": "260", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 146 - } - }, - { - "pk": "261", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 147 - } - }, - { - "pk": "262", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 148 - } - }, - { - "pk": "263", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 149 - } - }, - { - "pk": "264", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 149 - } - }, - { - "pk": "265", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 150 - } - }, - { - "pk": "266", - "model": "main.packagedepend", - "fields": { - "depname": "logrotate", - "depvcmp": "", - "pkg": 151 - } - }, - { - "pk": "267", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 151 - } - }, - { - "pk": "268", - "model": "main.packagedepend", - "fields": { - "depname": "shadow", - "depvcmp": "", - "pkg": 152 - } - }, - { - "pk": "269", - "model": "main.packagedepend", - "fields": { - "depname": "util-linux", - "depvcmp": "", - "pkg": 152 - } - }, - { - "pk": "270", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 152 - } - }, - { - "pk": "271", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 152 - } - }, - { - "pk": "272", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 152 - } - }, - { - "pk": "273", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 153 - } - }, - { - "pk": "274", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 153 - } - }, - { - "pk": "275", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 154 - } - }, - { - "pk": "276", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 154 - } - }, - { - "pk": "277", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 155 - } - }, - { - "pk": "278", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 156 - } - }, - { - "pk": "279", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 156 - } - }, - { - "pk": "280", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<2.6.25", - "pkg": 156 - } - }, - { - "pk": "281", - "model": "main.packagedepend", - "fields": { - "depname": "tiacx-firmware", - "depvcmp": "", - "pkg": 156 - } - }, - { - "pk": "282", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 159 - } - }, - { - "pk": "283", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 159 - } - }, - { - "pk": "284", - "model": "main.packagedepend", - "fields": { - "depname": "util-linux", - "depvcmp": "", - "pkg": 159 - } - }, - { - "pk": "285", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 160 - } - }, - { - "pk": "286", - "model": "main.packagedepend", - "fields": { - "depname": "libusb", - "depvcmp": "", - "pkg": 160 - } - }, - { - "pk": "287", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 161 - } - }, - { - "pk": "288", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 161 - } - }, - { - "pk": "289", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 161 - } - }, - { - "pk": "290", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 161 - } - }, - { - "pk": "291", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 162 - } - }, - { - "pk": "292", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 162 - } - }, - { - "pk": "293", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 162 - } - }, - { - "pk": "294", - "model": "main.packagedepend", - "fields": { - "depname": "libgcrypt", - "depvcmp": "", - "pkg": 163 - } - }, - { - "pk": "295", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 163 - } - }, - { - "pk": "296", - "model": "main.packagedepend", - "fields": { - "depname": "iproute", - "depvcmp": "", - "pkg": 163 - } - }, - { - "pk": "297", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 164 - } - }, - { - "pk": "298", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 164 - } - }, - { - "pk": "299", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 165 - } - }, - { - "pk": "300", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 166 - } - }, - { - "pk": "301", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 167 - } - }, - { - "pk": "302", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 167 - } - }, - { - "pk": "303", - "model": "main.packagedepend", - "fields": { - "depname": "wlan-ng26-utils", - "depvcmp": "", - "pkg": 167 - } - }, - { - "pk": "304", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 168 - } - }, - { - "pk": "305", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 168 - } - }, - { - "pk": "306", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 169 - } - }, - { - "pk": "307", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 170 - } - }, - { - "pk": "308", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 171 - } - }, - { - "pk": "309", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 171 - } - }, - { - "pk": "310", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 173 - } - }, - { - "pk": "311", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 174 - } - }, - { - "pk": "312", - "model": "main.packagedepend", - "fields": { - "depname": "rsync", - "depvcmp": "", - "pkg": 174 - } - }, - { - "pk": "313", - "model": "main.packagedepend", - "fields": { - "depname": "attr", - "depvcmp": ">=2.4.41", - "pkg": 175 - } - }, - { - "pk": "314", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.4-1", - "pkg": 176 - } - }, - { - "pk": "315", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<2.6.25", - "pkg": 176 - } - }, - { - "pk": "316", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 177 - } - }, - { - "pk": "317", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 178 - } - }, - { - "pk": "318", - "model": "main.packagedepend", - "fields": { - "depname": "m4", - "depvcmp": "", - "pkg": 178 - } - }, - { - "pk": "319", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 178 - } - }, - { - "pk": "320", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 178 - } - }, - { - "pk": "321", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 179 - } - }, - { - "pk": "322", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 179 - } - }, - { - "pk": "323", - "model": "main.packagedepend", - "fields": { - "depname": "readline", - "depvcmp": ">=5.2", - "pkg": 180 - } - }, - { - "pk": "324", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 180 - } - }, - { - "pk": "325", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 181 - } - }, - { - "pk": "326", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 182 - } - }, - { - "pk": "327", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7", - "pkg": 183 - } - }, - { - "pk": "328", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 184 - } - }, - { - "pk": "329", - "model": "main.packagedepend", - "fields": { - "depname": "m4", - "depvcmp": "", - "pkg": 184 - } - }, - { - "pk": "330", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 185 - } - }, - { - "pk": "331", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 186 - } - }, - { - "pk": "332", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 187 - } - }, - { - "pk": "333", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 187 - } - }, - { - "pk": "334", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7-7", - "pkg": 188 - } - }, - { - "pk": "335", - "model": "main.packagedepend", - "fields": { - "depname": "shadow", - "depvcmp": ">=4.0.18.2-2", - "pkg": 188 - } - }, - { - "pk": "336", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": ">=0.99.9.0-2", - "pkg": 188 - } - }, - { - "pk": "337", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": ">=2.2.45-2", - "pkg": 188 - } - }, - { - "pk": "338", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 189 - } - }, - { - "pk": "339", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 190 - } - }, - { - "pk": "340", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 191 - } - }, - { - "pk": "341", - "model": "main.packagedepend", - "fields": { - "depname": "libgcrypt", - "depvcmp": "", - "pkg": 191 - } - }, - { - "pk": "342", - "model": "main.packagedepend", - "fields": { - "depname": "popt", - "depvcmp": "", - "pkg": 191 - } - }, - { - "pk": "343", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 191 - } - }, - { - "pk": "344", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 192 - } - }, - { - "pk": "345", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 192 - } - }, - { - "pk": "346", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 192 - } - }, - { - "pk": "347", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 194 - } - }, - { - "pk": "348", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 194 - } - }, - { - "pk": "349", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 195 - } - }, - { - "pk": "350", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 196 - } - }, - { - "pk": "351", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 197 - } - }, - { - "pk": "352", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 198 - } - }, - { - "pk": "353", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 199 - } - }, - { - "pk": "354", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 200 - } - }, - { - "pk": "355", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 201 - } - }, - { - "pk": "356", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8e", - "pkg": 202 - } - }, - { - "pk": "357", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 203 - } - }, - { - "pk": "358", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 204 - } - }, - { - "pk": "359", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 205 - } - }, - { - "pk": "360", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 206 - } - }, - { - "pk": "361", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 207 - } - }, - { - "pk": "362", - "model": "main.packagedepend", - "fields": { - "depname": "filesystem", - "depvcmp": "", - "pkg": 207 - } - }, - { - "pk": "363", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 207 - } - }, - { - "pk": "364", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 207 - } - }, - { - "pk": "365", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 208 - } - }, - { - "pk": "366", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 208 - } - }, - { - "pk": "367", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 210 - } - }, - { - "pk": "368", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 211 - } - }, - { - "pk": "369", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 211 - } - }, - { - "pk": "370", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 212 - } - }, - { - "pk": "371", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 213 - } - }, - { - "pk": "372", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 213 - } - }, - { - "pk": "373", - "model": "main.packagedepend", - "fields": { - "depname": "binutils", - "depvcmp": ">=2.18-3", - "pkg": 214 - } - }, - { - "pk": "374", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": ">=4.3.0", - "pkg": 214 - } - }, - { - "pk": "375", - "model": "main.packagedepend", - "fields": { - "depname": "mpfr", - "depvcmp": ">=2.3.1", - "pkg": 214 - } - }, - { - "pk": "376", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": ">=2.7", - "pkg": 215 - } - }, - { - "pk": "377", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 216 - } - }, - { - "pk": "378", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 217 - } - }, - { - "pk": "379", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 218 - } - }, - { - "pk": "380", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": "", - "pkg": 218 - } - }, - { - "pk": "381", - "model": "main.packagedepend", - "fields": { - "depname": "pcre", - "depvcmp": ">=7.6-3", - "pkg": 219 - } - }, - { - "pk": "382", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 220 - } - }, - { - "pk": "383", - "model": "main.packagedepend", - "fields": { - "depname": "kernel-headers", - "depvcmp": ">=2.6.24.3", - "pkg": 220 - } - }, - { - "pk": "384", - "model": "main.packagedepend", - "fields": { - "depname": "tzdata", - "depvcmp": "", - "pkg": 220 - } - }, - { - "pk": "385", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 221 - } - }, - { - "pk": "386", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 222 - } - }, - { - "pk": "387", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 223 - } - }, - { - "pk": "388", - "model": "main.packagedepend", - "fields": { - "depname": "pcre", - "depvcmp": "", - "pkg": 223 - } - }, - { - "pk": "389", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 224 - } - }, - { - "pk": "390", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 224 - } - }, - { - "pk": "391", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 225 - } - }, - { - "pk": "392", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 225 - } - }, - { - "pk": "393", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 225 - } - }, - { - "pk": "394", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 226 - } - }, - { - "pk": "395", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 226 - } - }, - { - "pk": "396", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 227 - } - }, - { - "pk": "397", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 228 - } - }, - { - "pk": "398", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 228 - } - }, - { - "pk": "399", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 228 - } - }, - { - "pk": "400", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 229 - } - }, - { - "pk": "401", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 229 - } - }, - { - "pk": "402", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 229 - } - }, - { - "pk": "403", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 229 - } - }, - { - "pk": "404", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 229 - } - }, - { - "pk": "405", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 230 - } - }, - { - "pk": "406", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "407", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "408", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "409", - "model": "main.packagedepend", - "fields": { - "depname": "grep", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "410", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "411", - "model": "main.packagedepend", - "fields": { - "depname": "sed", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "412", - "model": "main.packagedepend", - "fields": { - "depname": "udev", - "depvcmp": ">=118", - "pkg": 231 - } - }, - { - "pk": "413", - "model": "main.packagedepend", - "fields": { - "depname": "net-tools", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "414", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 231 - } - }, - { - "pk": "415", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 232 - } - }, - { - "pk": "416", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 233 - } - }, - { - "pk": "417", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 234 - } - }, - { - "pk": "418", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 235 - } - }, - { - "pk": "419", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 236 - } - }, - { - "pk": "420", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 237 - } - }, - { - "pk": "421", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 237 - } - }, - { - "pk": "422", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 237 - } - }, - { - "pk": "423", - "model": "main.packagedepend", - "fields": { - "depname": "ipw3945-ucode", - "depvcmp": "", - "pkg": 237 - } - }, - { - "pk": "424", - "model": "main.packagedepend", - "fields": { - "depname": "ipw3945d", - "depvcmp": "", - "pkg": 237 - } - }, - { - "pk": "425", - "model": "main.packagedepend", - "fields": { - "depname": "udev", - "depvcmp": "", - "pkg": 238 - } - }, - { - "pk": "426", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 239 - } - }, - { - "pk": "427", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 240 - } - }, - { - "pk": "428", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 243 - } - }, - { - "pk": "429", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 244 - } - }, - { - "pk": "430", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 246 - } - }, - { - "pk": "431", - "model": "main.packagedepend", - "fields": { - "depname": "module-init-tools", - "depvcmp": "", - "pkg": 246 - } - }, - { - "pk": "432", - "model": "main.packagedepend", - "fields": { - "depname": "mkinitcpio", - "depvcmp": ">=0.5.18", - "pkg": 246 - } - }, - { - "pk": "433", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 248 - } - }, - { - "pk": "434", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 249 - } - }, - { - "pk": "435", - "model": "main.packagedepend", - "fields": { - "depname": "kbd", - "depvcmp": "", - "pkg": 249 - } - }, - { - "pk": "436", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 250 - } - }, - { - "pk": "437", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 251 - } - }, - { - "pk": "438", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-4", - "pkg": 251 - } - }, - { - "pk": "439", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 252 - } - }, - { - "pk": "440", - "model": "main.packagedepend", - "fields": { - "depname": "file", - "depvcmp": "", - "pkg": 252 - } - }, - { - "pk": "441", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 253 - } - }, - { - "pk": "442", - "model": "main.packagedepend", - "fields": { - "depname": "bzip2", - "depvcmp": "", - "pkg": 253 - } - }, - { - "pk": "443", - "model": "main.packagedepend", - "fields": { - "depname": "acl", - "depvcmp": "", - "pkg": 253 - } - }, - { - "pk": "444", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 254 - } - }, - { - "pk": "445", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 255 - } - }, - { - "pk": "446", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 256 - } - }, - { - "pk": "447", - "model": "main.packagedepend", - "fields": { - "depname": "libgpg-error", - "depvcmp": ">=1.6", - "pkg": 257 - } - }, - { - "pk": "448", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 258 - } - }, - { - "pk": "449", - "model": "main.packagedepend", - "fields": { - "depname": "libsasl", - "depvcmp": "", - "pkg": 259 - } - }, - { - "pk": "450", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8f", - "pkg": 259 - } - }, - { - "pk": "451", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 260 - } - }, - { - "pk": "452", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 261 - } - }, - { - "pk": "453", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 262 - } - }, - { - "pk": "454", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 263 - } - }, - { - "pk": "455", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": "", - "pkg": 265 - } - }, - { - "pk": "456", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 265 - } - }, - { - "pk": "457", - "model": "main.packagedepend", - "fields": { - "depname": "bzip2", - "depvcmp": "", - "pkg": 266 - } - }, - { - "pk": "458", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 266 - } - }, - { - "pk": "459", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 266 - } - }, - { - "pk": "460", - "model": "main.packagedepend", - "fields": { - "depname": "gpm", - "depvcmp": "", - "pkg": 266 - } - }, - { - "pk": "461", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 267 - } - }, - { - "pk": "462", - "model": "main.packagedepend", - "fields": { - "depname": "popt", - "depvcmp": "", - "pkg": 268 - } - }, - { - "pk": "463", - "model": "main.packagedepend", - "fields": { - "depname": "cron", - "depvcmp": "", - "pkg": 268 - } - }, - { - "pk": "464", - "model": "main.packagedepend", - "fields": { - "depname": "gzip", - "depvcmp": "", - "pkg": 268 - } - }, - { - "pk": "465", - "model": "main.packagedepend", - "fields": { - "depname": "device-mapper", - "depvcmp": ">=1.02.22", - "pkg": 269 - } - }, - { - "pk": "466", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 270 - } - }, - { - "pk": "467", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 271 - } - }, - { - "pk": "468", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 271 - } - }, - { - "pk": "469", - "model": "main.packagedepend", - "fields": { - "depname": "madwifi-utils", - "depvcmp": "", - "pkg": 272 - } - }, - { - "pk": "470", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 272 - } - }, - { - "pk": "471", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 272 - } - }, - { - "pk": "472", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 273 - } - }, - { - "pk": "473", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 274 - } - }, - { - "pk": "474", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 275 - } - }, - { - "pk": "475", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 275 - } - }, - { - "pk": "476", - "model": "main.packagedepend", - "fields": { - "depname": "groff", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "477", - "model": "main.packagedepend", - "fields": { - "depname": "less", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "478", - "model": "main.packagedepend", - "fields": { - "depname": "gzip", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "479", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "480", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "481", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "482", - "model": "main.packagedepend", - "fields": { - "depname": "diffutils", - "depvcmp": "", - "pkg": 276 - } - }, - { - "pk": "483", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 278 - } - }, - { - "pk": "484", - "model": "main.packagedepend", - "fields": { - "depname": "klibc", - "depvcmp": ">=1.5-5", - "pkg": 279 - } - }, - { - "pk": "485", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-extras", - "depvcmp": ">=2.4", - "pkg": 279 - } - }, - { - "pk": "486", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-udev", - "depvcmp": ">=116-3", - "pkg": 279 - } - }, - { - "pk": "487", - "model": "main.packagedepend", - "fields": { - "depname": "gen-init-cpio", - "depvcmp": "", - "pkg": 279 - } - }, - { - "pk": "488", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-module-init-tools", - "depvcmp": "", - "pkg": 279 - } - }, - { - "pk": "489", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 279 - } - }, - { - "pk": "490", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 279 - } - }, - { - "pk": "491", - "model": "main.packagedepend", - "fields": { - "depname": "klibc-kbd", - "depvcmp": "", - "pkg": 279 - } - }, - { - "pk": "492", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 280 - } - }, - { - "pk": "493", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 281 - } - }, - { - "pk": "494", - "model": "main.packagedepend", - "fields": { - "depname": "gmp", - "depvcmp": ">=4.2.2", - "pkg": 282 - } - }, - { - "pk": "495", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 283 - } - }, - { - "pk": "496", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 283 - } - }, - { - "pk": "497", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 284 - } - }, - { - "pk": "498", - "model": "main.packagedepend", - "fields": { - "depname": "ndiswrapper-utils", - "depvcmp": "=1.52", - "pkg": 285 - } - }, - { - "pk": "499", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 285 - } - }, - { - "pk": "500", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 285 - } - }, - { - "pk": "501", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 286 - } - }, - { - "pk": "502", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 286 - } - }, - { - "pk": "503", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 287 - } - }, - { - "pk": "504", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 288 - } - }, - { - "pk": "505", - "model": "main.packagedepend", - "fields": { - "depname": "wpa_supplicant", - "depvcmp": "", - "pkg": 288 - } - }, - { - "pk": "506", - "model": "main.packagedepend", - "fields": { - "depname": "net-tools", - "depvcmp": "", - "pkg": 288 - } - }, - { - "pk": "507", - "model": "main.packagedepend", - "fields": { - "depname": "mktemp", - "depvcmp": "", - "pkg": 288 - } - }, - { - "pk": "508", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 289 - } - }, - { - "pk": "509", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 290 - } - }, - { - "pk": "510", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 290 - } - }, - { - "pk": "511", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 290 - } - }, - { - "pk": "512", - "model": "main.packagedepend", - "fields": { - "depname": "portmap", - "depvcmp": "", - "pkg": 290 - } - }, - { - "pk": "513", - "model": "main.packagedepend", - "fields": { - "depname": "nfsidmap", - "depvcmp": "", - "pkg": 290 - } - }, - { - "pk": "514", - "model": "main.packagedepend", - "fields": { - "depname": "libevent", - "depvcmp": ">=1.3e", - "pkg": 290 - } - }, - { - "pk": "515", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 291 - } - }, - { - "pk": "516", - "model": "main.packagedepend", - "fields": { - "depname": "libldap", - "depvcmp": "", - "pkg": 291 - } - }, - { - "pk": "517", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 292 - } - }, - { - "pk": "518", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 293 - } - }, - { - "pk": "519", - "model": "main.packagedepend", - "fields": { - "depname": "fuse", - "depvcmp": "", - "pkg": 293 - } - }, - { - "pk": "520", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 293 - } - }, - { - "pk": "521", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": ">=0.9.8g", - "pkg": 294 - } - }, - { - "pk": "522", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 294 - } - }, - { - "pk": "523", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 294 - } - }, - { - "pk": "524", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 294 - } - }, - { - "pk": "525", - "model": "main.packagedepend", - "fields": { - "depname": "heimdal", - "depvcmp": "", - "pkg": 294 - } - }, - { - "pk": "526", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 295 - } - }, - { - "pk": "527", - "model": "main.packagedepend", - "fields": { - "depname": "iproute", - "depvcmp": "", - "pkg": 296 - } - }, - { - "pk": "528", - "model": "main.packagedepend", - "fields": { - "depname": "gmp", - "depvcmp": "", - "pkg": 296 - } - }, - { - "pk": "529", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 296 - } - }, - { - "pk": "530", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 297 - } - }, - { - "pk": "531", - "model": "main.packagedepend", - "fields": { - "depname": "lzo2", - "depvcmp": "", - "pkg": 297 - } - }, - { - "pk": "532", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 298 - } - }, - { - "pk": "533", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 298 - } - }, - { - "pk": "534", - "model": "main.packagedepend", - "fields": { - "depname": "libarchive", - "depvcmp": ">=2.4.17", - "pkg": 298 - } - }, - { - "pk": "535", - "model": "main.packagedepend", - "fields": { - "depname": "libdownload", - "depvcmp": ">=1.3", - "pkg": 298 - } - }, - { - "pk": "536", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 299 - } - }, - { - "pk": "537", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 299 - } - }, - { - "pk": "538", - "model": "main.packagedepend", - "fields": { - "depname": "cracklib", - "depvcmp": "", - "pkg": 299 - } - }, - { - "pk": "539", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 300 - } - }, - { - "pk": "540", - "model": "main.packagedepend", - "fields": { - "depname": "ed", - "depvcmp": "", - "pkg": 300 - } - }, - { - "pk": "541", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 301 - } - }, - { - "pk": "542", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 302 - } - }, - { - "pk": "543", - "model": "main.packagedepend", - "fields": { - "depname": "sysfsutils", - "depvcmp": "", - "pkg": 302 - } - }, - { - "pk": "544", - "model": "main.packagedepend", - "fields": { - "depname": "module-init-tools", - "depvcmp": ">=3.2pre9", - "pkg": 302 - } - }, - { - "pk": "545", - "model": "main.packagedepend", - "fields": { - "depname": "gcc-libs", - "depvcmp": "", - "pkg": 303 - } - }, - { - "pk": "546", - "model": "main.packagedepend", - "fields": { - "depname": "gdbm", - "depvcmp": "", - "pkg": 304 - } - }, - { - "pk": "547", - "model": "main.packagedepend", - "fields": { - "depname": "db", - "depvcmp": ">=4.6", - "pkg": 304 - } - }, - { - "pk": "548", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 304 - } - }, - { - "pk": "549", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 304 - } - }, - { - "pk": "550", - "model": "main.packagedepend", - "fields": { - "depname": "sh", - "depvcmp": "", - "pkg": 304 - } - }, - { - "pk": "551", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 305 - } - }, - { - "pk": "552", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 306 - } - }, - { - "pk": "553", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 307 - } - }, - { - "pk": "554", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 308 - } - }, - { - "pk": "555", - "model": "main.packagedepend", - "fields": { - "depname": "libpcap", - "depvcmp": ">=0.9.8", - "pkg": 308 - } - }, - { - "pk": "556", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 309 - } - }, - { - "pk": "557", - "model": "main.packagedepend", - "fields": { - "depname": "ppp", - "depvcmp": "", - "pkg": 309 - } - }, - { - "pk": "558", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 310 - } - }, - { - "pk": "559", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 310 - } - }, - { - "pk": "560", - "model": "main.packagedepend", - "fields": { - "depname": "perl", - "depvcmp": "", - "pkg": 310 - } - }, - { - "pk": "561", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 311 - } - }, - { - "pk": "562", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 312 - } - }, - { - "pk": "563", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 312 - } - }, - { - "pk": "564", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 313 - } - }, - { - "pk": "565", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 313 - } - }, - { - "pk": "566", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 314 - } - }, - { - "pk": "567", - "model": "main.packagedepend", - "fields": { - "depname": "ppp", - "depvcmp": "", - "pkg": 315 - } - }, - { - "pk": "568", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 316 - } - }, - { - "pk": "569", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 316 - } - }, - { - "pk": "570", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 319 - } - }, - { - "pk": "571", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 320 - } - }, - { - "pk": "572", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 321 - } - }, - { - "pk": "573", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 322 - } - }, - { - "pk": "574", - "model": "main.packagedepend", - "fields": { - "depname": "pam", - "depvcmp": "", - "pkg": 322 - } - }, - { - "pk": "575", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 323 - } - }, - { - "pk": "576", - "model": "main.packagedepend", - "fields": { - "depname": "logrotate", - "depvcmp": "", - "pkg": 324 - } - }, - { - "pk": "577", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 324 - } - }, - { - "pk": "578", - "model": "main.packagedepend", - "fields": { - "depname": "shadow", - "depvcmp": "", - "pkg": 325 - } - }, - { - "pk": "579", - "model": "main.packagedepend", - "fields": { - "depname": "util-linux", - "depvcmp": "", - "pkg": 325 - } - }, - { - "pk": "580", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 325 - } - }, - { - "pk": "581", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 325 - } - }, - { - "pk": "582", - "model": "main.packagedepend", - "fields": { - "depname": "awk", - "depvcmp": "", - "pkg": 325 - } - }, - { - "pk": "583", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 326 - } - }, - { - "pk": "584", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 326 - } - }, - { - "pk": "585", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 327 - } - }, - { - "pk": "586", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 327 - } - }, - { - "pk": "587", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 328 - } - }, - { - "pk": "588", - "model": "main.packagedepend", - "fields": { - "depname": "wireless_tools", - "depvcmp": "", - "pkg": 329 - } - }, - { - "pk": "589", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 329 - } - }, - { - "pk": "590", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<2.6.25", - "pkg": 329 - } - }, - { - "pk": "591", - "model": "main.packagedepend", - "fields": { - "depname": "tiacx-firmware", - "depvcmp": "", - "pkg": 329 - } - }, - { - "pk": "592", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 332 - } - }, - { - "pk": "593", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 332 - } - }, - { - "pk": "594", - "model": "main.packagedepend", - "fields": { - "depname": "util-linux", - "depvcmp": "", - "pkg": 332 - } - }, - { - "pk": "595", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 333 - } - }, - { - "pk": "596", - "model": "main.packagedepend", - "fields": { - "depname": "libusb", - "depvcmp": "", - "pkg": 333 - } - }, - { - "pk": "597", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 334 - } - }, - { - "pk": "598", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 334 - } - }, - { - "pk": "599", - "model": "main.packagedepend", - "fields": { - "depname": "zlib", - "depvcmp": "", - "pkg": 334 - } - }, - { - "pk": "600", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 334 - } - }, - { - "pk": "601", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 335 - } - }, - { - "pk": "602", - "model": "main.packagedepend", - "fields": { - "depname": "ncurses", - "depvcmp": "", - "pkg": 335 - } - }, - { - "pk": "603", - "model": "main.packagedepend", - "fields": { - "depname": "coreutils", - "depvcmp": "", - "pkg": 335 - } - }, - { - "pk": "604", - "model": "main.packagedepend", - "fields": { - "depname": "libgcrypt", - "depvcmp": "", - "pkg": 336 - } - }, - { - "pk": "605", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 336 - } - }, - { - "pk": "606", - "model": "main.packagedepend", - "fields": { - "depname": "iproute", - "depvcmp": "", - "pkg": 336 - } - }, - { - "pk": "607", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 337 - } - }, - { - "pk": "608", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 337 - } - }, - { - "pk": "609", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 338 - } - }, - { - "pk": "610", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 339 - } - }, - { - "pk": "611", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": ">=2.6.24.3-4", - "pkg": 340 - } - }, - { - "pk": "612", - "model": "main.packagedepend", - "fields": { - "depname": "kernel26", - "depvcmp": "<=2.6.25-0", - "pkg": 340 - } - }, - { - "pk": "613", - "model": "main.packagedepend", - "fields": { - "depname": "wlan-ng26-utils", - "depvcmp": "", - "pkg": 340 - } - }, - { - "pk": "614", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 341 - } - }, - { - "pk": "615", - "model": "main.packagedepend", - "fields": { - "depname": "bash", - "depvcmp": "", - "pkg": 341 - } - }, - { - "pk": "616", - "model": "main.packagedepend", - "fields": { - "depname": "openssl", - "depvcmp": "", - "pkg": 342 - } - }, - { - "pk": "617", - "model": "main.packagedepend", - "fields": { - "depname": "e2fsprogs", - "depvcmp": "", - "pkg": 343 - } - }, - { - "pk": "618", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 344 - } - }, - { - "pk": "619", - "model": "main.packagedepend", - "fields": { - "depname": "tcp_wrappers", - "depvcmp": "", - "pkg": 344 - } - }, - { - "pk": "620", - "model": "main.packagedepend", - "fields": { - "depname": "glibc", - "depvcmp": "", - "pkg": 346 - } - } -] diff --git a/main/log.py b/main/log.py new file mode 100644 index 00000000..5c745cc8 --- /dev/null +++ b/main/log.py @@ -0,0 +1,70 @@ +# Derived from Django snippets: http://djangosnippets.org/snippets/2242/ +from collections import OrderedDict +from datetime import datetime, timedelta +from hashlib import md5 +import traceback +from pytz import utc + + +class LimitedSizeDict(OrderedDict): + def __init__(self, *args, **kwargs): + self.size_limit = kwargs.pop('size', None) + if self.size_limit == 0: + self.size_limit = None + if self.size_limit and self.size_limit < 0: + raise Exception('Invalid size specified') + super(LimitedSizeDict, self).__init__(*args, **kwargs) + self.check_item_limits() + + def __setitem__(self, key, value): + # delete and add to ensure it ends up at the end of the linked list + if key in self: + super(LimitedSizeDict, self).__delitem__(key) + super(LimitedSizeDict, self).__setitem__(key, value) + self.check_item_limits() + + def check_item_limits(self): + if self.size_limit is None: + return + while len(self) > self.size_limit: + self.popitem(last=False) + + +class RateLimitFilter(object): + def __init__(self, name='', rate=10, prefix='error_rate', max_keys=100): + # delayed import otherwise we have a circular dep when setting up + # the logging config: settings -> logging -> cache -> settings + self.cache_module = __import__('django.core.cache', fromlist=['cache']) + self.errors = LimitedSizeDict(size=max_keys) + self.rate = rate + self.prefix = prefix + + def filter(self, record): + if self.rate == 0: + # rate == 0 means totally unfiltered + return True + + trace = '\n'.join(traceback.format_exception(*record.exc_info)) + key = md5(trace).hexdigest() + cache = self.cache_module.cache + + # Test if the cache works + try: + cache.set(self.prefix, 1, 300) + use_cache = (cache.get(self.prefix) == 1) + except: + use_cache = False + + if use_cache: + cache_key = '%s_%s' % (self.prefix, key) + duplicate = (cache.get(cache_key) == 1) + cache.set(cache_key, 1, self.rate) + else: + now = datetime.utcnow().replace(tzinfo=utc) + min_date = now - timedelta(seconds=self.rate) + duplicate = (key in self.errors and self.errors[key] >= min_date) + self.errors[key] = now + + return not duplicate + +# vim: set ts=4 sw=4 et: diff --git a/main/middleware.py b/main/middleware.py deleted file mode 100644 index f893c795..00000000 --- a/main/middleware.py +++ /dev/null @@ -1,52 +0,0 @@ -# begin copy of stock Django UpdateCacheMiddleware -# this is to address feeds caching issue which makes it horribly -# unperformant - -from django.conf import settings -from django.core.cache import cache -from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age - -class UpdateCacheMiddleware(object): - """ - Response-phase cache middleware that updates the cache if the response is - cacheable. - - Must be used as part of the two-part update/fetch cache middleware. - UpdateCacheMiddleware must be the first piece of middleware in - MIDDLEWARE_CLASSES so that it'll get called last during the response phase. - """ - def __init__(self): - self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS - self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX - self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) - - def process_response(self, request, response): - """Sets the cache, if needed.""" - if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache: - # We don't need to update the cache, just return. - return response - if request.method != 'GET': - # This is a stronger requirement than above. It is needed - # because of interactions between this middleware and the - # HTTPMiddleware, which throws the body of a HEAD-request - # away before this middleware gets a chance to cache it. - return response - if not response.status_code == 200: - return response - # Try to get the timeout from the "max-age" section of the "Cache- - # Control" header before reverting to using the default cache_timeout - # length. - timeout = get_max_age(response) - if timeout == None: - timeout = self.cache_timeout - elif timeout == 0: - # max-age was set to 0, don't bother caching. - return response - patch_response_headers(response, timeout) - if timeout: - response.content = response.content - cache_key = learn_cache_key(request, response, timeout, self.key_prefix) - cache.set(cache_key, response, timeout) - return response - -# vim: set ts=4 sw=4 et: diff --git a/main/migrations/0001_initial.py b/main/migrations/0001_initial.py index 4c89d8a0..8349d4b9 100644 --- a/main/migrations/0001_initial.py +++ b/main/migrations/0001_initial.py @@ -1,440 +1,119 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals -from south.db import db -from django.db import models -from main.models import * +from django.db import models, migrations +import main.fields +import django.db.models.deletion +from django.conf import settings -class Migration: - - def forwards(self, orm): - - # Adding model 'PackageDepend' - db.create_table('package_depends', ( - ('id', orm['main.PackageDepend:id']), - ('pkg', orm['main.PackageDepend:pkg']), - ('depname', orm['main.PackageDepend:depname']), - ('depvcmp', orm['main.PackageDepend:depvcmp']), - )) - db.send_create_signal('main', ['PackageDepend']) - - # Adding model 'Press' - db.create_table('press', ( - ('id', orm['main.Press:id']), - ('name', orm['main.Press:name']), - ('url', orm['main.Press:url']), - )) - db.send_create_signal('main', ['Press']) - - # Adding model 'MirrorUrl' - db.create_table('main_mirrorurl', ( - ('id', orm['main.MirrorUrl:id']), - ('url', orm['main.MirrorUrl:url']), - ('protocol', orm['main.MirrorUrl:protocol']), - ('mirror', orm['main.MirrorUrl:mirror']), - )) - db.send_create_signal('main', ['MirrorUrl']) - - # Adding model 'MirrorRsync' - db.create_table('main_mirrorrsync', ( - ('id', orm['main.MirrorRsync:id']), - ('hostname', orm['main.MirrorRsync:hostname']), - ('ip', orm['main.MirrorRsync:ip']), - ('mirror', orm['main.MirrorRsync:mirror']), - )) - db.send_create_signal('main', ['MirrorRsync']) - - # Adding model 'AltForum' - db.create_table('alt_forums', ( - ('id', orm['main.AltForum:id']), - ('language', orm['main.AltForum:language']), - ('url', orm['main.AltForum:url']), - ('name', orm['main.AltForum:name']), - )) - db.send_create_signal('main', ['AltForum']) - - # Adding model 'Signoff' - db.create_table('main_signoff', ( - ('id', orm['main.Signoff:id']), - ('pkg', orm['main.Signoff:pkg']), - ('pkgver', orm['main.Signoff:pkgver']), - ('pkgrel', orm['main.Signoff:pkgrel']), - ('packager', orm['main.Signoff:packager']), - )) - db.send_create_signal('main', ['Signoff']) - - # Adding model 'UserProfile' - db.create_table('user_profiles', ( - ('id', orm['main.UserProfile:id']), - ('notify', orm['main.UserProfile:notify']), - ('alias', orm['main.UserProfile:alias']), - ('public_email', orm['main.UserProfile:public_email']), - ('other_contact', orm['main.UserProfile:other_contact']), - ('website', orm['main.UserProfile:website']), - ('yob', orm['main.UserProfile:yob']), - ('location', orm['main.UserProfile:location']), - ('languages', orm['main.UserProfile:languages']), - ('interests', orm['main.UserProfile:interests']), - ('occupation', orm['main.UserProfile:occupation']), - ('roles', orm['main.UserProfile:roles']), - ('favorite_distros', orm['main.UserProfile:favorite_distros']), - ('picture', orm['main.UserProfile:picture']), - ('user', orm['main.UserProfile:user']), - )) - db.send_create_signal('main', ['UserProfile']) - - # Adding model 'Arch' - db.create_table('arches', ( - ('id', orm['main.Arch:id']), - ('name', orm['main.Arch:name']), - )) - db.send_create_signal('main', ['Arch']) - - # Adding model 'PackageFile' - db.create_table('package_files', ( - ('id', orm['main.PackageFile:id']), - ('pkg', orm['main.PackageFile:pkg']), - ('path', orm['main.PackageFile:path']), - )) - db.send_create_signal('main', ['PackageFile']) - - # Adding model 'Todolist' - db.create_table('todolists', ( - ('id', orm['main.Todolist:id']), - ('creator', orm['main.Todolist:creator']), - ('name', orm['main.Todolist:name']), - ('description', orm['main.Todolist:description']), - ('date_added', orm['main.Todolist:date_added']), - )) - db.send_create_signal('main', ['Todolist']) - - # Adding model 'TodolistPkg' - db.create_table('todolist_pkgs', ( - ('id', orm['main.TodolistPkg:id']), - ('list', orm['main.TodolistPkg:list']), - ('pkg', orm['main.TodolistPkg:pkg']), - ('complete', orm['main.TodolistPkg:complete']), - )) - db.send_create_signal('main', ['TodolistPkg']) - - # Adding model 'Donor' - db.create_table('donors', ( - ('id', orm['main.Donor:id']), - ('name', orm['main.Donor:name']), - )) - db.send_create_signal('main', ['Donor']) - - # Adding model 'Package' - db.create_table('packages', ( - ('id', orm['main.Package:id']), - ('repo', orm['main.Package:repo']), - ('arch', orm['main.Package:arch']), - ('maintainer', orm['main.Package:maintainer']), - ('needupdate', orm['main.Package:needupdate']), - ('pkgname', orm['main.Package:pkgname']), - ('pkgbase', orm['main.Package:pkgbase']), - ('pkgver', orm['main.Package:pkgver']), - ('pkgrel', orm['main.Package:pkgrel']), - ('pkgdesc', orm['main.Package:pkgdesc']), - ('url', orm['main.Package:url']), - ('last_update', orm['main.Package:last_update']), - ('license', orm['main.Package:license']), - )) - db.send_create_signal('main', ['Package']) - - # Adding model 'Repo' - db.create_table('repos', ( - ('id', orm['main.Repo:id']), - ('name', orm['main.Repo:name']), - )) - db.send_create_signal('main', ['Repo']) - - # Adding model 'Mirror' - db.create_table('main_mirror', ( - ('id', orm['main.Mirror:id']), - ('name', orm['main.Mirror:name']), - ('country', orm['main.Mirror:country']), - ('admin_email', orm['main.Mirror:admin_email']), - ('notes', orm['main.Mirror:notes']), - ('public', orm['main.Mirror:public']), - ('active', orm['main.Mirror:active']), - ('isos', orm['main.Mirror:isos']), - )) - db.send_create_signal('main', ['Mirror']) - - # Adding model 'MirrorProtocol' - db.create_table('main_mirrorprotocol', ( - ('id', orm['main.MirrorProtocol:id']), - ('protocol', orm['main.MirrorProtocol:protocol']), - )) - db.send_create_signal('main', ['MirrorProtocol']) - - # Adding model 'ExternalProject' - db.create_table('main_externalproject', ( - ('id', orm['main.ExternalProject:id']), - ('url', orm['main.ExternalProject:url']), - ('name', orm['main.ExternalProject:name']), - ('description', orm['main.ExternalProject:description']), - )) - db.send_create_signal('main', ['ExternalProject']) - - # Adding model 'News' - db.create_table('news', ( - ('id', orm['main.News:id']), - ('author', orm['main.News:author']), - ('postdate', orm['main.News:postdate']), - ('title', orm['main.News:title']), - ('content', orm['main.News:content']), - )) - db.send_create_signal('main', ['News']) - - # Adding ManyToManyField 'UserProfile.allowed_repos' - db.create_table('user_profiles_allowed_repos', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('userprofile', models.ForeignKey(orm.UserProfile, null=False)), - ('repo', models.ForeignKey(orm.Repo, null=False)) - )) - - # Creating unique_together for [list, pkg] on TodolistPkg. - db.create_unique('todolist_pkgs', ['list_id', 'pkg_id']) - - - - def backwards(self, orm): - - # Deleting unique_together for [list, pkg] on TodolistPkg. - db.delete_unique('todolist_pkgs', ['list_id', 'pkg_id']) - - # Deleting model 'PackageDepend' - db.delete_table('package_depends') - - # Deleting model 'Press' - db.delete_table('press') - - # Deleting model 'MirrorUrl' - db.delete_table('main_mirrorurl') - - # Deleting model 'MirrorRsync' - db.delete_table('main_mirrorrsync') - - # Deleting model 'AltForum' - db.delete_table('alt_forums') - - # Deleting model 'Signoff' - db.delete_table('main_signoff') - - # Deleting model 'UserProfile' - db.delete_table('user_profiles') - - # Deleting model 'Arch' - db.delete_table('arches') - - # Deleting model 'PackageFile' - db.delete_table('package_files') - - # Deleting model 'Todolist' - db.delete_table('todolists') - - # Deleting model 'TodolistPkg' - db.delete_table('todolist_pkgs') - - # Deleting model 'Donor' - db.delete_table('donors') - - # Deleting model 'Package' - db.delete_table('packages') - - # Deleting model 'Repo' - db.delete_table('repos') - - # Deleting model 'Mirror' - db.delete_table('main_mirror') - - # Deleting model 'MirrorProtocol' - db.delete_table('main_mirrorprotocol') - - # Deleting model 'ExternalProject' - db.delete_table('main_externalproject') - - # Deleting model 'News' - db.delete_table('news') - - # Dropping ManyToManyField 'UserProfile.allowed_repos' - db.delete_table('user_profiles_allowed_repos') - - - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'maintained_packages'", 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Arch', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(unique=True, max_length=255)), + ('agnostic', models.BooleanField(default=False, help_text=b'Is this architecture non-platform specific?')), + ('required_signoffs', models.PositiveIntegerField(default=2, help_text=b'Number of signoffs required for packages of this architecture')), + ], + options={ + 'ordering': ('name',), + 'db_table': 'arches', + 'verbose_name_plural': 'arches', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Donor', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(unique=True, max_length=255)), + ('visible', models.BooleanField(default=True, help_text=b'Should we show this donor on the public page?')), + ('created', models.DateTimeField()), + ], + options={ + 'ordering': ('name',), + 'db_table': 'donors', + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Package', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgname', models.CharField(max_length=255)), + ('pkgbase', models.CharField(max_length=255, db_index=True)), + ('pkgver', models.CharField(max_length=255)), + ('pkgrel', models.CharField(max_length=255)), + ('epoch', models.PositiveIntegerField(default=0)), + ('pkgdesc', models.TextField(null=True, verbose_name=b'description')), + ('url', models.CharField(max_length=255, null=True, verbose_name=b'URL')), + ('filename', models.CharField(max_length=255)), + ('compressed_size', main.fields.PositiveBigIntegerField()), + ('installed_size', main.fields.PositiveBigIntegerField()), + ('build_date', models.DateTimeField(null=True)), + ('last_update', models.DateTimeField(db_index=True)), + ('files_last_update', models.DateTimeField(null=True, blank=True)), + ('created', models.DateTimeField()), + ('packager_str', models.CharField(max_length=255, verbose_name=b'packager string')), + ('signature_bytes', models.BinaryField(verbose_name=b'PGP signature', null=True)), + ('flag_date', models.DateTimeField(null=True, blank=True)), + ('arch', models.ForeignKey(related_name=b'packages', on_delete=django.db.models.deletion.PROTECT, to='main.Arch')), + ('packager', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True)), + ], + options={ + 'ordering': ('pkgname',), + 'db_table': 'packages', + 'get_latest_by': 'last_update', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PackageFile', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('is_directory', models.BooleanField(default=False)), + ('directory', models.CharField(max_length=1024)), + ('filename', models.CharField(max_length=1024, null=True, blank=True)), + ('pkg', models.ForeignKey(to='main.Package')), + ], + options={ + 'db_table': 'package_files', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Repo', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(unique=True, max_length=255)), + ('testing', models.BooleanField(default=False, help_text=b'Is this repo meant for package testing?')), + ('staging', models.BooleanField(default=False, help_text=b'Is this repo meant for package staging?')), + ('bugs_project', models.SmallIntegerField(default=1, help_text=b'Flyspray project ID for this repository.')), + ('bugs_category', models.SmallIntegerField(default=2, help_text=b'Flyspray category ID for this repository.')), + ('svn_root', models.CharField(help_text=b'SVN root (e.g. path) for this repository.', max_length=64)), + ], + options={ + 'ordering': ('name',), + 'db_table': 'repos', + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='package', + name='repo', + field=models.ForeignKey(related_name=b'packages', on_delete=django.db.models.deletion.PROTECT, to='main.Repo'), + preserve_default=True, + ), + migrations.AlterUniqueTogether( + name='package', + unique_together=set([('pkgname', 'repo', 'arch')]), + ), + ] diff --git a/main/migrations/0002_make_maintainer_nullable.py b/main/migrations/0002_make_maintainer_nullable.py deleted file mode 100644 index 138b103b..00000000 --- a/main/migrations/0002_make_maintainer_nullable.py +++ /dev/null @@ -1,199 +0,0 @@ - -from south.db import db -from django.db import models -from main.models import * - -class Migration: - - def forwards(self, orm): - - # Changing field 'Package.maintainer' - # (to signature: django.db.models.fields.related.ForeignKey(null=True, to=orm['auth.User'])) - db.alter_column('packages', 'maintainer_id', orm['main.package:maintainer']) - - - - def backwards(self, orm): - - # Changing field 'Package.maintainer' - # (to signature: django.db.models.fields.related.ForeignKey(to=orm['auth.User'])) - db.alter_column('packages', 'maintainer_id', orm['main.package:maintainer']) - - - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0003_migrate_maintainer.py b/main/migrations/0003_migrate_maintainer.py deleted file mode 100644 index a3a4793f..00000000 --- a/main/migrations/0003_migrate_maintainer.py +++ /dev/null @@ -1,195 +0,0 @@ - -from south.db import db -from django.db import models -from main.models import * - -class Migration: - - no_dry_run = True - - def forwards(self, orm): - orm.Package.objects.filter(maintainer=0).update(maintainer=None) - - - def backwards(self, orm): - # This will fail if foreign keys are in effect. Let's hope we'll - # never have to go backwards. :P - orm.Package.objects.filter(maintainer=None).update(maintainer=0) - - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0004_add_pkgname_index.py b/main/migrations/0004_add_pkgname_index.py deleted file mode 100644 index aeb85b2e..00000000 --- a/main/migrations/0004_add_pkgname_index.py +++ /dev/null @@ -1,209 +0,0 @@ - -from south.db import db -from django.db import models -from main.models import * - -class Migration: - - def forwards(self, orm): - - # Changing field 'Package.maintainer' - # (to signature: django.db.models.fields.related.ForeignKey(blank=True, null=True, to=orm['auth.User'])) - db.alter_column('packages', 'maintainer_id', orm['main.package:maintainer']) - - # Changing field 'Package.pkgname' - # (to signature: django.db.models.fields.CharField(max_length=255, db_index=True)) - db.alter_column('packages', 'pkgname', orm['main.package:pkgname']) - - db.create_index('packages', ['pkgname']) - - - def backwards(self, orm): - - # Changing field 'Package.maintainer' - # (to signature: django.db.models.fields.related.ForeignKey(null=True, to=orm['auth.User'])) - db.alter_column('packages', 'maintainer_id', orm['main.package:maintainer']) - - # Changing field 'Package.pkgname' - # (to signature: django.db.models.fields.CharField(max_length=255)) - db.alter_column('packages', 'pkgname', orm['main.package:pkgname']) - - db.delete_index('packages', ['pkgname']) - - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0005_fix_empty_url_pkgdesc.py b/main/migrations/0005_fix_empty_url_pkgdesc.py deleted file mode 100644 index c7cc1d8c..00000000 --- a/main/migrations/0005_fix_empty_url_pkgdesc.py +++ /dev/null @@ -1,211 +0,0 @@ - -from south.db import db -from django.db import models -from main.models import * - -class Migration: - - no_dry_run = True - - def forwards(self, orm): - "Write your forwards migration here" - for p in orm.Package.objects.filter(pkgdesc=''): - p.pkgdesc = None - p.save() - for p in orm.Package.objects.filter(pkgdesc='None'): - p.pkgdesc = None - p.save() - for p in orm.Package.objects.filter(url=''): - p.url = None - p.save() - for p in orm.Package.objects.filter(url='None'): - p.url= None - p.save() - - - def backwards(self, orm): - "Write your backwards migration here" - for p in orm.Package.objects.filter(pkgdesc=None): - p.pkgdesc = '' - p.save() - for p in orm.Package.objects.filter(url=None): - p.url = '' - p.save() - - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0006_add_more_info_to_packages.py b/main/migrations/0006_add_more_info_to_packages.py deleted file mode 100644 index 5a2a1cd0..00000000 --- a/main/migrations/0006_add_more_info_to_packages.py +++ /dev/null @@ -1,201 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - - def forwards(self, orm): - # Adding field 'Package.compressed_size' - db.add_column('packages', 'compressed_size', orm['main.package:compressed_size']) - # Adding field 'Package.installed_size' - db.add_column('packages', 'installed_size', orm['main.package:installed_size']) - # Adding field 'Package.build_date' - db.add_column('packages', 'build_date', orm['main.package:build_date']) - - def backwards(self, orm): - # Deleting field 'Package.compressed_size' - db.delete_column('packages', 'compressed_size') - # Deleting field 'Package.installed_size' - db.delete_column('packages', 'installed_size') - # Deleting field 'Package.build_date' - db.delete_column('packages', 'build_date') - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0007_add_files_last_update.py b/main/migrations/0007_add_files_last_update.py deleted file mode 100644 index 36f99c26..00000000 --- a/main/migrations/0007_add_files_last_update.py +++ /dev/null @@ -1,193 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Adding field 'Package.files_last_update' - db.add_column('packages', 'files_last_update', orm['main.package:files_last_update']) - - def backwards(self, orm): - # Deleting field 'Package.files_last_update' - db.delete_column('packages', 'files_last_update') - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0008_mirror_tiering.py b/main/migrations/0008_mirror_tiering.py deleted file mode 100644 index 3993289e..00000000 --- a/main/migrations/0008_mirror_tiering.py +++ /dev/null @@ -1,199 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Adding field 'Mirror.tier' - db.add_column('main_mirror', 'tier', orm['main.mirror:tier']) - # Adding field 'Mirror.upstream' - db.add_column('main_mirror', 'upstream', orm['main.mirror:upstream']) - - def backwards(self, orm): - # Deleting field 'Mirror.tier' - db.delete_column('main_mirror', 'tier') - # Deleting field 'Mirror.upstream' - db.delete_column('main_mirror', 'upstream_id') - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0009_mirror_rsync_credentials.py b/main/migrations/0009_mirror_rsync_credentials.py deleted file mode 100644 index bbfc9d61..00000000 --- a/main/migrations/0009_mirror_rsync_credentials.py +++ /dev/null @@ -1,201 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Adding field 'Mirror.rsync_user' - db.add_column('main_mirror', 'rsync_user', orm['main.mirror:rsync_user']) - # Adding field 'Mirror.rsync_password' - db.add_column('main_mirror', 'rsync_password', orm['main.mirror:rsync_password']) - - def backwards(self, orm): - # Deleting field 'Mirror.rsync_user' - db.delete_column('main_mirror', 'rsync_user') - # Deleting field 'Mirror.rsync_password' - db.delete_column('main_mirror', 'rsync_password') - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0010_kill_rsync_ip_hostname.py b/main/migrations/0010_kill_rsync_ip_hostname.py deleted file mode 100644 index 105fcede..00000000 --- a/main/migrations/0010_kill_rsync_ip_hostname.py +++ /dev/null @@ -1,196 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Deleting field 'MirrorRsync.hostname' - db.delete_column('main_mirrorrsync', 'hostname') - - def backwards(self, orm): - # Adding field 'MirrorRsync.hostname' - db.add_column('main_mirrorrsync', 'hostname', orm['main.mirrorrsync:hostname']) - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0011_mirror_notes_text_field.py b/main/migrations/0011_mirror_notes_text_field.py deleted file mode 100644 index cb6347de..00000000 --- a/main/migrations/0011_mirror_notes_text_field.py +++ /dev/null @@ -1,198 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Changing field 'Mirror.notes' - # (to signature: django.db.models.fields.TextField(blank=True)) - db.alter_column('main_mirror', 'notes', orm['main.mirror:notes']) - - def backwards(self, orm): - # Changing field 'Mirror.notes' - # (to signature: django.db.models.fields.CharField(max_length=255, blank=True)) - db.alter_column('main_mirror', 'notes', orm['main.mirror:notes']) - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0012_is_repo_testing.py b/main/migrations/0012_is_repo_testing.py deleted file mode 100644 index b7a98b4a..00000000 --- a/main/migrations/0012_is_repo_testing.py +++ /dev/null @@ -1,194 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Adding field 'Repo.testing' - db.add_column('repos', 'testing', orm['main.repo:testing']) - - def backwards(self, orm): - # Deleting field 'Repo.testing' - db.delete_column('repos', 'testing') - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0013_mark_repos_testing.py b/main/migrations/0013_mark_repos_testing.py deleted file mode 100644 index 617a3ab8..00000000 --- a/main/migrations/0013_mark_repos_testing.py +++ /dev/null @@ -1,194 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - no_dry_run = True - - def forwards(self, orm): - orm.Repo.objects.filter(name__endswith="Testing").update(testing=True) - - def backwards(self, orm): - pass - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0014_mirror_notes_rsync_optional.py b/main/migrations/0014_mirror_notes_rsync_optional.py deleted file mode 100644 index 21d13627..00000000 --- a/main/migrations/0014_mirror_notes_rsync_optional.py +++ /dev/null @@ -1,201 +0,0 @@ -from south.db import db -from django.db import models -from main.models import * - -class Migration: - def forwards(self, orm): - # Changing field field 'Mirror.rsync_user' - db.alter_column('main_mirror', 'rsync_user', orm['main.mirror:rsync_user']) - # Changing field 'Mirror.rsync_password' - db.alter_column('main_mirror', 'rsync_password', orm['main.mirror:rsync_password']) - - def backwards(self, orm): - # Changing field field 'Mirror.rsync_user' - db.alter_column('main_mirror', 'rsync_user', orm['main.mirror:rsync_user']) - # Changing field 'Mirror.rsync_password' - db.alter_column('main_mirror', 'rsync_password', orm['main.mirror:rsync_password']) - - models = { - 'auth.group': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)"}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0015_auto__del_field_package_maintainer.py b/main/migrations/0015_auto__del_field_package_maintainer.py deleted file mode 100644 index 48aa9244..00000000 --- a/main/migrations/0015_auto__del_field_package_maintainer.py +++ /dev/null @@ -1,211 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - depends_on = ( - ("packages", "0002_populate_package_relation"), - ) - - def forwards(self, orm): - # Deleting field 'package.maintainer' - db.delete_column('packages', 'maintainer_id') - - def backwards(self, orm): - # Adding field 'package.maintainer' - db.add_column('packages', 'maintainer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='maintained_packages', null=True, to=orm['auth.User'], blank=True), keep_default=False) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'object_name': 'AltForum', 'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'object_name': 'Press', 'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0016_always_fill_pkgbase.py b/main/migrations/0016_always_fill_pkgbase.py deleted file mode 100644 index 8f556593..00000000 --- a/main/migrations/0016_always_fill_pkgbase.py +++ /dev/null @@ -1,206 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - orm.Package.objects.filter(pkgbase=None).update(pkgbase=models.F('pkgname')) - - def backwards(self, orm): - if not db.dry_run: - orm.Package.objects.filter(pkgbase=models.F('pkgname')).update(pkgbase=None) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'object_name': 'AltForum', 'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'object_name': 'Press', 'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0017_auto__chg_field_package_pkgbase.py b/main/migrations/0017_auto__chg_field_package_pkgbase.py deleted file mode 100644 index 1dccce40..00000000 --- a/main/migrations/0017_auto__chg_field_package_pkgbase.py +++ /dev/null @@ -1,211 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Changing field 'Package.pkgbase' - db.alter_column('packages', 'pkgbase', self.gf('django.db.models.fields.CharField')(max_length=255)) - # Adding index on 'Package', fields ['pkgbase'] - db.create_index('packages', ['pkgbase']) - - def backwards(self, orm): - # Removing index on 'Package', fields ['pkgbase'] - db.delete_index('packages', ['pkgbase']) - # Changing field 'Package.pkgbase' - db.alter_column('packages', 'pkgbase', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'object_name': 'AltForum', 'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'object_name': 'Press', 'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0018_auto__del_press.py b/main/migrations/0018_auto__del_press.py deleted file mode 100644 index 6cb7a7b0..00000000 --- a/main/migrations/0018_auto__del_press.py +++ /dev/null @@ -1,210 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting model 'Press' - db.delete_table('press') - - - def backwards(self, orm): - - # Adding model 'Press' - db.create_table('press', ( - ('url', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - )) - db.send_create_signal('main', ['Press']) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'object_name': 'AltForum', 'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0019_auto__del_altforum.py b/main/migrations/0019_auto__del_altforum.py deleted file mode 100644 index 52a090a9..00000000 --- a/main/migrations/0019_auto__del_altforum.py +++ /dev/null @@ -1,204 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting model 'AltForum' - db.delete_table('alt_forums') - - - def backwards(self, orm): - - # Adding model 'AltForum' - db.create_table('alt_forums', ( - ('url', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('language', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - )) - db.send_create_signal('main', ['AltForum']) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0020_auto__del_externalproject.py b/main/migrations/0020_auto__del_externalproject.py deleted file mode 100644 index 90fa0b16..00000000 --- a/main/migrations/0020_auto__del_externalproject.py +++ /dev/null @@ -1,197 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting model 'ExternalProject' - db.delete_table('main_externalproject') - - - def backwards(self, orm): - - # Adding model 'ExternalProject' - db.create_table('main_externalproject', ( - ('url', self.gf('django.db.models.fields.URLField')(max_length=200)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('description', self.gf('django.db.models.fields.CharField')(max_length=128)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), - )) - db.send_create_signal('main', ['ExternalProject']) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0021_mark_package_fields_nullable.py b/main/migrations/0021_mark_package_fields_nullable.py deleted file mode 100644 index 4258b54c..00000000 --- a/main/migrations/0021_mark_package_fields_nullable.py +++ /dev/null @@ -1,203 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Changing field 'Package.license' - db.alter_column('packages', 'license', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) - - # Changing field 'Package.pkgdesc' - db.alter_column('packages', 'pkgdesc', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) - - # Changing field 'Package.url' - db.alter_column('packages', 'url', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) - - - def backwards(self, orm): - - # Changing field 'Package.license' - db.alter_column('packages', 'license', self.gf('django.db.models.fields.CharField')(max_length=255)) - - # Changing field 'Package.pkgdesc' - db.alter_column('packages', 'pkgdesc', self.gf('django.db.models.fields.CharField')(max_length=255)) - - # Changing field 'Package.url' - db.alter_column('packages', 'url', self.gf('django.db.models.fields.CharField')(max_length=255)) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0022_auto__add_field_package_filename.py b/main/migrations/0022_auto__add_field_package_filename.py deleted file mode 100644 index 16440170..00000000 --- a/main/migrations/0022_auto__add_field_package_filename.py +++ /dev/null @@ -1,192 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding field 'Package.filename' - db.add_column('packages', 'filename', self.gf('django.db.models.fields.CharField')(default='package.pkg.tar.gz', max_length=255), keep_default=False) - - - def backwards(self, orm): - - # Deleting field 'Package.filename' - db.delete_column('packages', 'filename') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0023_auto__add_field_package_flag_date.py b/main/migrations/0023_auto__add_field_package_flag_date.py deleted file mode 100644 index dcc10606..00000000 --- a/main/migrations/0023_auto__add_field_package_flag_date.py +++ /dev/null @@ -1,193 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding field 'Package.flag_date' - db.add_column('packages', 'flag_date', self.gf('django.db.models.fields.DateTimeField')(null=True), keep_default=False) - - - def backwards(self, orm): - - # Deleting field 'Package.flag_date' - db.delete_column('packages', 'flag_date') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0024_set_initial_flag_date.py b/main/migrations/0024_set_initial_flag_date.py deleted file mode 100644 index 5026f721..00000000 --- a/main/migrations/0024_set_initial_flag_date.py +++ /dev/null @@ -1,190 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - orm.Package.objects.filter(needupdate=False).update(flag_date=None) - orm.Package.objects.filter(needupdate=True).update(flag_date=datetime.datetime.now()) - - def backwards(self, orm): - orm.Package.objects.filter(flag_date__isnull=True).update(needupdate=False) - orm.Package.objects.filter(flag_date__isnull=False).update(needupdate=True) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0025_auto__del_field_package_needupdate.py b/main/migrations/0025_auto__del_field_package_needupdate.py deleted file mode 100644 index 3cf0cf3c..00000000 --- a/main/migrations/0025_auto__del_field_package_needupdate.py +++ /dev/null @@ -1,192 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting field 'Package.needupdate' - db.delete_column('packages', 'needupdate') - - - def backwards(self, orm): - - # Adding field 'Package.needupdate' - db.add_column('packages', 'needupdate', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0026_auto__add_field_package_packager_str__add_field_package_packager.py b/main/migrations/0026_auto__add_field_package_packager_str__add_field_package_packager.py deleted file mode 100644 index 21b66842..00000000 --- a/main/migrations/0026_auto__add_field_package_packager_str__add_field_package_packager.py +++ /dev/null @@ -1,200 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding field 'Package.packager_str' - db.add_column('packages', 'packager_str', self.gf('django.db.models.fields.CharField')(default='', max_length=255), keep_default=False) - - # Adding field 'Package.packager' - db.add_column('packages', 'packager', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True), keep_default=False) - - - def backwards(self, orm): - - # Deleting field 'Package.packager_str' - db.delete_column('packages', 'packager_str') - - # Deleting field 'Package.packager' - db.delete_column('packages', 'packager_id') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0027_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py b/main/migrations/0027_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py deleted file mode 100644 index 9368e148..00000000 --- a/main/migrations/0027_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py +++ /dev/null @@ -1,198 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Changing field 'Package.compressed_size' - db.alter_column('packages', 'compressed_size', self.gf('django.db.models.fields.BigIntegerField')(null=True)) - - # Changing field 'Package.installed_size' - db.alter_column('packages', 'installed_size', self.gf('django.db.models.fields.BigIntegerField')(null=True)) - - - def backwards(self, orm): - # Changing field 'Package.compressed_size' - db.alter_column('packages', 'compressed_size', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)) - - # Changing field 'Package.installed_size' - db.alter_column('packages', 'installed_size', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0028_auto__add_field_repo_bugs_project__add_field_repo_svn_root.py b/main/migrations/0028_auto__add_field_repo_bugs_project__add_field_repo_svn_root.py deleted file mode 100644 index 92e8499d..00000000 --- a/main/migrations/0028_auto__add_field_repo_bugs_project__add_field_repo_svn_root.py +++ /dev/null @@ -1,200 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Repo.bugs_project' - db.add_column('repos', 'bugs_project', self.gf('django.db.models.fields.SmallIntegerField')(default=1), keep_default=False) - - # Adding field 'Repo.svn_root' - db.add_column('repos', 'svn_root', self.gf('django.db.models.fields.CharField')(default='packages', max_length=64), keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Repo.bugs_project' - db.delete_column('repos', 'bugs_project') - - # Deleting field 'Repo.svn_root' - db.delete_column('repos', 'svn_root') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0029_fill_in_repo_data.py b/main/migrations/0029_fill_in_repo_data.py deleted file mode 100644 index 0887b28c..00000000 --- a/main/migrations/0029_fill_in_repo_data.py +++ /dev/null @@ -1,194 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - "Write your forwards methods here." - orm.Repo.objects.filter(name__istartswith='community').update(bugs_project=5, svn_root='community') - orm.Repo.objects.filter(name__iexact='multilib').update(bugs_project=5, svn_root='community') - - - def backwards(self, orm): - pass - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.mirror': { - 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0030_move_mirror_models.py b/main/migrations/0030_move_mirror_models.py deleted file mode 100644 index 998ff6a2..00000000 --- a/main/migrations/0030_move_mirror_models.py +++ /dev/null @@ -1,161 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - depends_on = ( - ('mirrors', '0002_rename_model_tables'), - ) - - def forwards(self, orm): - pass - - def backwards(self, orm): - pass - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0031_move_news_out.py b/main/migrations/0031_move_news_out.py deleted file mode 100644 index a730f4f3..00000000 --- a/main/migrations/0031_move_news_out.py +++ /dev/null @@ -1,153 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - depends_on = ( - ('news', '0002_move_news_in'), - ) - - def forwards(self, orm): - pass - - def backwards(self, orm): - pass - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0032_auto__add_field_arch_agnostic.py b/main/migrations/0032_auto__add_field_arch_agnostic.py deleted file mode 100644 index ab9b9159..00000000 --- a/main/migrations/0032_auto__add_field_arch_agnostic.py +++ /dev/null @@ -1,152 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Arch.agnostic' - db.add_column('arches', 'agnostic', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) - - def backwards(self, orm): - # Deleting field 'Arch.agnostic' - db.delete_column('arches', 'agnostic') - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0033_mark_any_agnostic.py b/main/migrations/0033_mark_any_agnostic.py deleted file mode 100644 index 6ba59b43..00000000 --- a/main/migrations/0033_mark_any_agnostic.py +++ /dev/null @@ -1,150 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - orm.Arch.objects.filter(name='any').update(agnostic=True) - - def backwards(self, orm): - pass - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/migrations/0034_update_content_type.py b/main/migrations/0034_update_content_type.py deleted file mode 100644 index 779021da..00000000 --- a/main/migrations/0034_update_content_type.py +++ /dev/null @@ -1,169 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - depends_on = ( - ('mirrors', '0002_rename_model_tables'), - ('news', '0002_move_news_in'), - ) - - mirror_apps = [ 'mirror', 'mirrorprotocol', 'mirrorurl', 'mirrorrsync' ] - - def forwards(self, orm): - ct = orm['contenttypes.ContentType'].objects - - # somehow these got in there already; remove them in favor of the old - ct.filter(app_label='news').delete() - ct.filter(app_label='mirrors').delete() - - ct.filter(app_label='main', model='news').update(app_label='news') - ct.filter(app_label='main', model__in=self.mirror_apps).update( - app_label='mirrors') - - def backwards(self, orm): - ct = orm['contenttypes.ContentType'].objects - - ct.filter(app_label='mirrors', model__in=self.mirror_apps).update( - app_label='main') - ct.filter(app_label='news', model='news').update(app_label='main') - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, - 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'ordering': "('pkgname',)", 'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), - 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.repo': { - 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, - 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['main'] diff --git a/main/models.py b/main/models.py index a377187b..1b95f3fa 100644 --- a/main/models.py +++ b/main/models.py @@ -1,200 +1,340 @@ +from datetime import datetime +from itertools import groupby +from pgpdump import BinaryData + from django.db import models +from django.db.models import Q from django.contrib.auth.models import User from django.contrib.sites.models import Site -from main.utils import cache_function -from packages.models import PackageRelation - -class UserProfile(models.Model): - id = models.AutoField(primary_key=True) # not technically needed - notify = models.BooleanField( - "Send notifications", - default=True, - help_text="When enabled, send user 'flag out of date' notifications") - alias = models.CharField( - max_length=50, - help_text="Required field") - public_email = models.CharField( - max_length=50, - help_text="Required field") - other_contact = models.CharField(max_length=100, null=True, blank=True) - website = models.CharField(max_length=200, null=True, blank=True) - yob = models.IntegerField(null=True, blank=True) - location = models.CharField(max_length=50, null=True, blank=True) - languages = models.CharField(max_length=50, null=True, blank=True) - interests = models.CharField(max_length=255, null=True, blank=True) - occupation = models.CharField(max_length=50, null=True, blank=True) - roles = models.CharField(max_length=255, null=True, blank=True) - favorite_distros = models.CharField(max_length=255, null=True, blank=True) - picture = models.FileField(upload_to='devs', default='devs/silhouette.png') - user = models.ForeignKey( - User, related_name='userprofile_user', unique=True) - allowed_repos = models.ManyToManyField('Repo', blank=True) - class Meta: - db_table = 'user_profiles' - verbose_name = 'Additional Profile Data' - verbose_name_plural = 'Additional Profile Data' - +from .fields import PositiveBigIntegerField +from .utils import set_created_field, DependStandin +from devel.models import DeveloperKey +from packages.alpm import AlpmAPI -class TodolistManager(models.Manager): - def incomplete(self): - return self.filter(todolistpkg__complete=False).distinct() class PackageManager(models.Manager): def flagged(self): - return self.get_query_set().filter(flag_date__isnull=False) + """Used by dev dashboard.""" + return self.filter(flag_date__isnull=False) + + def normal(self): + return self.select_related('arch', 'repo') + + def restricted(self, user=None): + qs = self.normal() + if user is not None and user.is_authenticated: + return qs + return qs.filter(repo__staging=False) class Donor(models.Model): - id = models.AutoField(primary_key=True) name = models.CharField(max_length=255, unique=True) + visible = models.BooleanField(default=True, + help_text="Should we show this donor on the public page?") + created = models.DateTimeField() def __unicode__(self): return self.name class Meta: db_table = 'donors' - ordering = ['name'] + ordering = ('name',) + get_latest_by = 'created' + class Arch(models.Model): - id = models.AutoField(primary_key=True) name = models.CharField(max_length=255, unique=True) agnostic = models.BooleanField(default=False, help_text="Is this architecture non-platform specific?") + required_signoffs = models.PositiveIntegerField(default=2, + help_text="Number of signoffs required for packages of this architecture") def __unicode__(self): return self.name + def __lt__(self, other): + return self.name < other.name + class Meta: db_table = 'arches' - ordering = ['name'] + ordering = ('name',) verbose_name_plural = 'arches' + class Repo(models.Model): - id = models.AutoField(primary_key=True) name = models.CharField(max_length=255, unique=True) testing = models.BooleanField(default=False, help_text="Is this repo meant for package testing?") + staging = models.BooleanField(default=False, + help_text="Is this repo meant for package staging?") bugs_project = models.SmallIntegerField(default=1, help_text="Flyspray project ID for this repository.") + bugs_category = models.SmallIntegerField(default=2, + help_text="Flyspray category ID for this repository.") svn_root = models.CharField(max_length=64, help_text="SVN root (e.g. path) for this repository.") def __unicode__(self): return self.name + def __lt__(self, other): + return self.name < other.name + class Meta: db_table = 'repos' - ordering = ['name'] - verbose_name_plural = 'repos' + ordering = ('name',) + class Package(models.Model): - id = models.AutoField(primary_key=True) - repo = models.ForeignKey(Repo, related_name="packages") - arch = models.ForeignKey(Arch, related_name="packages") - pkgname = models.CharField(max_length=255, db_index=True) + repo = models.ForeignKey(Repo, related_name="packages", + on_delete=models.PROTECT) + arch = models.ForeignKey(Arch, related_name="packages", + on_delete=models.PROTECT) + pkgname = models.CharField(max_length=255) pkgbase = models.CharField(max_length=255, db_index=True) pkgver = models.CharField(max_length=255) pkgrel = models.CharField(max_length=255) - pkgdesc = models.CharField(max_length=255, null=True) - url = models.CharField(max_length=255, null=True) + epoch = models.PositiveIntegerField(default=0) + pkgdesc = models.TextField('description', null=True) + url = models.CharField('URL', max_length=255, null=True) filename = models.CharField(max_length=255) - # TODO: it would be nice to have the >0 check constraint back here - compressed_size = models.BigIntegerField(null=True) - installed_size = models.BigIntegerField(null=True) + compressed_size = PositiveBigIntegerField() + installed_size = PositiveBigIntegerField() build_date = models.DateTimeField(null=True) - last_update = models.DateTimeField(null=True, blank=True) + last_update = models.DateTimeField(db_index=True) files_last_update = models.DateTimeField(null=True, blank=True) - license = models.CharField(max_length=255, null=True) - packager_str = models.CharField(max_length=255) - packager = models.ForeignKey(User, null=True) - flag_date = models.DateTimeField(null=True) + created = models.DateTimeField() + packager_str = models.CharField('packager string', max_length=255) + packager = models.ForeignKey(User, null=True, blank=True, + on_delete=models.SET_NULL) + signature_bytes = models.BinaryField('PGP signature', null=True) + flag_date = models.DateTimeField(null=True, blank=True) objects = PackageManager() + class Meta: db_table = 'packages' ordering = ('pkgname',) - #get_latest_by = 'last_update' - #ordering = ('-last_update',) + get_latest_by = 'last_update' + unique_together = (('pkgname', 'repo', 'arch'),) def __unicode__(self): return self.pkgname + @property + def full_version(self): + if self.epoch > 0: + return u'%d:%s-%s' % (self.epoch, self.pkgver, self.pkgrel) + return u'%s-%s' % (self.pkgver, self.pkgrel) + def get_absolute_url(self): return '/packages/%s/%s/%s/' % (self.repo.name.lower(), self.arch.name, self.pkgname) - def get_full_url(self, proto='http'): + def get_full_url(self, proto='https'): '''get a URL suitable for things like email including the domain''' domain = Site.objects.get_current().domain return '%s://%s%s' % (proto, domain, self.get_absolute_url()) @property - def maintainers(self): - return User.objects.filter( - package_relations__pkgbase=self.pkgbase, - package_relations__type=PackageRelation.MAINTAINER) + def signature(self): + if not self.signature_bytes: + return None + data = BinaryData(self.signature_bytes) + packets = list(data.packets()) + return packets[0] + + @property + def signer(self): + sig = self.signature + if sig and sig.key_id: + try: + matching_key = DeveloperKey.objects.select_related( + 'owner').get(key=sig.key_id, owner_id__isnull=False) + user = matching_key.owner + except DeveloperKey.DoesNotExist: + user = None + return user + return None + + _maintainers = None @property - def signoffs(self): - if 'signoffs_cache' in dir(self): - return self.signoffs_cache - self.signoffs_cache = list(Signoff.objects.filter( - pkg=self, - pkgver=self.pkgver, - pkgrel=self.pkgrel)) - return self.signoffs_cache - - def approved_for_signoff(self): - return len(self.signoffs) >= 2 - - @cache_function(300) + def maintainers(self): + from packages.models import PackageRelation + if self._maintainers is None: + self._maintainers = User.objects.filter( + package_relations__pkgbase=self.pkgbase, + package_relations__type=PackageRelation.MAINTAINER) + return self._maintainers + + @maintainers.setter + def maintainers(self, maintainers): + self._maintainers = maintainers + + _applicable_arches = None + + def applicable_arches(self): + '''The list of (this arch) + (available agnostic arches).''' + if self._applicable_arches is None: + arches = set(Arch.objects.filter(agnostic=True)) + arches.add(self.arch) + self._applicable_arches = list(arches) + return self._applicable_arches + def get_requiredby(self): """ - Returns a list of package objects. + Returns a list of package objects. An attempt will be made to keep this + list slim by including the corresponding package in the same testing + category as this package if that check makes sense. """ - arches = list(Arch.objects.filter(agnostic=True)) - arches.append(self.arch) - requiredby = Package.objects.select_related('arch', 'repo').filter( - packagedepend__depname=self.pkgname, - arch__in=arches).distinct() - return requiredby.order_by('pkgname') - - @cache_function(300) + from packages.models import Depend + sorttype = '''(CASE deptype + WHEN 'D' THEN 0 + WHEN 'O' THEN 1 + WHEN 'M' THEN 2 + WHEN 'C' THEN 3 + ELSE 1000 END)''' + name_clause = '''packages_depend.name IN ( + SELECT %s UNION ALL + SELECT z.name FROM packages_provision z WHERE z.pkg_id = %s + )''' + requiredby = Depend.objects.select_related('pkg', + 'pkg__arch', 'pkg__repo').extra( + select={'sorttype': sorttype}, + where=[name_clause], params=[self.pkgname, self.id]).order_by( + 'sorttype', 'pkg__pkgname', + 'pkg__arch__name', 'pkg__repo__name') + if not self.arch.agnostic: + # make sure we match architectures if possible + requiredby = requiredby.filter( + pkg__arch__in=self.applicable_arches()) + + # if we can use ALPM, ensure our returned Depend objects abide by the + # version comparison operators they may specify + alpm = AlpmAPI() + if alpm.available: + provides = self.provides.all() + new_rqd = [] + for dep in requiredby: + if not dep.comparison or not dep.version: + # no comparisson/version, so always let it through + new_rqd.append(dep) + elif self.pkgname == dep.name: + # depends on this package, so check it directly + if alpm.compare_versions(self.full_version, + dep.comparison, dep.version): + new_rqd.append(dep) + else: + # it must be a provision of ours at this point + for provide in (p for p in provides if p.name == dep.name): + if alpm.compare_versions(provide.version, + dep.comparison, dep.version): + new_rqd.append(dep) + break + requiredby = new_rqd + + # sort out duplicate packages; this happens if something has a double + # versioned depend such as a kernel module + requiredby = [list(vals)[0] for _, vals in + groupby(requiredby, lambda x: x.pkg.id)] + if len(requiredby) == 0: + return requiredby + + # do we have duplicate pkgbase values for non-primary depends? + # if so, filter it down to base packages only + def grouper(depend): + p = depend.pkg + return (depend.deptype, p.pkgbase, p.repo.testing, p.repo.staging) + + filtered = [] + for (typ, pkgbase, _, _), dep_pkgs in groupby(requiredby, grouper): + dep_pkgs = list(dep_pkgs) + if typ == 'D' or len(dep_pkgs) == 1: + filtered.extend(dep_pkgs) + else: + filtered.append(DependStandin(dep_pkgs)) + + # find another package by this name in a different testing or staging + # repo; if we can't, we can short-circuit some checks + repo_q = (Q(repo__testing=(not self.repo.testing)) | + Q(repo__staging=(not self.repo.staging))) + if not Package.objects.filter( + repo_q, pkgname=self.pkgname, arch=self.arch + ).exclude(id=self.id).exists(): + # there isn't one? short circuit, all required by entries are fine + return filtered + + trimmed = [] + # for each unique package name, try to screen our package list down to + # those packages in the same testing and staging category (yes or no) + # iff there is a package in the same testing and staging category. + for _, dep_pkgs in groupby(filtered, lambda x: x.pkg.pkgname): + dep_pkgs = list(dep_pkgs) + dep = dep_pkgs[0] + if len(dep_pkgs) > 1: + dep_pkgs = [d for d in dep_pkgs + if d.pkg.repo.testing == self.repo.testing and + d.pkg.repo.staging == self.repo.staging] + if len(dep_pkgs) > 0: + dep = dep_pkgs[0] + trimmed.append(dep) + + return trimmed + def get_depends(self): """ - Returns a list of dicts. Each dict contains ('pkg' and 'dep'). - If it represents a found package both vars will be available; - else pkg will be None if it is a 'virtual' dependency. + Returns a list of dicts. Each dict contains ('dep', 'pkg', and + 'providers'). If it represents a found package both vars will be + available; else pkg will be None if it is a 'virtual' dependency. + If pkg is None and providers are known, they will be available in + providers. + Packages will match the testing status of this package if possible. """ deps = [] - arches = list(Arch.objects.filter(agnostic=True)) - arches.append(self.arch) - # TODO: we can use list comprehension and an 'in' query to make this more effective - for dep in self.packagedepend_set.order_by('depname'): - pkgs = Package.objects.select_related('arch', 'repo').filter( - pkgname=dep.depname) - if not self.arch.agnostic: - # make sure we match architectures if possible - pkgs = pkgs.filter(arch__in=arches) - if len(pkgs) == 0: - # couldn't find a package in the DB - # it should be a virtual depend (or a removed package) - pkg = None - elif len(pkgs) == 1: - pkg = pkgs[0] - else: - # more than one package, see if we can't shrink it down - # grab the first though in case we fail - pkg = pkgs[0] - if self.repo.testing: - pkgs = pkgs.filter(repo__testing=True) - else: - pkgs = pkgs.filter(repo__testing=False) - if len(pkgs) > 0: - pkg = pkgs[0] - deps.append({'dep': dep, 'pkg': pkg}) - return deps + # TODO: we can use list comprehension and an 'in' query to make this + # more effective + for dep in self.depends.all(): + pkg = dep.get_best_satisfier() + providers = None + if not pkg: + providers = dep.get_providers() + deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) + # sort the list; deptype sorting makes this tricker than expected + sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3} + + def sort_key(val): + dep = val['dep'] + return (sort_order.get(dep.deptype, 1000), dep.name) + return sorted(deps, key=sort_key) + + def reverse_conflicts(self): + """ + Returns a list of packages with conflicts against this package. + """ + pkgs = Package.objects.normal().filter(conflicts__name=self.pkgname) + if not self.arch.agnostic: + # make sure we match architectures if possible + pkgs = pkgs.filter(arch__in=self.applicable_arches()) + + alpm = AlpmAPI() + if not alpm.available: + return pkgs + + # If we can use ALPM, we can filter out items that don't actually + # conflict due to the version specification. + pkgs = pkgs.prefetch_related('conflicts') + new_pkgs = [] + for package in pkgs: + for conflict in package.conflicts.all(): + if conflict.name != self.pkgname: + continue + if not conflict.comparison or not conflict.version \ + or alpm.compare_versions(self.full_version, + conflict.comparison, conflict.version): + new_pkgs.append(package) + return new_pkgs def base_package(self): """ @@ -204,13 +344,14 @@ class Package(models.Model): """ try: # start by looking for something in this repo - return Package.objects.get(arch=self.arch, + return Package.objects.normal().get(arch=self.arch, repo=self.repo, pkgname=self.pkgbase) except Package.DoesNotExist: - # this package might be split across repos? just find one + # this package might be split across repos? find one # that matches the correct [testing] repo flag - pkglist = Package.objects.filter(arch=self.arch, - repo__testing=self.repo.testing, pkgname=self.pkgbase) + pkglist = Package.objects.normal().filter(arch=self.arch, + repo__testing=self.repo.testing, + repo__staging=self.repo.staging, pkgname=self.pkgbase) if len(pkglist) > 0: return pkglist[0] return None @@ -220,32 +361,36 @@ class Package(models.Model): Return all packages that were built with this one (e.g. share a pkgbase value). The package this method is called on will never be in the list, and we will never return a package that does not have the same - repo.testing flag. For any non-split packages, the return value will be - an empty list. + repo.testing and repo.staging flags. For any non-split packages, the + return value will be an empty list. """ - return Package.objects.filter(arch=self.arch, - repo__testing=self.repo.testing, pkgbase=self.pkgbase).exclude(id=self.id) - - def get_svn_link(self, svnpath): - linkbase = "http://repos.archlinux.org/wsvn/%s/%s/%s/" - return linkbase % (self.repo.svn_root, self.pkgbase, svnpath) - - def get_arch_svn_link(self): - repo = self.repo.name.lower() - return self.get_svn_link("repos/%s-%s" % (repo, self.arch.name)) - - def get_trunk_svn_link(self): - return self.get_svn_link("trunk") - - def get_bugs_link(self): - return "https://bugs.archlinux.org/?project=%d&string=%s" % \ - (self.repo.bugs_project, self.pkgname) + return Package.objects.normal().filter( + arch__in=self.applicable_arches(), + repo__testing=self.repo.testing, + repo__staging=self.repo.staging, + pkgbase=self.pkgbase).exclude(id=self.id) + + def flag_request(self): + if self.flag_date is None: + return None + from packages.models import FlagRequest + try: + # Note that we don't match on pkgrel here; this is because a pkgrel + # bump does not unflag a package so we can still show the same flag + # request from a different pkgrel. + request = FlagRequest.objects.filter(pkgbase=self.pkgbase, + repo=self.repo, pkgver=self.pkgver, + epoch=self.epoch, is_spam=False).latest() + return request + except FlagRequest.DoesNotExist: + return None def is_same_version(self, other): 'is this package similar, name and version-wise, to another' return self.pkgname == other.pkgname \ and self.pkgver == other.pkgver \ - and self.pkgrel == other.pkgrel + and self.pkgrel == other.pkgrel \ + and self.epoch == other.epoch def in_testing(self): '''attempt to locate this package in a testing repo; if we are in @@ -253,7 +398,18 @@ class Package(models.Model): if self.repo.testing: return None try: - return Package.objects.get(repo__testing=True, + return Package.objects.normal().get(repo__testing=True, + pkgname=self.pkgname, arch=self.arch) + except Package.DoesNotExist: + return None + + def in_staging(self): + '''attempt to locate this package in a staging repo; if we are in + a staging repo we will always return None.''' + if self.repo.staging: + return None + try: + return Package.objects.normal().get(repo__staging=True, pkgname=self.pkgname, arch=self.arch) except Package.DoesNotExist: return None @@ -261,65 +417,37 @@ class Package(models.Model): def elsewhere(self): '''attempt to locate this package anywhere else, regardless of architecture or repository. Excludes this package from the list.''' - return Package.objects.select_related('arch', 'repo').filter( - pkgname=self.pkgname).exclude(id=self.id).order_by( + names = [self.pkgname] + if self.pkgname.startswith(u'lib32-'): + names.append(self.pkgname[6:]) + elif self.pkgname.endswith(u'-multilib'): + names.append(self.pkgname[:-9]) + else: + names.append(u'lib32-' + self.pkgname) + names.append(self.pkgname + u'-multilib') + return Package.objects.normal().filter( + pkgname__in=names).exclude(id=self.id).order_by( 'arch__name', 'repo__name') -class Signoff(models.Model): - pkg = models.ForeignKey(Package) - pkgver = models.CharField(max_length=255) - pkgrel = models.CharField(max_length=255) - packager = models.ForeignKey(User) class PackageFile(models.Model): - id = models.AutoField(primary_key=True) - pkg = models.ForeignKey('Package') - path = models.CharField(max_length=255) - class Meta: - db_table = 'package_files' + pkg = models.ForeignKey(Package) + is_directory = models.BooleanField(default=False) + directory = models.CharField(max_length=1024) + filename = models.CharField(max_length=1024, null=True, blank=True) -class PackageDepend(models.Model): - id = models.AutoField(primary_key=True) - pkg = models.ForeignKey('Package') - depname = models.CharField(db_index=True, max_length=255) - depvcmp = models.CharField(max_length=255) - class Meta: - db_table = 'package_depends' - -class Todolist(models.Model): - id = models.AutoField(primary_key=True) - creator = models.ForeignKey(User) - name = models.CharField(max_length=255) - description = models.TextField() - date_added = models.DateField(auto_now_add=True) - objects = TodolistManager() def __unicode__(self): - return self.name - - @property - def packages(self): - # select_related() does not use LEFT OUTER JOIN for nullable ForeignKey - # fields. That is why we need to explicitly list the ones we want. - return TodolistPkg.objects.select_related( - 'pkg__repo', 'pkg__arch').filter(list=self).order_by('pkg') - - @property - def package_names(self): - return '\n'.join(set([p.pkg.pkgname for p in self.packages])) + return "%s%s" % (self.directory, self.filename or '') class Meta: - db_table = 'todolists' + db_table = 'package_files' - def get_absolute_url(self): - return '/todo/%i/' % self.id -class TodolistPkg(models.Model): - id = models.AutoField(primary_key=True) - list = models.ForeignKey('Todolist') - pkg = models.ForeignKey('Package') - complete = models.BooleanField(default=False) - class Meta: - db_table = 'todolist_pkgs' - unique_together = (('list','pkg'),) +from django.db.models.signals import pre_save + +# note: reporead sets the 'created' field on Package objects, so no signal +# listener is set up here to do so +pre_save.connect(set_created_field, sender=Donor, + dispatch_uid="main.models") # vim: set ts=4 sw=4 et: diff --git a/main/storage.py b/main/storage.py new file mode 100644 index 00000000..62e94ef7 --- /dev/null +++ b/main/storage.py @@ -0,0 +1,36 @@ +import cssmin +import jsmin + +from django.contrib.staticfiles.storage import CachedStaticFilesStorage +from django.core.files.base import ContentFile +from django.utils.encoding import smart_str + + +class MinifiedStaticFilesStorage(CachedStaticFilesStorage): + """ + A static file system storage backend which minifies the hashed + copies of the files it saves. It currently knows how to process + CSS and JS files. Files containing '.min' anywhere in the filename + are skipped as they are already assumed minified. + """ + minifiers = ( + ('.css', cssmin.cssmin), + ('.js', jsmin.jsmin), + ) + + def post_process(self, paths, dry_run=False, **options): + for original_path, processed_path, processed in super( + MinifiedStaticFilesStorage, self).post_process( + paths, dry_run, **options): + for ext, func in self.minifiers: + if '.min' in original_path: + continue + if original_path.endswith(ext): + with self._open(processed_path) as processed_file: + minified = func(processed_file.read()) + minified_file = ContentFile(smart_str(minified)) + self.delete(processed_path) + self._save(processed_path, minified_file) + processed = True + + yield original_path, processed_path, processed diff --git a/main/templatetags/attributes.py b/main/templatetags/attributes.py new file mode 100644 index 00000000..bd4ccf3d --- /dev/null +++ b/main/templatetags/attributes.py @@ -0,0 +1,21 @@ +import re +from django import template +from django.conf import settings + +numeric_test = re.compile("^\d+$") +register = template.Library() + +def attribute(value, arg): + """Gets an attribute of an object dynamically from a string name""" + if hasattr(value, str(arg)): + return getattr(value, arg) + elif hasattr(value, 'has_key') and value.has_key(arg): + return value[arg] + elif numeric_test.match(str(arg)) and len(value) > int(arg): + return value[int(arg)] + else: + return settings.TEMPLATE_STRING_IF_INVALID + +register.filter('attribute', attribute) + +# vim: set ts=4 sw=4 et: diff --git a/main/templatetags/bugs.py b/main/templatetags/bugs.py new file mode 100644 index 00000000..b548859a --- /dev/null +++ b/main/templatetags/bugs.py @@ -0,0 +1,6 @@ +from django import template +register = template.Library() + +@register.simple_tag +def bug_link(bugid): + return "<a href=\"https://bugs.archlinux.org/task/{0}\">FS#{0}</a>".format(bugid) diff --git a/main/templatetags/cdn.py b/main/templatetags/cdn.py index ff45e524..fc63fdd8 100644 --- a/main/templatetags/cdn.py +++ b/main/templatetags/cdn.py @@ -1,25 +1,28 @@ from django import template from django.conf import settings +from django.contrib.staticfiles.storage import staticfiles_storage register = template.Library() -@register.tag -def jquery(parser, token): - return JQueryNode() -class JQueryNode(template.Node): - def render(self, context): - # if we have the request in context, we can check if it is secure and - # serve content from HTTPS instead. - secure = 'secure' in context and context['secure'] - prefixes = { False: 'http', True: 'https' } - version = '1.4.2' - oncdn = getattr(settings, 'CDN_ENABLED', True) - if oncdn: - jquery = '%s://ajax.googleapis.com/ajax/libs/jquery/' \ - '%s/jquery.min.js' % (prefixes[secure], version) - else: - jquery = '/media/jquery-%s.min.js' % version - return '<script type="text/javascript" src="%s"></script>' % jquery +@register.simple_tag +def jquery(): + version = '1.8.3' + oncdn = getattr(settings, 'CDN_ENABLED', True) + if oncdn: + link = 'https://ajax.googleapis.com/ajax/libs/jquery/' \ + '%s/jquery.min.js' % version + else: + filename = 'jquery-%s.min.js' % version + link = staticfiles_storage.url(filename) + return '<script type="text/javascript" src="%s"></script>' % link + + +@register.simple_tag +def jquery_tablesorter(): + version = '2.7' + filename = 'jquery.tablesorter-%s.min.js' % version + link = staticfiles_storage.url(filename) + return '<script type="text/javascript" src="%s"></script>' % link # vim: set ts=4 sw=4 et: diff --git a/main/templatetags/flags.py b/main/templatetags/flags.py new file mode 100644 index 00000000..5b356561 --- /dev/null +++ b/main/templatetags/flags.py @@ -0,0 +1,13 @@ +from django import template + +register = template.Library() + + +@register.simple_tag +def country_flag(country): + if not country: + return '' + return '<span class="fam-flag fam-flag-%s" title="%s"></span> ' % ( + unicode(country.code).lower(), unicode(country.name)) + +# vim: set ts=4 sw=4 et: diff --git a/main/templatetags/pgp.py b/main/templatetags/pgp.py new file mode 100644 index 00000000..16b63232 --- /dev/null +++ b/main/templatetags/pgp.py @@ -0,0 +1,77 @@ +from django import template +from django.conf import settings +from django.utils.html import conditional_escape +from django.utils.safestring import mark_safe + +from ..utils import cache_function +from devel.models import DeveloperKey + +register = template.Library() + + +def format_key(key_id): + if len(key_id) in (8, 20): + return u'0x%s' % key_id + elif len(key_id) == 40: + # normal display format is 5 groups of 4 hex chars seperated by spaces, + # double space, then 5 more groups of 4 hex chars + split = tuple(key_id[i:i+4] for i in range(0, 40, 4)) + return u'%s\u00a0 %s' % (' '.join(split[0:5]), ' '.join(split[5:10])) + return u'0x%s' % key_id + +@register.simple_tag +def pgp_key_link(key_id, link_text=None): + if not key_id: + return "Unknown" + if isinstance(key_id, (int, long)): + key_id = '%X' % key_id + # zero-fill to nearest 8, 16, or 40 chars if necessary + if len(key_id) <= 8: + key_id = key_id.zfill(8) + elif len(key_id) <= 16: + key_id = key_id.zfill(16) + elif len(key_id) <= 40: + key_id = key_id.zfill(40) + # Something like 'pgp.mit.edu:11371' + pgp_server = getattr(settings, 'PGP_SERVER', None) + if not pgp_server: + return format_key(key_id) + pgp_server_secure = getattr(settings, 'PGP_SERVER_SECURE', False) + scheme = 'https' if pgp_server_secure else 'http' + url = '%s://%s/pks/lookup?op=vindex&fingerprint=on&exact=on&search=0x%s' % \ + (scheme, pgp_server, key_id) + if link_text is None: + link_text = '0x%s' % key_id[-8:] + values = (url, format_key(key_id), link_text) + return '<a href="%s" title="PGP key search for %s">%s</a>' % values + + +@register.simple_tag +def user_pgp_key_link(dev_keys, key_id): + normalized = key_id[-16:] + found = dev_keys.get(normalized, None) + if found: + return pgp_key_link(key_id, found.owner.get_full_name()) + else: + return pgp_key_link(key_id, None) + + +@register.filter(needs_autoescape=True) +def pgp_fingerprint(key_id, autoescape=True): + if not key_id: + return u'' + if autoescape: + esc = conditional_escape + else: + esc = lambda x: x + return mark_safe(format_key(esc(key_id))) + + +@register.assignment_tag +def signature_exists(signatures, signer, signee): + if not signer or not signee: + return False + lookup = (signer[-16:], signee[-16:]) + return lookup in signatures + +# vim: set ts=4 sw=4 et: diff --git a/main/templatetags/wiki.py b/main/templatetags/wiki.py new file mode 100644 index 00000000..e3ffb138 --- /dev/null +++ b/main/templatetags/wiki.py @@ -0,0 +1,9 @@ +from django import template +register = template.Library() + +@register.simple_tag +def wiki_url(article=""): + if article == "": + return "https://wiki.parabola.nu/" + else: + return "https://wiki.parabola.nu/"+article.replace(' ', '_') diff --git a/main/utils.py b/main/utils.py index 81093e2a..f94f314d 100644 --- a/main/utils.py +++ b/main/utils.py @@ -2,7 +2,24 @@ try: import cPickle as pickle except ImportError: import pickle -from django.utils.hashcompat import md5_constructor + +import hashlib +import markdown +from markdown.extensions import Extension + +from django.core.cache import cache +from django.db import connections, router +from django.http import HttpResponse +from django.utils.timezone import now +from django.template.defaultfilters import slugify + + +def cache_function_key(func, args, kwargs): + raw = [func.__name__, func.__module__, args, kwargs] + pickled = pickle.dumps(raw, protocol=pickle.HIGHEST_PROTOCOL) + key = hashlib.md5(pickled).hexdigest() + return 'cache_function.' + func.__name__ + '.' + key + def cache_function(length): """ @@ -18,12 +35,7 @@ def cache_function(length): """ def decorator(func): def inner_func(*args, **kwargs): - from django.core.cache import cache - - raw = [func.__name__, func.__module__, args, kwargs] - pickled = pickle.dumps(raw, protocol=pickle.HIGHEST_PROTOCOL) - key = md5_constructor(pickled).hexdigest() - key = 'cache_function.' + func.__name__ + '.' + key + key = cache_function_key(func, args, kwargs) value = cache.get(key) if value is not None: return value @@ -34,5 +46,132 @@ def cache_function(length): return inner_func return decorator -#utility to make a pair of django choices + +def clear_cache_function(func, args, kwargs): + key = cache_function_key(func, args, kwargs) + cache.delete(key) + + +def empty_response(): + empty = HttpResponse('') + # designating response as 'streaming' forces ConditionalGetMiddleware to + # not add a 'Content-Length: 0' header + empty.streaming = True + return empty + + +def format_http_headers(request): + headers = sorted((k, v) for k, v in request.META.items() + if k.startswith('HTTP_')) + data = [] + for k, v in headers: + data.extend([k[5:].replace('_', '-').title(), ': ', v, '\n']) + return ''.join(data) + + +# utility to make a pair of django choices make_choice = lambda l: [(str(m), str(m)) for m in l] + + +def set_created_field(sender, **kwargs): + '''This will set the 'created' field on any object to the current UTC time + if it is unset. + Additionally, this will set the 'last_modified' field on any object to the + current UTC time on any save of the object. + For use as a pre_save signal handler.''' + obj = kwargs['instance'] + time = now() + if hasattr(obj, 'created') and not obj.created: + obj.created = time + if hasattr(obj, 'last_modified'): + obj.last_modified = time + + +def find_unique_slug(model, title): + '''Attempt to find a unique slug for this model with given title.''' + existing = set(model.objects.values_list( + 'slug', flat=True).order_by().distinct()) + + suffixed = slug = slugify(title) + suffix = 0 + while suffixed in existing: + suffix += 1 + suffixed = "%s-%d" % (slug, suffix) + + return suffixed + + +def database_vendor(model, mode='read'): + if mode == 'read': + database = router.db_for_read(model) + elif mode == 'write': + database = router.db_for_write(model) + else: + raise Exception('Invalid database mode specified') + return connections[database].vendor + + +class EscapeHtml(Extension): + def extendMarkdown(self, md, md_globals): + del md.preprocessors['html_block'] + del md.inlinePatterns['html'] + + +def parse_markdown(text, allow_html=False): + if allow_html: + return markdown.markdown(text, enable_attributes=False) + ext = [EscapeHtml()] + return markdown.markdown(text, extensions=ext, enable_attributes=False) + + +def groupby_preserve_order(iterable, keyfunc): + '''Take an iterable and regroup using keyfunc to determine whether items + belong to the same group. The order of the iterable is preserved and + similar keys do not have to be consecutive. This means the earliest + occurrence of a given key will determine the order of the lists in the + returned list.''' + seen_keys = {} + result = [] + for item in iterable: + key = keyfunc(item) + + group = seen_keys.get(key, None) + if group is None: + group = [] + seen_keys[key] = group + result.append(group) + + group.append(item) + + return result + + +class PackageStandin(object): + '''Resembles a Package object, and has a few of the same fields, but is + really a link to a pkgbase that has no package with matching pkgname.''' + def __init__(self, package): + self.package = package + self.pkgname = package.pkgbase + + def __getattr__(self, name): + return getattr(self.package, name) + + def get_absolute_url(self): + return '/packages/%s/%s/%s/' % ( + self.repo.name.lower(), self.arch.name, self.pkgbase) + + +class DependStandin(object): + '''Resembles a Depend object, and has a few of the same fields, but is + really a link to a base package rather than a single package.''' + def __init__(self, depends): + self._depends = depends + first = depends[0] + self.name = first.name + self.version = first.version + self.comparison = first.comparison + self.description = first.description + self.deptype = first.deptype + self.pkg = first.pkg.base_package() or PackageStandin(first.pkg) + +# vim: set ts=4 sw=4 et: @@ -1,14 +1,12 @@ -#!/usr/bin/env python -from django.core.management import execute_manager -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) - sys.exit(1) +#!/usr/bin/env python2 +import os +import sys if __name__ == "__main__": - execute_manager(settings) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") -# vim: set ts=4 sw=4 et: + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) +# vim: set ts=4 sw=4 et: diff --git a/media/airvm_button.jpg b/media/airvm_button.jpg Binary files differdeleted file mode 100644 index b3801873..00000000 --- a/media/airvm_button.jpg +++ /dev/null diff --git a/media/archweb-print.css b/media/archweb-print.css deleted file mode 100644 index 2946de54..00000000 --- a/media/archweb-print.css +++ /dev/null @@ -1,11 +0,0 @@ -/* - * ARCH LINUX DJANGO (MAIN SITE) - * - * Stylesheet for printing - */ - -/* general styling */ -body { font: normal 100% sans-serif; } -#content { font-size: 0.812em; } -#archnavbarmenu, #archdev-navbar, .admin-actions { display: none; } - diff --git a/media/django-jsi18n.js b/media/django-jsi18n.js deleted file mode 100644 index 83562c1a..00000000 --- a/media/django-jsi18n.js +++ /dev/null @@ -1,35 +0,0 @@ - -/* gettext library */ - -var catalog = new Array(); - -function pluralidx(count) { return (count == 1) ? 0 : 1; } - - -function gettext(msgid) { - var value = catalog[msgid]; - if (typeof(value) == 'undefined') { - return msgid; - } else { - return (typeof(value) == 'string') ? value : value[0]; - } -} - -function ngettext(singular, plural, count) { - value = catalog[singular]; - if (typeof(value) == 'undefined') { - return (count == 1) ? singular : plural; - } else { - return value[pluralidx(count)]; - } -} - -function gettext_noop(msgid) { return msgid; } - -function interpolate(fmt, obj, named) { - if (named) { - return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); - } else { - return fmt.replace(/%s/g, function(match){return String(obj.shift())}); - } -} diff --git a/media/donate.gif b/media/donate.gif Binary files differdeleted file mode 100644 index d637428b..00000000 --- a/media/donate.gif +++ /dev/null diff --git a/media/jquery-1.4.2.min.js b/media/jquery-1.4.2.min.js deleted file mode 100644 index 7c243080..00000000 --- a/media/jquery-1.4.2.min.js +++ /dev/null @@ -1,154 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i? -e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r= -j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g, -"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e= -true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)|| -c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded", -L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype, -"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+ -a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f], -d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]=== -a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&& -!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari= -true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ", -i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ", -" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className= -this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i= -e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!= -null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), -fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| -d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this, -"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent= -a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y, -isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit= -{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}}; -if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&& -!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}}, -toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector, -u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "), -function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q]; -if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[]; -for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length- -1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, -CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}}, -relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]= -l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[]; -h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m= -m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition|| -!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m= -h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>"; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/, -gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length; -c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)? -a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&& -this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]|| -u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length=== -1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay"); -this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a], -"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)}, -animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing= -j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]); -this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length|| -c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement? -function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b= -this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle; -k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&& -f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>"; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/media/jquery.tablesorter.min.js b/media/jquery.tablesorter.min.js deleted file mode 100644 index 64c70071..00000000 --- a/media/jquery.tablesorter.min.js +++ /dev/null @@ -1,2 +0,0 @@ - -(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
\ No newline at end of file diff --git a/media/logos/archlinux-logo-black-1200dpi.png b/media/logos/archlinux-logo-black-1200dpi.png Binary files differdeleted file mode 100644 index a3082c39..00000000 --- a/media/logos/archlinux-logo-black-1200dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-black-90dpi.png b/media/logos/archlinux-logo-black-90dpi.png Binary files differdeleted file mode 100644 index 6948b795..00000000 --- a/media/logos/archlinux-logo-black-90dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-dark-1200dpi.png b/media/logos/archlinux-logo-dark-1200dpi.png Binary files differdeleted file mode 100644 index 24a5cefa..00000000 --- a/media/logos/archlinux-logo-dark-1200dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-dark-90dpi.png b/media/logos/archlinux-logo-dark-90dpi.png Binary files differdeleted file mode 100644 index f3757c61..00000000 --- a/media/logos/archlinux-logo-dark-90dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-light-1200dpi.png b/media/logos/archlinux-logo-light-1200dpi.png Binary files differdeleted file mode 100644 index 79e0a0f1..00000000 --- a/media/logos/archlinux-logo-light-1200dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-light-90dpi.png b/media/logos/archlinux-logo-light-90dpi.png Binary files differdeleted file mode 100644 index 95803309..00000000 --- a/media/logos/archlinux-logo-light-90dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-white-1200dpi.png b/media/logos/archlinux-logo-white-1200dpi.png Binary files differdeleted file mode 100644 index 50e700cf..00000000 --- a/media/logos/archlinux-logo-white-1200dpi.png +++ /dev/null diff --git a/media/logos/archlinux-logo-white-90dpi.png b/media/logos/archlinux-logo-white-90dpi.png Binary files differdeleted file mode 100644 index 86679601..00000000 --- a/media/logos/archlinux-logo-white-90dpi.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-aqua-blue.png b/media/logos/legacy/arch-legacy-aqua-blue.png Binary files differdeleted file mode 100644 index 9637ce72..00000000 --- a/media/logos/legacy/arch-legacy-aqua-blue.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-aqua-white.png b/media/logos/legacy/arch-legacy-aqua-white.png Binary files differdeleted file mode 100644 index 25fe9001..00000000 --- a/media/logos/legacy/arch-legacy-aqua-white.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-aqua.png b/media/logos/legacy/arch-legacy-aqua.png Binary files differdeleted file mode 100644 index 881e1709..00000000 --- a/media/logos/legacy/arch-legacy-aqua.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-blue1.png b/media/logos/legacy/arch-legacy-blue1.png Binary files differdeleted file mode 100644 index 3ed6c248..00000000 --- a/media/logos/legacy/arch-legacy-blue1.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-blue2.png b/media/logos/legacy/arch-legacy-blue2.png Binary files differdeleted file mode 100644 index 8b5b791e..00000000 --- a/media/logos/legacy/arch-legacy-blue2.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-noodle-blue.png b/media/logos/legacy/arch-legacy-noodle-blue.png Binary files differdeleted file mode 100644 index b24d34cf..00000000 --- a/media/logos/legacy/arch-legacy-noodle-blue.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-noodle-box.png b/media/logos/legacy/arch-legacy-noodle-box.png Binary files differdeleted file mode 100644 index 1162ed64..00000000 --- a/media/logos/legacy/arch-legacy-noodle-box.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-noodle-cup.png b/media/logos/legacy/arch-legacy-noodle-cup.png Binary files differdeleted file mode 100644 index b4f93078..00000000 --- a/media/logos/legacy/arch-legacy-noodle-cup.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-noodle-white.png b/media/logos/legacy/arch-legacy-noodle-white.png Binary files differdeleted file mode 100644 index a12ee21c..00000000 --- a/media/logos/legacy/arch-legacy-noodle-white.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-ribbon1.png b/media/logos/legacy/arch-legacy-ribbon1.png Binary files differdeleted file mode 100644 index fb8e7720..00000000 --- a/media/logos/legacy/arch-legacy-ribbon1.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-ribbon2.png b/media/logos/legacy/arch-legacy-ribbon2.png Binary files differdeleted file mode 100644 index 66635999..00000000 --- a/media/logos/legacy/arch-legacy-ribbon2.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-ribbon3.png b/media/logos/legacy/arch-legacy-ribbon3.png Binary files differdeleted file mode 100644 index c3c00b85..00000000 --- a/media/logos/legacy/arch-legacy-ribbon3.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-ribbon4.png b/media/logos/legacy/arch-legacy-ribbon4.png Binary files differdeleted file mode 100644 index 33a78edf..00000000 --- a/media/logos/legacy/arch-legacy-ribbon4.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-ribbon6.png b/media/logos/legacy/arch-legacy-ribbon6.png Binary files differdeleted file mode 100644 index 9f275f22..00000000 --- a/media/logos/legacy/arch-legacy-ribbon6.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-wombat-lg.png b/media/logos/legacy/arch-legacy-wombat-lg.png Binary files differdeleted file mode 100644 index 0661b6f5..00000000 --- a/media/logos/legacy/arch-legacy-wombat-lg.png +++ /dev/null diff --git a/media/logos/legacy/arch-legacy-wombat.png b/media/logos/legacy/arch-legacy-wombat.png Binary files differdeleted file mode 100644 index 67e1afac..00000000 --- a/media/logos/legacy/arch-legacy-wombat.png +++ /dev/null diff --git a/media/silhouette.png b/media/silhouette.png Binary files differdeleted file mode 100644 index afa87cd1..00000000 --- a/media/silhouette.png +++ /dev/null diff --git a/mirrors/admin.py b/mirrors/admin.py index 394b3508..16a97ea2 100644 --- a/mirrors/admin.py +++ b/mirrors/admin.py @@ -1,61 +1,99 @@ -import re +from datetime import datetime +from urlparse import urlparse, urlunsplit from django import forms from django.contrib import admin -from .models import Mirror, MirrorProtocol, MirrorUrl, MirrorRsync +from .models import (Mirror, MirrorProtocol, MirrorUrl, MirrorRsync, + CheckLocation) + class MirrorUrlForm(forms.ModelForm): class Meta: model = MirrorUrl + fields = ('url', 'country', 'bandwidth', 'active') + def clean_url(self): + # is this a valid-looking URL? + url_parts = urlparse(self.cleaned_data["url"]) + if not url_parts.scheme: + raise forms.ValidationError("No URL scheme (protocol) provided.") + if not url_parts.netloc: + raise forms.ValidationError("No URL host provided.") + if url_parts.params or url_parts.query or url_parts.fragment: + raise forms.ValidationError( + "URL parameters, query, and fragment elements are not supported.") # ensure we always save the URL with a trailing slash - url = self.cleaned_data["url"].strip() - if url[-1] == '/': - return url - return url + '/' + path = url_parts.path + if not path.endswith('/'): + path += '/' + url = urlunsplit((url_parts.scheme, url_parts.netloc, path, '', '')) + return url + class MirrorUrlInlineAdmin(admin.TabularInline): model = MirrorUrl form = MirrorUrlForm + readonly_fields = ('protocol', 'has_ipv4', 'has_ipv6') extra = 3 -# ripped off from django.forms.fields, adding netmask ability -ipv4nm_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}(/(\d|[1-2]\d|3[0-2])){0,1}$') -class IPAddressNetmaskField(forms.fields.RegexField): - default_error_messages = { - 'invalid': u'Enter a valid IPv4 address, possibly including netmask.', - } - - def __init__(self, *args, **kwargs): - super(IPAddressNetmaskField, self).__init__(ipv4nm_re, *args, **kwargs) class MirrorRsyncForm(forms.ModelForm): class Meta: model = MirrorRsync - ip = IPAddressNetmaskField(label='IP') + fields = ('ip',) + class MirrorRsyncInlineAdmin(admin.TabularInline): model = MirrorRsync form = MirrorRsyncForm extra = 2 + class MirrorAdminForm(forms.ModelForm): class Meta: model = Mirror - upstream = forms.ModelChoiceField(queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), required=False) + fields = ('name', 'tier', 'upstream', 'admin_email', 'alternate_email', + 'public', 'active', 'isos', 'rsync_user', 'rsync_password', + 'bug', 'notes') + + upstream = forms.ModelChoiceField( + queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), + required=False) + class MirrorAdmin(admin.ModelAdmin): form = MirrorAdminForm - list_display = ('name', 'tier', 'country', 'active', 'public', 'isos', 'admin_email', 'supported_protocols') - list_filter = ('tier', 'country', 'active', 'public') - search_fields = ('name',) + list_display = ('name', 'tier', 'active', 'public', + 'isos', 'admin_email', 'alternate_email') + list_filter = ('tier', 'active', 'public') + search_fields = ('name', 'admin_email', 'alternate_email') + readonly_fields = ('created', 'last_modified') inlines = [ MirrorUrlInlineAdmin, MirrorRsyncInlineAdmin, ] + def save_model(self, request, obj, form, change): + if '~~~' in obj.notes: + date = datetime.utcnow().strftime('%Y-%m-%d') + usertext = request.user.get_full_name() + obj.notes = obj.notes.replace('~~~', '%s (%s)' % (date, usertext)) + obj.save() + + +class MirrorProtocolAdmin(admin.ModelAdmin): + list_display = ('protocol', 'is_download', 'default') + list_filter = ('is_download', 'default') + + +class CheckLocationAdmin(admin.ModelAdmin): + list_display = ('hostname', 'source_ip', 'country', 'created') + search_fields = ('hostname', 'source_ip') + + admin.site.register(Mirror, MirrorAdmin) -admin.site.register(MirrorProtocol) +admin.site.register(MirrorProtocol, MirrorProtocolAdmin) +admin.site.register(CheckLocation, CheckLocationAdmin) # vim: set ts=4 sw=4 et: diff --git a/mirrors/fields.py b/mirrors/fields.py new file mode 100644 index 00000000..e8963edf --- /dev/null +++ b/mirrors/fields.py @@ -0,0 +1,45 @@ +from IPy import IP + +from django import forms +from django.core import validators +from django.core.exceptions import ValidationError +from django.db import models + + +class IPNetworkFormField(forms.Field): + def to_python(self, value): + if value in validators.EMPTY_VALUES: + return None + try: + value = IP(value) + except ValueError as e: + raise ValidationError(str(e)) + return value + + +class IPNetworkField(models.Field): + __metaclass__ = models.SubfieldBase + description = "IPv4 or IPv6 address or subnet" + + def __init__(self, *args, **kwargs): + kwargs['max_length'] = 44 + super(IPNetworkField, self).__init__(*args, **kwargs) + + def get_internal_type(self): + return "IPAddressField" + + def to_python(self, value): + if not value: + return None + return IP(value) + + def get_prep_value(self, value): + value = self.to_python(value) + if not value: + return None + return str(value) + + def formfield(self, **kwargs): + defaults = {'form_class': IPNetworkFormField} + defaults.update(kwargs) + return super(IPNetworkField, self).formfield(**defaults) diff --git a/mirrors/fixtures/mirrorprotocols.json b/mirrors/fixtures/mirrorprotocols.json new file mode 100644 index 00000000..1a07510b --- /dev/null +++ b/mirrors/fixtures/mirrorprotocols.json @@ -0,0 +1,29 @@ +[ + { + "pk": 1, + "model": "mirrors.mirrorprotocol", + "fields": { + "is_download": true, + "default": true, + "protocol": "http" + } + }, + { + "pk": 3, + "model": "mirrors.mirrorprotocol", + "fields": { + "is_download": false, + "default": false, + "protocol": "rsync" + } + }, + { + "pk": 5, + "model": "mirrors.mirrorprotocol", + "fields": { + "is_download": true, + "default": false, + "protocol": "https" + } + } +] diff --git a/mirrors/management/commands/mirrorcheck.py b/mirrors/management/commands/mirrorcheck.py index 1662b15c..1a33073a 100644 --- a/mirrors/management/commands/mirrorcheck.py +++ b/mirrors/management/commands/mirrorcheck.py @@ -9,145 +9,255 @@ we encounter errors, record those as well. Usage: ./manage.py mirrorcheck """ -from django.core.management.base import NoArgsCommand -from django.db.models import Q - -from datetime import datetime, timedelta +from collections import deque +from datetime import datetime +from httplib import HTTPException import logging +import os +from optparse import make_option +from pytz import utc import re import socket +import ssl +import subprocess import sys import time -import thread +import tempfile from threading import Thread +import types from Queue import Queue, Empty import urllib2 -from logging import ERROR, WARNING, INFO, DEBUG +from django.core.management.base import NoArgsCommand +from django.db import transaction +from django.utils.timezone import now + +from mirrors.models import MirrorUrl, MirrorLog, CheckLocation -from mirrors.models import Mirror, MirrorUrl, MirrorLog logging.basicConfig( - level=WARNING, + level=logging.WARNING, format='%(asctime)s -> %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', stream=sys.stderr) logger = logging.getLogger() + class Command(NoArgsCommand): + option_list = NoArgsCommand.option_list + ( + make_option('-t', '--timeout', dest='timeout', type='float', default=10.0, + help='Timeout value for connecting to URL'), + make_option('-l', '--location', dest='location', type='int', + help='ID of CheckLocation object to use for this run'), + ) help = "Runs a check on all known mirror URLs to determine their up-to-date status." def handle_noargs(self, **options): v = int(options.get('verbosity', 0)) if v == 0: - logger.level = ERROR + logger.level = logging.ERROR elif v == 1: - logger.level = WARNING - elif v == 2: - logger.level = DEBUG - - import signal, traceback - handler = lambda sig, stack: traceback.print_stack(stack) - signal.signal(signal.SIGQUIT, handler) - signal.signal(signal.SIGUSR1, handler) - - return check_current_mirrors() - -def parse_rfc3339_datetime(time): - # '2010-09-02 11:05:06+02:00' - m = re.match('^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})([-+])(\d{2}):(\d{2})', time) - if m: - vals = m.groups() - parsed = datetime(int(vals[0]), int(vals[1]), int(vals[2]), - int(vals[3]), int(vals[4]), int(vals[5])) - # now account for time zone offset - sign = vals[6] - offset = timedelta(hours=int(sign + vals[7]), - minutes=int(sign + vals[8])) - # subtract the offset, e.g. '-04:00' should be moved up 4 hours - return parsed - offset - return None - -def check_mirror_url(mirror_url): + logger.level = logging.WARNING + elif v >= 2: + logger.level = logging.DEBUG + + timeout = options.get('timeout') + + urls = MirrorUrl.objects.select_related('protocol').filter( + active=True, mirror__active=True, mirror__public=True) + + location = options.get('location', None) + if location: + location = CheckLocation.objects.get(id=location) + family = location.family + monkeypatch_getaddrinfo(family) + if family == socket.AF_INET6: + urls = urls.filter(has_ipv6=True) + elif family == socket.AF_INET: + urls = urls.filter(has_ipv4=True) + + pool = MirrorCheckPool(urls, location, timeout) + pool.run() + return 0 + + +def monkeypatch_getaddrinfo(force_family=socket.AF_INET): + '''Force the Python socket module to connect over the designated family; + e.g. socket.AF_INET or socket.AF_INET6.''' + orig = socket.getaddrinfo + + def wrapper(host, port, family=0, socktype=0, proto=0, flags=0): + return orig(host, port, force_family, socktype, proto, flags) + + socket.getaddrinfo = wrapper + + +def parse_lastsync(log, data): + '''lastsync file should be an epoch value created by us.''' + try: + parsed_time = datetime.utcfromtimestamp(int(data)) + log.last_sync = parsed_time.replace(tzinfo=utc) + except (TypeError, ValueError): + # it is bad news to try logging the lastsync value; + # sometimes we get a crazy-encoded web page. + # if we couldn't parse a time, this is a failure. + log.last_sync = None + log.error = "Could not parse time from lastsync" + log.is_success = False + + +def check_mirror_url(mirror_url, location, timeout): url = mirror_url.url + 'lastsync' - logger.info("checking URL %s" % url) - log = MirrorLog(url=mirror_url, check_time=datetime.utcnow()) + logger.info("checking URL %s", url) + log = MirrorLog(url=mirror_url, check_time=now(), location=location) + headers = {'User-Agent': 'archweb/1.0'} + req = urllib2.Request(url, None, headers) + start = time.time() try: - start = time.time() - result = urllib2.urlopen(url, timeout=10) + result = urllib2.urlopen(req, timeout=timeout) data = result.read() result.close() end = time.time() - # lastsync should be an epoch value, but some mirrors - # are creating their own in RFC-3339 format: - # '2010-09-02 11:05:06+02:00' - try: - parsed_time = datetime.utcfromtimestamp(int(data)) - except ValueError: - # it is bad news to try logging the lastsync value; - # sometimes we get a crazy-encoded web page. - logger.info("attempting to parse generated lastsync file" - " from mirror %s" % url) - parsed_time = parse_rfc3339_datetime(data) - - log.last_sync = parsed_time + parse_lastsync(log, data) log.duration = end - start - logger.debug("success: %s, %.2f" % (url, log.duration)) - except urllib2.HTTPError, e: + logger.debug("success: %s, %.2f", url, log.duration) + except urllib2.HTTPError as e: + if e.code == 404: + # we have a duration, just not a success + end = time.time() + log.duration = end - start + log.is_success = False + log.error = str(e) + logger.debug("failed: %s, %s", url, log.error) + except urllib2.URLError as e: log.is_success = False - log.error =str(e) - logger.debug("failed: %s, %s" % (url, log.error)) - except urllib2.URLError, e: - log.is_success=False log.error = e.reason + if isinstance(e.reason, types.StringTypes) and \ + re.search(r'550.*No such file', e.reason): + # similar to 404 case above, still record duration + end = time.time() + log.duration = end - start if isinstance(e.reason, socket.timeout): log.error = "Connection timed out." elif isinstance(e.reason, socket.error): - log.error = e.reason.args[1] - logger.debug("failed: %s, %s" % (url, log.error)) + log.error = e.reason.args[-1] + logger.debug("failed: %s, %s", url, log.error) + except HTTPException: + # e.g., BadStatusLine + log.is_success = False + log.error = "Exception in processing HTTP request." + logger.debug("failed: %s, %s", url, log.error) + except ssl.CertificateError as e: + log.is_success = False + log.error = str(e) + logger.debug("failed: %s, %s", url, log.error) + except socket.timeout: + log.is_success = False + log.error = "Connection timed out." + logger.debug("failed: %s, %s", url, log.error) + except socket.error as e: + log.is_success = False + log.error = str(e) + logger.debug("failed: %s, %s", url, log.error) - log.save() return log -def mirror_url_worker(queue): + +def check_rsync_url(mirror_url, location, timeout): + url = mirror_url.url + 'lastsync' + logger.info("checking URL %s", url) + log = MirrorLog(url=mirror_url, check_time=now(), location=location) + + tempdir = tempfile.mkdtemp() + ipopt = '' + if location: + if location.family == socket.AF_INET6: + ipopt = '--ipv6' + elif location.family == socket.AF_INET: + ipopt = '--ipv4' + lastsync_path = os.path.join(tempdir, 'lastsync') + rsync_cmd = ["rsync", "--quiet", "--contimeout=%d" % timeout, + "--timeout=%d" % timeout] + if ipopt: + rsync_cmd.append(ipopt) + rsync_cmd.append(url) + rsync_cmd.append(lastsync_path) + try: + with open(os.devnull, 'w') as devnull: + if logger.isEnabledFor(logging.DEBUG): + logger.debug("rsync cmd: %s", ' '.join(rsync_cmd)) + start = time.time() + proc = subprocess.Popen(rsync_cmd, stdout=devnull, + stderr=subprocess.PIPE) + _, errdata = proc.communicate() + end = time.time() + log.duration = end - start + if proc.returncode != 0: + logger.debug("error: %s, %s", url, errdata) + log.is_success = False + log.error = errdata.strip() + # look at rsync error code- if we had a command error or timed out, + # don't record a duration as it is misleading + if proc.returncode in (1, 30, 35): + log.duration = None + else: + logger.debug("success: %s, %.2f", url, log.duration) + if os.path.exists(lastsync_path): + with open(lastsync_path, 'r') as lastsync: + parse_lastsync(log, lastsync.read()) + else: + parse_lastsync(log, None) + finally: + if os.path.exists(lastsync_path): + os.unlink(lastsync_path) + os.rmdir(tempdir) + + return log + + +def mirror_url_worker(work, output, location, timeout): while True: try: - item = queue.get(block=False) - check_mirror_url(item) - queue.task_done() + url = work.get(block=False) + try: + if url.protocol.protocol == 'rsync': + log = check_rsync_url(url, location, timeout) + elif (url.protocol.protocol == 'ftp' and location and + location.family == socket.AF_INET6): + # IPv6 + FTP don't work; skip checking completely + log = None + else: + log = check_mirror_url(url, location, timeout) + if log: + output.append(log) + finally: + work.task_done() except Empty: return 0 + class MirrorCheckPool(object): - def __init__(self, work, num_threads=10): + def __init__(self, urls, location, timeout=10, num_threads=10): self.tasks = Queue() - for i in work: - self.tasks.put(i) + self.logs = deque() + for url in list(urls): + self.tasks.put(url) self.threads = [] - for i in range(num_threads): - thread = Thread(target=mirror_url_worker, args=(self.tasks,)) + for _ in range(num_threads): + thread = Thread(target=mirror_url_worker, + args=(self.tasks, self.logs, location, timeout)) thread.daemon = True self.threads.append(thread) - def run_and_join(self): + @transaction.atomic + def run(self): logger.debug("starting threads") - for t in self.threads: - t.start() + for thread in self.threads: + thread.start() logger.debug("joining on all threads") self.tasks.join() - -def check_current_mirrors(): - urls = MirrorUrl.objects.filter( - Q(protocol__protocol__iexact='HTTP') | - Q(protocol__protocol__iexact='FTP'), - mirror__active=True, mirror__public=True) - - pool = MirrorCheckPool(urls) - pool.run_and_join() - return 0 - -# For lack of a better place to put it, here is a query to get latest check -# result joined with mirror details: -# SELECT mu.*, m.*, ml.* FROM mirrors_mirrorurl mu JOIN mirrors_mirror m ON mu.mirror_id = m.id JOIN mirrors_mirrorlog ml ON mu.id = ml.url_id LEFT JOIN mirrors_mirrorlog ml2 ON ml.url_id = ml2.url_id AND ml.id < ml2.id WHERE ml2.id IS NULL AND m.active = 1 AND m.public = 1; + logger.debug("processing %d log entries", len(self.logs)) + MirrorLog.objects.bulk_create(self.logs) + logger.debug("log entries saved") # vim: set ts=4 sw=4 et: diff --git a/mirrors/management/commands/mirrorresolv.py b/mirrors/management/commands/mirrorresolv.py new file mode 100644 index 00000000..0e71894b --- /dev/null +++ b/mirrors/management/commands/mirrorresolv.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +""" +mirrorresolv command + +Poll all mirror URLs and determine whether they have IPv4 and/or IPv6 addresses +available. + +Usage: ./manage.py mirrorresolv +""" + +from django.core.management.base import NoArgsCommand + +import sys +import logging +import socket + +from mirrors.models import MirrorUrl + +logging.basicConfig( + level=logging.WARNING, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(NoArgsCommand): + help = "Runs a check on all active mirror URLs to determine if they are reachable via IPv4 and/or v6." + + def handle_noargs(self, **options): + v = int(options.get('verbosity', 0)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.WARNING + elif v >= 2: + logger.level = logging.DEBUG + + return resolve_mirrors() + +def resolve_mirrors(): + logger.debug("requesting list of mirror URLs") + for mirrorurl in MirrorUrl.objects.filter(active=True, mirror__active=True): + try: + # save old values, we can skip no-op updates this way + oldvals = (mirrorurl.has_ipv4, mirrorurl.has_ipv6) + logger.debug("resolving %3i (%s)", mirrorurl.id, mirrorurl.hostname) + families = mirrorurl.address_families() + mirrorurl.has_ipv4 = socket.AF_INET in families + mirrorurl.has_ipv6 = socket.AF_INET6 in families + logger.debug("%s: v4: %s v6: %s", mirrorurl.hostname, + mirrorurl.has_ipv4, mirrorurl.has_ipv6) + # now check new values, only update if new != old + newvals = (mirrorurl.has_ipv4, mirrorurl.has_ipv6) + if newvals != oldvals: + logger.debug("values changed for %s", mirrorurl) + mirrorurl.save(update_fields=('has_ipv4', 'has_ipv6')) + except socket.gaierror, e: + if e.errno == socket.EAI_NONAME: + logger.debug("gaierror resolving %s: %s", mirrorurl.hostname, e) + else: + logger.warn("gaierror resolving %s: %s", mirrorurl.hostname, e) + except socket.error, e: + logger.warn("error resolving %s: %s", mirrorurl.hostname, e) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/migrations/0001_initial.py b/mirrors/migrations/0001_initial.py index 4a3173c5..6f36c9eb 100644 --- a/mirrors/migrations/0001_initial.py +++ b/mirrors/migrations/0001_initial.py @@ -1,17 +1,123 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models +# -*- coding: utf-8 -*- +from __future__ import unicode_literals -class Migration(SchemaMigration): +from django.db import models, migrations +import django_countries.fields +import django.db.models.deletion +import mirrors.fields - def forwards(self, orm): - pass - def backwards(self, orm): - pass +class Migration(migrations.Migration): - models = {} + dependencies = [ + ] - complete_apps = ['mirrors'] + operations = [ + migrations.CreateModel( + name='CheckLocation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('hostname', models.CharField(max_length=255)), + ('source_ip', models.GenericIPAddressField(unique=True, verbose_name=b'source IP', unpack_ipv4=True)), + ('country', django_countries.fields.CountryField(max_length=2)), + ('created', models.DateTimeField(editable=False)), + ], + options={ + 'ordering': ('hostname', 'source_ip'), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Mirror', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(unique=True, max_length=255)), + ('tier', models.SmallIntegerField(default=2, choices=[(0, b'Tier 0'), (1, b'Tier 1'), (2, b'Tier 2'), (-1, b'Untiered')])), + ('admin_email', models.EmailField(max_length=255, blank=True)), + ('alternate_email', models.EmailField(max_length=255, blank=True)), + ('public', models.BooleanField(default=True)), + ('active', models.BooleanField(default=True)), + ('isos', models.BooleanField(default=True, verbose_name=b'ISOs')), + ('rsync_user', models.CharField(default=b'', max_length=50, blank=True)), + ('rsync_password', models.CharField(default=b'', max_length=50, blank=True)), + ('bug', models.PositiveIntegerField(null=True, verbose_name=b'Flyspray bug', blank=True)), + ('notes', models.TextField(blank=True)), + ('created', models.DateTimeField(editable=False)), + ('last_modified', models.DateTimeField(editable=False)), + ('upstream', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='mirrors.Mirror', null=True)), + ], + options={ + 'ordering': ('name',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MirrorLog', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('check_time', models.DateTimeField(db_index=True)), + ('last_sync', models.DateTimeField(null=True)), + ('duration', models.FloatField(null=True)), + ('is_success', models.BooleanField(default=True)), + ('error', models.TextField(default=b'', blank=True)), + ('location', models.ForeignKey(related_name=b'logs', to='mirrors.CheckLocation', null=True)), + ], + options={ + 'get_latest_by': 'check_time', + 'verbose_name': 'mirror check log', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MirrorProtocol', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('protocol', models.CharField(unique=True, max_length=10)), + ('is_download', models.BooleanField(default=True, help_text=b'Is protocol useful for end-users, e.g. HTTP')), + ('default', models.BooleanField(default=True, help_text=b'Included by default when building mirror list?')), + ('created', models.DateTimeField(editable=False)), + ], + options={ + 'ordering': ('protocol',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MirrorRsync', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('ip', mirrors.fields.IPNetworkField(max_length=44, verbose_name=b'IP')), + ('created', models.DateTimeField(editable=False)), + ('mirror', models.ForeignKey(related_name=b'rsync_ips', to='mirrors.Mirror')), + ], + options={ + 'ordering': ('ip',), + 'verbose_name': 'mirror rsync IP', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MirrorUrl', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('url', models.CharField(unique=True, max_length=255, verbose_name=b'URL')), + ('country', django_countries.fields.CountryField(blank=True, max_length=2, db_index=True)), + ('has_ipv4', models.BooleanField(default=True, verbose_name=b'IPv4 capable', editable=False)), + ('has_ipv6', models.BooleanField(default=False, verbose_name=b'IPv6 capable', editable=False)), + ('created', models.DateTimeField(editable=False)), + ('active', models.BooleanField(default=True)), + ('mirror', models.ForeignKey(related_name=b'urls', to='mirrors.Mirror')), + ('protocol', models.ForeignKey(related_name=b'urls', on_delete=django.db.models.deletion.PROTECT, editable=False, to='mirrors.MirrorProtocol')), + ], + options={ + 'verbose_name': 'mirror URL', + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='mirrorlog', + name='url', + field=models.ForeignKey(related_name=b'logs', to='mirrors.MirrorUrl'), + preserve_default=True, + ), + ] diff --git a/mirrors/migrations/0002_mirrorurl_bandwidth.py b/mirrors/migrations/0002_mirrorurl_bandwidth.py new file mode 100644 index 00000000..f0118199 --- /dev/null +++ b/mirrors/migrations/0002_mirrorurl_bandwidth.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mirrors', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='mirrorurl', + name='bandwidth', + field=models.FloatField(null=True, verbose_name=b'bandwidth (mbits)', blank=True), + preserve_default=True, + ), + ] diff --git a/mirrors/migrations/0002_rename_model_tables.py b/mirrors/migrations/0002_rename_model_tables.py deleted file mode 100644 index d510bada..00000000 --- a/mirrors/migrations/0002_rename_model_tables.py +++ /dev/null @@ -1,61 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - depends_on = ( - ('main', '0014_mirror_notes_rsync_optional'), - ) - - def forwards(self, orm): - db.rename_table('main_mirror', 'mirrors_mirror') - db.rename_table('main_mirrorurl', 'mirrors_mirrorurl') - db.rename_table('main_mirrorrsync', 'mirrors_mirrorrsync') - db.rename_table('main_mirrorprotocol', 'mirrors_mirrorprotocol') - - def backwards(self, orm): - db.rename_table('mirrors_mirror', 'main_mirror') - db.rename_table('mirrors_mirrorurl', 'main_mirrorurl') - db.rename_table('mirrors_mirrorrsync', 'main_mirrorrsync') - db.rename_table('mirrors_mirrorprotocol', 'main_mirrorprotocol') - - models = { - 'mirrors.mirror': { - 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mirrors.Mirror']", 'null': 'True'}) - }, - 'mirrors.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'mirrors.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['mirrors.Mirror']"}) - }, - 'mirrors.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['mirrors'] diff --git a/mirrors/migrations/0003_auto__add_mirrorlog.py b/mirrors/migrations/0003_auto__add_mirrorlog.py deleted file mode 100644 index 5b4c225b..00000000 --- a/mirrors/migrations/0003_auto__add_mirrorlog.py +++ /dev/null @@ -1,72 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'MirrorLog' - db.create_table('mirrors_mirrorlog', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('url', self.gf('django.db.models.fields.related.ForeignKey')(related_name='logs', to=orm['mirrors.MirrorUrl'])), - ('check_time', self.gf('django.db.models.fields.DateTimeField')(db_index=True)), - ('last_sync', self.gf('django.db.models.fields.DateTimeField')(null=True)), - ('duration', self.gf('django.db.models.fields.FloatField')(null=True)), - ('is_success', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('error', self.gf('django.db.models.fields.CharField')(default='', max_length=255, blank=True)), - )) - db.send_create_signal('mirrors', ['MirrorLog']) - - def backwards(self, orm): - # Deleting model 'MirrorLog' - db.delete_table('mirrors_mirrorlog') - - models = { - 'mirrors.mirror': { - 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['mirrors.Mirror']", 'null': 'True'}) - }, - 'mirrors.mirrorlog': { - 'Meta': {'object_name': 'MirrorLog'}, - 'check_time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), - 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), - 'error': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_success': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'last_sync': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'url': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': "orm['mirrors.MirrorUrl']"}) - }, - 'mirrors.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'mirrors.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['mirrors.Mirror']"}) - }, - 'mirrors.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['mirrors'] diff --git a/mirrors/models.py b/mirrors/models.py index 85423303..9743d177 100644 --- a/mirrors/models.py +++ b/mirrors/models.py @@ -1,78 +1,189 @@ +from datetime import timedelta +import socket +from urlparse import urlparse + +from django.core.exceptions import ValidationError from django.db import models +from django.db.models.signals import pre_save +from django_countries.fields import CountryField + +from .fields import IPNetworkField +from main.utils import set_created_field -TIER_CHOICES = ( - (0, 'Tier 0'), - (1, 'Tier 1'), - (2, 'Tier 2'), - (-1, 'Untiered'), -) class Mirror(models.Model): - name = models.CharField(max_length=255) + TIER_CHOICES = ( + (0, 'Tier 0'), + (1, 'Tier 1'), + (2, 'Tier 2'), + (-1, 'Untiered'), + ) + + name = models.CharField(max_length=255, unique=True) tier = models.SmallIntegerField(default=2, choices=TIER_CHOICES) - upstream = models.ForeignKey('self', null=True) - country = models.CharField(max_length=255, db_index=True) + upstream = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) admin_email = models.EmailField(max_length=255, blank=True) + alternate_email = models.EmailField(max_length=255, blank=True) public = models.BooleanField(default=True) active = models.BooleanField(default=True) - isos = models.BooleanField(default=True) + isos = models.BooleanField("ISOs", default=True) rsync_user = models.CharField(max_length=50, blank=True, default='') rsync_password = models.CharField(max_length=50, blank=True, default='') + bug = models.PositiveIntegerField("Flyspray bug", null=True, blank=True) notes = models.TextField(blank=True) + created = models.DateTimeField(editable=False) + last_modified = models.DateTimeField(editable=False) class Meta: - ordering = ('country', 'name') + ordering = ('name',) def __unicode__(self): return self.name - def supported_protocols(self): - protocols = MirrorProtocol.objects.filter( - urls__mirror=self).order_by('protocol').distinct() - return ", ".join([p.protocol for p in protocols]) - def downstream(self): return Mirror.objects.filter(upstream=self).order_by('name') def get_absolute_url(self): return '/mirrors/%s/' % self.name + class MirrorProtocol(models.Model): protocol = models.CharField(max_length=10, unique=True) + is_download = models.BooleanField(default=True, + help_text="Is protocol useful for end-users, e.g. HTTP") + default = models.BooleanField(default=True, + help_text="Included by default when building mirror list?") + created = models.DateTimeField(editable=False) + def __unicode__(self): return self.protocol + class Meta: - verbose_name = 'Mirror Protocol' + ordering = ('protocol',) + class MirrorUrl(models.Model): - url = models.CharField(max_length=255) - protocol = models.ForeignKey(MirrorProtocol, related_name="urls") + url = models.CharField("URL", max_length=255, unique=True) + protocol = models.ForeignKey(MirrorProtocol, related_name="urls", + editable=False, on_delete=models.PROTECT) mirror = models.ForeignKey(Mirror, related_name="urls") + country = CountryField(blank=True, db_index=True) + has_ipv4 = models.BooleanField("IPv4 capable", default=True, + editable=False) + has_ipv6 = models.BooleanField("IPv6 capable", default=False, + editable=False) + active = models.BooleanField(default=True) + bandwidth = models.FloatField("bandwidth (mbits)", null=True, blank=True) + created = models.DateTimeField(editable=False) + + class Meta: + verbose_name = 'mirror URL' + def __unicode__(self): return self.url - class Meta: - verbose_name = 'Mirror URL' + + def address_families(self): + hostname = urlparse(self.url).hostname + info = socket.getaddrinfo(hostname, None, 0, socket.SOCK_STREAM) + families = [x[0] for x in info] + return families + + @property + def hostname(self): + return urlparse(self.url).hostname + + def clean(self): + try: + # Auto-map the protocol field by looking at the URL + protocol = urlparse(self.url).scheme + self.protocol = MirrorProtocol.objects.get(protocol=protocol) + except Exception as e: + raise ValidationError(e) + try: + families = self.address_families() + self.has_ipv4 = socket.AF_INET in families + self.has_ipv6 = socket.AF_INET6 in families + except socket.error: + # We don't fail in this case; we'll just set both to False + self.has_ipv4 = False + self.has_ipv6 = False + + def get_absolute_url(self): + return '/mirrors/%s/%d/' % (self.mirror.name, self.pk) + class MirrorRsync(models.Model): - ip = models.CharField(max_length=24) + # max length is 40 chars for full-form IPv6 addr + subnet + ip = IPNetworkField("IP") mirror = models.ForeignKey(Mirror, related_name="rsync_ips") + created = models.DateTimeField(editable=False) + def __unicode__(self): - return "%s" % (self.ip) + return unicode(self.ip) + + class Meta: + verbose_name = 'mirror rsync IP' + ordering = ('ip',) + + +class CheckLocation(models.Model): + hostname = models.CharField(max_length=255) + source_ip = models.GenericIPAddressField('source IP', + unpack_ipv4=True, unique=True) + country = CountryField() + created = models.DateTimeField(editable=False) + class Meta: - verbose_name = 'Mirror Rsync IP' + ordering = ('hostname', 'source_ip') + + def __unicode__(self): + return self.hostname + + @property + def family(self): + info = socket.getaddrinfo(self.source_ip, None, 0, 0, 0, + socket.AI_NUMERICHOST) + families = [x[0] for x in info] + return families[0] + + @property + def ip_version(self): + '''Returns integer '4' or '6'.''' + if self.family == socket.AF_INET6: + return 6 + if self.family == socket.AF_INET: + return 4 + return None + class MirrorLog(models.Model): url = models.ForeignKey(MirrorUrl, related_name="logs") + location = models.ForeignKey(CheckLocation, related_name="logs", null=True) check_time = models.DateTimeField(db_index=True) last_sync = models.DateTimeField(null=True) duration = models.FloatField(null=True) is_success = models.BooleanField(default=True) - error = models.CharField(max_length=255, blank=True, default='') + error = models.TextField(blank=True, default='') + + @property + def delay(self): + if self.last_sync is None: + return None + # sanity check, this shouldn't happen + if self.check_time < self.last_sync: + return timedelta() + return self.check_time - self.last_sync def __unicode__(self): - return "Check of %s at %s" % (url.url, check_time) + return "Check of %s at %s" % (self.url.url, self.check_time) class Meta: - verbose_name = 'Mirror Check Log' + verbose_name = 'mirror check log' + get_latest_by = 'check_time' + + +for model in (Mirror, MirrorProtocol, MirrorUrl, MirrorRsync, CheckLocation): + pre_save.connect(set_created_field, sender=model, + dispatch_uid="mirrors.models") # vim: set ts=4 sw=4 et: diff --git a/mirrors/static/mirror_status.js b/mirrors/static/mirror_status.js new file mode 100644 index 00000000..44c81935 --- /dev/null +++ b/mirrors/static/mirror_status.js @@ -0,0 +1,193 @@ +/* mirror_status.js + * Homepage: https://projects.archlinux.org/archweb.git/ + * Copyright: 2012-2013 The Archweb Team (Dan McGee) + * License: GPLv2 + * + * This file is part of Archweb. + * + * Archweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Archweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Archweb. If not, see <http://www.gnu.org/licenses/>. + */ + +function draw_graphs(location_url, log_url, container_id) { + jQuery.when(jQuery.getJSON(location_url), jQuery.getJSON(log_url)) + .then(function(loc_data, log_data) { + /* use the same color selection for a given URL in every graph */ + var color = d3.scale.category10(); + jQuery.each(loc_data[0].locations, function(i, val) { + mirror_status(container_id, val, log_data[0], color); + }); + }); +} + +function mirror_status(container_id, check_loc, log_data, color) { + + var draw_graph = function(chart_id, data) { + var jq_div = jQuery(chart_id); + var margin = {top: 20, right: 20, bottom: 30, left: 40}, + width = jq_div.width() - margin.left - margin.right, + height = jq_div.height() - margin.top - margin.bottom; + + var x = d3.time.scale.utc().range([0, width]), + y = d3.scale.linear().range([height, 0]), + x_axis = d3.svg.axis().scale(x).orient("bottom"), + y_axis = d3.svg.axis().scale(y).orient("left"); + + /* remove any existing graph first if we are redrawing after resize */ + d3.select(chart_id).select("svg").remove(); + var svg = d3.select(chart_id).append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + x.domain([ + d3.min(data, function(c) { return d3.min(c.logs, function(v) { return v.check_time; }); }), + d3.max(data, function(c) { return d3.max(c.logs, function(v) { return v.check_time; }); }) + ]).nice(d3.time.hour); + y.domain([ + 0, + d3.max(data, function(c) { return d3.max(c.logs, function(v) { return v.duration; }); }) + ]).nice(); + + /* build the axis lines... */ + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(x_axis) + .append("text") + .attr("class", "label") + .attr("x", width) + .attr("y", -6) + .style("text-anchor", "end") + .text("Check Time (UTC)"); + + svg.append("g") + .attr("class", "y axis") + .call(y_axis) + .append("text") + .attr("class", "label") + .attr("transform", "rotate(-90)") + .attr("y", 6) + .attr("dy", ".71em") + .style("text-anchor", "end") + .text("Duration (seconds)"); + + var line = d3.svg.line() + .interpolate("basis") + .x(function(d) { return x(d.check_time); }) + .y(function(d) { return y(d.duration); }); + + /* ...then the points and lines between them. */ + var urls = svg.selectAll(".url") + .data(data) + .enter() + .append("g") + .attr("class", "url"); + + urls.append("path") + .attr("class", "url-line") + .attr("d", function(d) { return line(d.logs); }) + .style("stroke", function(d) { return color(d.url); }); + + urls.selectAll("circle") + .data(function(u) { + return jQuery.map(u.logs, function(l, i) { + return {url: u.url, check_time: l.check_time, duration: l.duration}; + }); + }) + .enter() + .append("circle") + .attr("class", "url-dot") + .attr("r", 3.5) + .attr("cx", function(d) { return x(d.check_time); }) + .attr("cy", function(d) { return y(d.duration); }) + .style("fill", function(d) { return color(d.url); }) + .append("title") + .text(function(d) { return d.url + "\n" + d.duration.toFixed(3) + " secs\n" + d.check_time.toUTCString(); }); + + /* add a legend for good measure */ + var active = jQuery.map(data, function(item, i) { return item.url; }); + var legend = svg.selectAll(".legend") + .data(active) + .enter().append("g") + .attr("class", "legend") + .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); + + legend.append("rect") + .attr("x", width - 18) + .attr("width", 18) + .attr("height", 18) + .style("fill", color); + + legend.append("text") + .attr("x", width - 24) + .attr("y", 9) + .attr("dy", ".35em") + .style("text-anchor", "end") + .text(function(d) { return d; }); + }; + + var filter_data = function(json, location_id) { + return jQuery.map(json.urls, function(url, i) { + var logs = jQuery.map(url.logs, function(log, j) { + if (!log.is_success) { + return null; + } + /* screen by location ID if we were given one */ + if (location_id && log.location_id !== location_id) { + return null; + } + return { + duration: log.duration, + check_time: new Date(log.check_time) + }; + }); + /* don't return URLs without any log info */ + if (logs.length === 0) { + return null; + } + return { + url: url.url, + logs: logs + }; + }); + }; + + var cached_data = filter_data(log_data, check_loc.id); + /* we had a check location with no log data handed to us, skip graphing */ + if (cached_data.length === 0) { + return; + } + + /* create the containers, defer the actual graph drawing */ + var chart_id = 'status-chart-' + check_loc.id; + jQuery(container_id).append('<h3><span class="fam-flag fam-flag-' + check_loc.country_code.toLowerCase() + '" title="' + check_loc.country + '"></span> ' + check_loc.country + ' (' + check_loc.source_ip + '), IPv' + check_loc.ip_version + '</h3>'); + jQuery(container_id).append('<div id="' + chart_id + '" class="visualize-mirror visualize-chart"></div>'); + jQuery(container_id).append('<br/>'); + setTimeout(function() { + draw_graph('#' + chart_id, cached_data); + }, 0); + + /* then hook up a resize handler to redraw if necessary */ + var resize_timeout = null; + var real_resize = function() { + resize_timeout = null; + draw_graph('#' + chart_id, cached_data); + }; + jQuery(window).resize(function() { + if (resize_timeout) { + clearTimeout(resize_timeout); + } + resize_timeout = setTimeout(real_resize, 200); + }); +} diff --git a/mirrors/templatetags/jinja2.py b/mirrors/templatetags/jinja2.py new file mode 100644 index 00000000..04e50238 --- /dev/null +++ b/mirrors/templatetags/jinja2.py @@ -0,0 +1,53 @@ +from datetime import timedelta +from django_jinja import library +from markupsafe import Markup + + +@library.global_function +def country_flag(country): + if not country: + return '' + html = '<span class="fam-flag fam-flag-%s" title="%s"></span> ' % ( + unicode(country.code).lower(), unicode(country.name)) + return Markup(html) + + +@library.filter +def duration(value): + if not value and type(value) != timedelta: + return u'' + # does not take microseconds into account + total_secs = value.seconds + value.days * 24 * 3600 + mins = total_secs // 60 + hrs, mins = divmod(mins, 60) + return '%d:%02d' % (hrs, mins) + + +@library.filter +def hours(value): + if not value and type(value) != timedelta: + return u'' + # does not take microseconds into account + total_secs = value.seconds + value.days * 24 * 3600 + mins = total_secs // 60 + hrs, mins = divmod(mins, 60) + if hrs == 1: + return '%d hour' % hrs + return '%d hours' % hrs + + +@library.filter +def floatvalue(value, arg=2): + if value is None: + return u'' + return '%.*f' % (arg, value) + + +@library.filter +def percentage(value, arg=1): + if not value and type(value) != float: + return u'' + new_val = value * 100.0 + return '%.*f%%' % (arg, new_val) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/templatetags/mirror_status.py b/mirrors/templatetags/mirror_status.py index 0031d83b..c8004e4b 100644 --- a/mirrors/templatetags/mirror_status.py +++ b/mirrors/templatetags/mirror_status.py @@ -1,6 +1,5 @@ from datetime import timedelta from django import template -from django.template.defaultfilters import floatformat register = template.Library() @@ -10,7 +9,7 @@ def duration(value): return u'' # does not take microseconds into account total_secs = value.seconds + value.days * 24 * 3600 - mins, secs = divmod(total_secs, 60) + mins = total_secs // 60 hrs, mins = divmod(mins, 60) return '%d:%02d' % (hrs, mins) @@ -20,17 +19,16 @@ def hours(value): return u'' # does not take microseconds into account total_secs = value.seconds + value.days * 24 * 3600 - mins, secs = divmod(total_secs, 60) + mins = total_secs // 60 hrs, mins = divmod(mins, 60) if hrs == 1: return '%d hour' % hrs return '%d hours' % hrs @register.filter -def percentage(value, arg=-1): - if not value and type(value) != float: +def floatvalue(value, arg=2): + if value is None: return u'' - new_val = value * 100.0 - return floatformat(new_val, arg) + '%' + return '%.*f' % (arg, value) # vim: set ts=4 sw=4 et: diff --git a/mirrors/urls.py b/mirrors/urls.py new file mode 100644 index 00000000..fc510fbb --- /dev/null +++ b/mirrors/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import patterns + +from .views import mirrors, status, mirror_details, url_details +from .views.api import status_json, mirror_details_json, locations_json + +urlpatterns = patterns('', + (r'^$', mirrors, {}, 'mirror-list'), + (r'^status/$', status, {}, 'mirror-status'), + (r'^status/json/$', status_json, {}, 'mirror-status-json'), + (r'^status/tier/(?P<tier>\d+)/$', status, {}, 'mirror-status-tier'), + (r'^status/tier/(?P<tier>\d+)/json/$', status_json, {}, 'mirror-status-tier-json'), + (r'^locations/json/$', locations_json, {}, 'mirror-locations-json'), + (r'^(?P<name>[\.\-\w]+)/$', mirror_details), + (r'^(?P<name>[\.\-\w]+)/json/$', mirror_details_json), + (r'^(?P<name>[\.\-\w]+)/(?P<url_id>\d+)/$', url_details), +) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/urls_mirrorlist.py b/mirrors/urls_mirrorlist.py new file mode 100644 index 00000000..a64656a9 --- /dev/null +++ b/mirrors/urls_mirrorlist.py @@ -0,0 +1,11 @@ +from django.conf.urls import patterns + + +urlpatterns = patterns('mirrors.views.mirrorlist', + (r'^$', 'generate_mirrorlist', {}, 'mirrorlist'), + (r'^all/$', 'find_mirrors', {'countries': ['all']}), + (r'^all/(?P<protocol>[A-z]+)/$', 'find_mirrors_simple', + {}, 'mirrorlist_simple') +) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/utils.py b/mirrors/utils.py index 0463247a..7c2f5d17 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -1,64 +1,150 @@ -from django.db.models import Avg, Count, Max, Min, StdDev - -from main.utils import cache_function -from .models import MirrorLog, MirrorProtocol, MirrorUrl - -import datetime - -default_cutoff = datetime.timedelta(hours=24) - -@cache_function(300) -def get_mirror_statuses(cutoff=default_cutoff): - cutoff_time = datetime.datetime.utcnow() - cutoff - protocols = MirrorProtocol.objects.exclude(protocol__iexact='rsync') - # I swear, this actually has decent performance... - urls = MirrorUrl.objects.select_related('mirror', 'protocol').filter( - mirror__active=True, mirror__public=True, - protocol__in=protocols, - logs__check_time__gte=cutoff_time).annotate( - check_count=Count('logs'), - success_count=Count('logs__duration'), - last_sync=Max('logs__last_sync'), - last_check=Max('logs__check_time'), - duration_avg=Avg('logs__duration'), - duration_stddev=StdDev('logs__duration') - ).order_by('-last_sync', '-duration_avg') - - # The Django ORM makes it really hard to get actual average delay in the - # above query, so run a seperate query for it and we will process the - # results here. - times = MirrorLog.objects.filter(is_success=True, last_sync__isnull=False, - check_time__gte=cutoff_time) - delays = {} - for log in times: - d = log.check_time - log.last_sync - delays.setdefault(log.url_id, []).append(d) +from datetime import timedelta + +from django.db import connection +from django.db.models import Count, Max, Min +from django.utils.dateparse import parse_datetime +from django.utils.timezone import now + +from main.utils import cache_function, database_vendor +from .models import MirrorLog, MirrorUrl + + +DEFAULT_CUTOFF = timedelta(hours=24) + + +def dictfetchall(cursor): + "Returns all rows from a cursor as a dict." + desc = cursor.description + return [ + dict(zip([col[0] for col in desc], row)) + for row in cursor.fetchall() + ] + +def status_data(cutoff_time, mirror_id=None): + if mirror_id is not None: + params = [cutoff_time, mirror_id] + mirror_where = 'AND u.mirror_id = %s' + else: + params = [cutoff_time] + mirror_where = '' + + vendor = database_vendor(MirrorUrl) + if vendor == 'sqlite': + sql = """ +SELECT l.url_id, u.mirror_id, + COUNT(l.id) AS check_count, + COUNT(l.last_sync) AS success_count, + MAX(l.last_sync) AS last_sync, + MAX(l.check_time) AS last_check, + AVG(l.duration) AS duration_avg, + 0.0 AS duration_stddev, + AVG(STRFTIME('%%s', check_time) - STRFTIME('%%s', last_sync)) AS delay +FROM mirrors_mirrorlog l +JOIN mirrors_mirrorurl u ON u.id = l.url_id +WHERE l.check_time >= %s +""" + mirror_where + """ +GROUP BY l.url_id, u.mirror_id +""" + else: + sql = """ +SELECT l.url_id, u.mirror_id, + COUNT(l.id) AS check_count, + COUNT(l.last_sync) AS success_count, + MAX(l.last_sync) AS last_sync, + MAX(l.check_time) AS last_check, + AVG(l.duration) AS duration_avg, + STDDEV(l.duration) AS duration_stddev, + AVG(check_time - last_sync) AS delay +FROM mirrors_mirrorlog l +JOIN mirrors_mirrorurl u ON u.id = l.url_id +WHERE l.check_time >= %s +""" + mirror_where + """ +GROUP BY l.url_id, u.mirror_id +""" + + cursor = connection.cursor() + cursor.execute(sql, params) + url_data = dictfetchall(cursor) + + # sqlite loves to return less than ideal types + if vendor == 'sqlite': + for item in url_data: + if item['delay'] is not None: + item['delay'] = timedelta(seconds=item['delay']) + if item['last_sync'] is not None: + item['last_sync'] = parse_datetime(item['last_sync']) + item['last_check'] = parse_datetime(item['last_check']) + + return {item['url_id']: item for item in url_data} + + +def annotate_url(url, url_data): + '''Given a MirrorURL object, add a few more attributes to it regarding + status, including completion_pct, delay, and score.''' + # set up some sane default values in case we are missing anything + url.success_count = 0 + url.check_count = 0 + url.completion_pct = None + url.duration_avg = None + url.duration_stddev = None + url.last_check = None + url.last_sync = None + url.delay = None + url.score = None + for k, v in url_data.items(): + if k not in ('url_id', 'mirror_id'): + setattr(url, k, v) + + if url.check_count > 0: + url.completion_pct = float(url.success_count) / url.check_count + + if url.delay is not None: + hours = url.delay.days * 24.0 + url.delay.seconds / 3600.0 + + if url.completion_pct > 0.0: + divisor = url.completion_pct + else: + # arbitrary small value + divisor = 0.005 + stddev = url.duration_stddev or 0.0 + url.score = (hours + url.duration_avg + stddev) / divisor + + return url + + +@cache_function(178) +def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): + cutoff_time = now() - cutoff + + urls = MirrorUrl.objects.select_related( + 'mirror', 'protocol').order_by('mirror__id', 'url') + if mirror_id: + urls = urls.filter(mirror_id=mirror_id) + if not show_all: + urls = urls.filter(active=True, mirror__active=True, + mirror__public=True) if urls: - last_check = max([u.last_check for u in urls]) - num_checks = max([u.check_count for u in urls]) - check_info = MirrorLog.objects.filter( - check_time__gte=cutoff_time).aggregate( + url_data = status_data(cutoff_time, mirror_id) + urls = [annotate_url(url, url_data.get(url.id, {})) for url in urls] + last_check = max([u.last_check for u in urls if u.last_check] or [None]) + num_checks = max(u.check_count for u in urls) + check_info = MirrorLog.objects.filter(check_time__gte=cutoff_time) + if mirror_id: + check_info = check_info.filter(url__mirror_id=mirror_id) + check_info = check_info.aggregate( mn=Min('check_time'), mx=Max('check_time')) - check_frequency = (check_info['mx'] - check_info['mn']) / num_checks + if num_checks > 1: + check_frequency = (check_info['mx'] - check_info['mn']) \ + / (num_checks - 1) + else: + check_frequency = None else: + urls = [] last_check = None num_checks = 0 check_frequency = None - for url in urls: - url.completion_pct = float(url.success_count) / num_checks - if url.id in delays: - url_delays = delays[url.id] - d = sum(url_delays, datetime.timedelta()) / len(url_delays) - url.delay = d - hours = d.days * 24.0 + d.seconds / 3600.0 - url.score = hours + url.duration_avg + url.duration_stddev - else: - url.delay = None - url.score = None - url.completion = 0.0 - return { 'cutoff': cutoff, 'last_check': last_check, @@ -67,16 +153,57 @@ def get_mirror_statuses(cutoff=default_cutoff): 'urls': urls, } -@cache_function(300) -def get_mirror_errors(cutoff=default_cutoff): - cutoff_time = datetime.datetime.utcnow() - cutoff + +def get_mirror_errors(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): + cutoff_time = now() - cutoff errors = MirrorLog.objects.filter( is_success=False, check_time__gte=cutoff_time, - url__mirror__active=True, url__mirror__public=True).values( - 'url__url', 'url__protocol__protocol', 'url__mirror__country', - 'error').annotate( + url__mirror__public=True).values('url__id', 'error').annotate( error_count=Count('error'), last_occurred=Max('check_time') ).order_by('-last_occurred', '-error_count') - return list(errors) + + if mirror_id: + errors = errors.filter(url__mirror_id=mirror_id) + if not show_all: + errors = errors.filter(url__active=True, url__mirror__active=True, + url__mirror__public=True) + + errors = list(errors) + to_fetch = [err['url__id'] for err in errors] + urls = MirrorUrl.objects.select_related( + 'mirror', 'protocol').in_bulk(to_fetch) + for err in errors: + err['url'] = urls[err['url__id']] + return errors + + +@cache_function(295) +def get_mirror_url_for_download(cutoff=DEFAULT_CUTOFF): + '''Find a good mirror URL to use for package downloads. If we have mirror + status data available, it is used to determine a good choice by looking at + the last batch of status rows.''' + cutoff_time = now() - cutoff + log_data = MirrorLog.objects.filter( + check_time__gte=cutoff_time).aggregate( + Max('check_time'), Max('last_sync')) + if log_data['check_time__max'] is not None: + min_check_time = log_data['check_time__max'] - timedelta(minutes=5) + min_sync_time = log_data['last_sync__max'] - timedelta(minutes=20) + best_logs = MirrorLog.objects.select_related('url').filter( + is_success=True, + check_time__gte=min_check_time, last_sync__gte=min_sync_time, + url__active=True, + url__mirror__public=True, url__mirror__active=True, + url__protocol__default=True).order_by( + 'duration')[:1] + if best_logs: + return best_logs[0].url + + mirror_urls = MirrorUrl.objects.filter(active=True, + mirror__public=True, mirror__active=True, + protocol__default=True)[:1] + if not mirror_urls: + return None + return mirror_urls[0] # vim: set ts=4 sw=4 et: diff --git a/mirrors/views.py b/mirrors/views.py deleted file mode 100644 index 34385a98..00000000 --- a/mirrors/views.py +++ /dev/null @@ -1,113 +0,0 @@ -from django import forms -from django.db.models import Avg, Count, Max, Min, StdDev -from django.db.models import Q -from django.http import Http404 -from django.shortcuts import get_object_or_404 -from django.views.decorators.csrf import csrf_exempt -from django.views.generic.simple import direct_to_template - -from main.utils import make_choice -from .models import Mirror, MirrorUrl, MirrorProtocol -from .utils import get_mirror_statuses, get_mirror_errors - -import datetime -from operator import attrgetter - -class MirrorlistForm(forms.Form): - country = forms.MultipleChoiceField(required=False) - protocol = forms.MultipleChoiceField(required=False) - use_mirror_status = forms.BooleanField(required=False) - - def __init__(self, *args, **kwargs): - super(MirrorlistForm, self).__init__(*args, **kwargs) - mirrors = Mirror.objects.filter(active=True).values_list( - 'country', flat=True).distinct().order_by('country') - self.fields['country'].choices = make_choice(mirrors) - self.fields['country'].initial = ['Any'] - protos = make_choice( - MirrorProtocol.objects.exclude(protocol__iexact='rsync')) - self.fields['protocol'].choices = protos - self.fields['protocol'].initial = [t[0] for t in protos] - -@csrf_exempt -def generate_mirrorlist(request): - if request.REQUEST.get('country', ''): - form = MirrorlistForm(data=request.REQUEST) - if form.is_valid(): - countries = form.cleaned_data['country'] - protocols = form.cleaned_data['protocol'] - use_status = form.cleaned_data['use_mirror_status'] - return find_mirrors(request, countries, protocols, use_status) - else: - form = MirrorlistForm() - - return direct_to_template(request, 'mirrors/index.html', {'mirrorlist_form': form}) - -def find_mirrors(request, countries=None, protocols=None, use_status=False): - if not protocols: - protocols = MirrorProtocol.objects.exclude( - protocol__iexact='rsync').values_list('protocol', flat=True) - qset = MirrorUrl.objects.select_related().filter( - protocol__protocol__in=protocols, - mirror__public=True, mirror__active=True, mirror__isos=True - ) - if countries and 'all' not in countries: - qset = qset.filter(mirror__country__in=countries) - if not use_status: - urls = qset.order_by('mirror__country', 'mirror__name', 'url') - template = 'mirrors/mirrorlist.txt' - else: - status_info = get_mirror_statuses() - scores = dict([(u.id, u.score) for u in status_info['urls']]) - urls = [] - for u in qset: - u.score = scores[u.id] - if u.score and u.score < 100.0: - urls.append(u) - urls = sorted(urls, key=attrgetter('score')) - template = 'mirrors/mirrorlist_status.txt' - - return direct_to_template(request, template, { - 'mirror_urls': urls, - }, - mimetype='text/plain') - -def mirrors(request): - mirrors = Mirror.objects.select_related().order_by('tier', 'country') - if not request.user.is_authenticated(): - mirrors = mirrors.filter(public=True, active=True) - return direct_to_template(request, 'mirrors/mirrors.html', - {'mirror_list': mirrors}) - -def mirror_details(request, name): - mirror = get_object_or_404(Mirror, name=name) - if not request.user.is_authenticated() and \ - (not mirror.public or not mirror.active): - # TODO: maybe this should be 403? but that would leak existence - raise Http404 - return direct_to_template(request, 'mirrors/mirror_details.html', - {'mirror': mirror}) - -def status(request): - bad_timedelta = datetime.timedelta(days=3) - status_info = get_mirror_statuses() - - urls = status_info['urls'] - good_urls = [] - bad_urls = [] - for url in urls: - # split them into good and bad lists based on delay - if not url.delay or url.delay > bad_timedelta: - bad_urls.append(url) - else: - good_urls.append(url) - - context = status_info.copy() - context.update({ - 'good_urls': good_urls, - 'bad_urls': bad_urls, - 'error_logs': get_mirror_errors(), - }) - return direct_to_template(request, 'mirrors/status.html', context) - -# vim: set ts=4 sw=4 et: diff --git a/mirrors/views/__init__.py b/mirrors/views/__init__.py new file mode 100644 index 00000000..01e8519d --- /dev/null +++ b/mirrors/views/__init__.py @@ -0,0 +1,149 @@ +from datetime import timedelta +from itertools import groupby +from operator import attrgetter, itemgetter + +from django.db import connection +from django.http import Http404 +from django.shortcuts import get_object_or_404, render +from django.utils.timezone import now +from django.views.decorators.http import condition +from django_countries.fields import Country + +from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, + CheckLocation) +from ..utils import get_mirror_statuses, get_mirror_errors + + +def mirrors(request): + mirror_list = Mirror.objects.select_related().order_by('tier', 'name') + protos = MirrorUrl.objects.values_list( + 'mirror_id', 'protocol__protocol').order_by( + 'mirror_id', 'protocol__protocol').distinct() + countries = MirrorUrl.objects.values_list( + 'mirror_id', 'country').order_by( + 'mirror_id', 'country').distinct() + + if not request.user.is_authenticated(): + mirror_list = mirror_list.filter(public=True, active=True) + protos = protos.filter( + mirror__public=True, mirror__active=True, active=True) + countries = countries.filter( + mirror__public=True, mirror__active=True, active=True) + + protos = {k: list(v) for k, v in groupby(protos, key=itemgetter(0))} + countries = {k: list(v) for k, v in groupby(countries, key=itemgetter(0))} + + for mirror in mirror_list: + item_protos = protos.get(mirror.id, []) + mirror.protocols = [item[1] for item in item_protos] + mirror.country = None + item_countries = countries.get(mirror.id, []) + if len(item_countries) == 1: + mirror.country = Country(item_countries[0][1]) + + return render(request, 'mirrors/mirrors.html', + {'mirror_list': mirror_list}) + + +def mirror_details(request, name): + mirror = get_object_or_404(Mirror, name=name) + authorized = request.user.is_authenticated() + if not authorized and \ + (not mirror.public or not mirror.active): + raise Http404 + error_cutoff = timedelta(days=7) + + status_info = get_mirror_statuses(mirror_id=mirror.id, + show_all=authorized) + checked_urls = {url for url in status_info['urls'] \ + if url.mirror_id == mirror.id} + all_urls = mirror.urls.select_related('protocol') + if not authorized: + all_urls = all_urls.filter(active=True) + all_urls = set(all_urls) + # Add dummy data for URLs that we haven't checked recently + other_urls = all_urls.difference(checked_urls) + for url in other_urls: + for attr in ('last_sync', 'completion_pct', 'delay', 'duration_avg', + 'duration_stddev', 'score'): + setattr(url, attr, None) + all_urls = sorted(checked_urls.union(other_urls), key=attrgetter('url')) + + error_logs = get_mirror_errors(mirror_id=mirror.id, cutoff=error_cutoff, + show_all=True) + + context = { + 'mirror': mirror, + 'urls': all_urls, + 'cutoff': error_cutoff, + 'error_logs': error_logs, + } + return render(request, 'mirrors/mirror_details.html', context) + + +def url_details(request, name, url_id): + url = get_object_or_404(MirrorUrl.objects.select_related(), + id=url_id, mirror__name=name) + mirror = url.mirror + authorized = request.user.is_authenticated() + if not authorized and \ + (not mirror.public or not mirror.active or not url.active): + raise Http404 + error_cutoff = timedelta(days=7) + cutoff_time = now() - error_cutoff + logs = MirrorLog.objects.select_related('location').filter( + url=url, check_time__gte=cutoff_time).order_by('-check_time') + + context = { + 'url': url, + 'logs': logs, + } + return render(request, 'mirrors/url_details.html', context) + + +def status_last_modified(request, *args, **kwargs): + cursor = connection.cursor() + cursor.execute("SELECT MAX(check_time) FROM mirrors_mirrorlog") + return cursor.fetchone()[0] + + +@condition(last_modified_func=status_last_modified) +def status(request, tier=None): + if tier is not None: + tier = int(tier) + if tier not in [t[0] for t in Mirror.TIER_CHOICES]: + raise Http404 + bad_timedelta = timedelta(days=3) + status_info = get_mirror_statuses() + + urls = status_info['urls'] + good_urls = [] + bad_urls = [] + for url in urls: + # screen by tier if we were asked to + if tier is not None and url.mirror.tier != tier: + continue + # split them into good and bad lists based on delay + if url.completion_pct is None: + # skip URLs that have never been checked + continue + elif not url.delay or url.delay > bad_timedelta: + bad_urls.append(url) + else: + good_urls.append(url) + + error_logs = get_mirror_errors() + if tier is not None: + error_logs = [log for log in error_logs + if log['url'].mirror.tier == tier] + + context = status_info.copy() + context.update({ + 'good_urls': sorted(good_urls, key=attrgetter('score')), + 'bad_urls': sorted(bad_urls, key=lambda u: u.delay or timedelta.max), + 'error_logs': error_logs, + 'tier': tier, + }) + return render(request, 'mirrors/status.html', context) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/views/api.py b/mirrors/views/api.py new file mode 100644 index 00000000..b72585e6 --- /dev/null +++ b/mirrors/views/api.py @@ -0,0 +1,108 @@ +from datetime import timedelta +import json + +from django.core.serializers.json import DjangoJSONEncoder +from django.http import Http404, HttpResponse +from django.shortcuts import get_object_or_404 +from django.utils.timezone import now + +from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, + CheckLocation) +from ..utils import get_mirror_statuses, DEFAULT_CUTOFF + + +class MirrorStatusJSONEncoder(DjangoJSONEncoder): + '''Base JSONEncoder extended to handle datetime.timedelta and MirrorUrl + serialization. The base class takes care of datetime.datetime types.''' + url_attributes = ('url', 'protocol', 'last_sync', 'completion_pct', + 'delay', 'duration_avg', 'duration_stddev', 'score') + + def default(self, obj): + if isinstance(obj, timedelta): + # always returned as integer seconds + return obj.days * 24 * 3600 + obj.seconds + if isinstance(obj, MirrorUrl): + data = {attr: getattr(obj, attr) for attr in self.url_attributes} + country = obj.country + data['country'] = unicode(country.name) + data['country_code'] = country.code + return data + if isinstance(obj, MirrorProtocol): + return unicode(obj) + return super(MirrorStatusJSONEncoder, self).default(obj) + + +class ExtendedMirrorStatusJSONEncoder(MirrorStatusJSONEncoder): + '''Adds URL check history information.''' + log_attributes = ('check_time', 'last_sync', 'duration', 'is_success', + 'location_id') + + def default(self, obj): + if isinstance(obj, MirrorUrl): + data = super(ExtendedMirrorStatusJSONEncoder, self).default(obj) + cutoff = now() - DEFAULT_CUTOFF + data['logs'] = list(obj.logs.filter( + check_time__gte=cutoff).order_by('check_time')) + return data + if isinstance(obj, MirrorLog): + data = {attr: getattr(obj, attr) for attr in self.log_attributes} + data['error'] = obj.error or None + return data + return super(ExtendedMirrorStatusJSONEncoder, self).default(obj) + + +class LocationJSONEncoder(DjangoJSONEncoder): + '''Base JSONEncoder extended to handle CheckLocation objects.''' + + def default(self, obj): + if isinstance(obj, CheckLocation): + return { + 'id': obj.pk, + 'hostname': obj.hostname, + 'source_ip': obj.source_ip, + 'country': unicode(obj.country.name), + 'country_code': obj.country.code, + 'ip_version': obj.ip_version, + } + return super(LocationJSONEncoder, self).default(obj) + + +def status_json(request, tier=None): + if tier is not None: + tier = int(tier) + if tier not in [t[0] for t in Mirror.TIER_CHOICES]: + raise Http404 + status_info = get_mirror_statuses() + data = status_info.copy() + if tier is not None: + data['urls'] = [url for url in data['urls'] if url.mirror.tier == tier] + data['version'] = 3 + to_json = json.dumps(data, ensure_ascii=False, cls=MirrorStatusJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + + +def mirror_details_json(request, name): + authorized = request.user.is_authenticated() + mirror = get_object_or_404(Mirror, name=name) + if not authorized and (not mirror.public or not mirror.active): + raise Http404 + status_info = get_mirror_statuses(mirror_id=mirror.id, + show_all=authorized) + data = status_info.copy() + data['version'] = 3 + to_json = json.dumps(data, ensure_ascii=False, + cls=ExtendedMirrorStatusJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + + +def locations_json(request): + data = {} + data['version'] = 1 + data['locations'] = list(CheckLocation.objects.all().order_by('pk')) + to_json = json.dumps(data, ensure_ascii=False, cls=LocationJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/views/mirrorlist.py b/mirrors/views/mirrorlist.py new file mode 100644 index 00000000..3c68d036 --- /dev/null +++ b/mirrors/views/mirrorlist.py @@ -0,0 +1,129 @@ +from operator import attrgetter, itemgetter + +from django import forms +from django.db.models import Q +from django.forms.widgets import SelectMultiple, CheckboxSelectMultiple +from django.shortcuts import get_object_or_404, redirect, render +from django.views.decorators.csrf import csrf_exempt +from django_countries import countries + +from ..models import MirrorUrl, MirrorProtocol +from ..utils import get_mirror_statuses + + +class MirrorlistForm(forms.Form): + country = forms.MultipleChoiceField(required=False, + widget=SelectMultiple(attrs={'size': '12'})) + protocol = forms.MultipleChoiceField(required=False, + widget=CheckboxSelectMultiple) + ip_version = forms.MultipleChoiceField(required=False, + label="IP version", choices=(('4','IPv4'), ('6','IPv6')), + widget=CheckboxSelectMultiple) + use_mirror_status = forms.BooleanField(required=False) + + def __init__(self, *args, **kwargs): + super(MirrorlistForm, self).__init__(*args, **kwargs) + fields = self.fields + fields['country'].choices = [('all','All')] + self.get_countries() + fields['country'].initial = ['all'] + protos = [(p.protocol, p.protocol) for p in + MirrorProtocol.objects.filter(is_download=True)] + initial = MirrorProtocol.objects.filter(is_download=True, default=True) + fields['protocol'].choices = protos + fields['protocol'].initial = [p.protocol for p in initial] + fields['ip_version'].initial = ['4'] + + def get_countries(self): + country_codes = set() + country_codes.update(MirrorUrl.objects.filter(active=True, + mirror__active=True).exclude(country='').values_list( + 'country', flat=True).order_by().distinct()) + code_list = [(code, countries.name(code)) for code in country_codes] + return sorted(code_list, key=itemgetter(1)) + + def as_div(self): + "Returns this form rendered as HTML <divs>s." + return self._html_output( + normal_row = u'<div%(html_class_attr)s>%(label)s %(field)s%(help_text)s</div>', + error_row = u'%s', + row_ender = '</div>', + help_text_html = u' <span class="helptext">%s</span>', + errors_on_separate_row = True) + + +@csrf_exempt +def generate_mirrorlist(request): + if request.method == 'POST' or len(request.GET) > 0: + form = MirrorlistForm(data=request.REQUEST) + if form.is_valid(): + countries = form.cleaned_data['country'] + protocols = form.cleaned_data['protocol'] + use_status = form.cleaned_data['use_mirror_status'] + ipv4 = '4' in form.cleaned_data['ip_version'] + ipv6 = '6' in form.cleaned_data['ip_version'] + return find_mirrors(request, countries, protocols, + use_status, ipv4, ipv6) + else: + form = MirrorlistForm() + + return render(request, 'mirrors/mirrorlist_generate.html', + {'mirrorlist_form': form}) + + +def status_filter(original_urls): + status_info = get_mirror_statuses() + scores = {u.id: u.score for u in status_info['urls']} + urls = [] + for u in original_urls: + u.score = scores.get(u.id, None) + # also include mirrors that don't have an up to date score + # (as opposed to those that have been set with no score) + if (u.id not in scores) or (u.score and u.score < 100.0): + urls.append(u) + # if a url doesn't have a score, treat it as the highest possible + return sorted(urls, key=lambda x: x.score or 100.0) + + +def find_mirrors(request, countries=None, protocols=None, use_status=False, + ipv4_supported=True, ipv6_supported=True): + if not protocols: + protocols = MirrorProtocol.objects.filter(is_download=True) + elif hasattr(protocols, 'model') and protocols.model == MirrorProtocol: + # we already have a queryset, no need to query again + pass + else: + protocols = MirrorProtocol.objects.filter(protocol__in=protocols) + qset = MirrorUrl.objects.select_related().filter( + protocol__in=protocols, active=True, + mirror__public=True, mirror__active=True) + if countries and 'all' not in countries: + qset = qset.filter(country__in=countries) + + ip_version = Q() + if ipv4_supported: + ip_version |= Q(has_ipv4=True) + if ipv6_supported: + ip_version |= Q(has_ipv6=True) + qset = qset.filter(ip_version) + + if not use_status: + sort_key = attrgetter('country.name', 'mirror.name', 'url') + urls = sorted(qset, key=sort_key) + template = 'mirrors/mirrorlist.txt' + else: + urls = status_filter(qset) + template = 'mirrors/mirrorlist_status.txt' + + context = { + 'mirror_urls': urls, + } + return render(request, template, context, content_type='text/plain') + + +def find_mirrors_simple(request, protocol): + if protocol == 'smart': + return redirect('mirrorlist_simple', 'http', permanent=True) + proto = get_object_or_404(MirrorProtocol, protocol=protocol) + return find_mirrors(request, protocols=[proto]) + +# vim: set ts=4 sw=4 et: diff --git a/newrelic.ini b/newrelic.ini new file mode 100644 index 00000000..72158dc4 --- /dev/null +++ b/newrelic.ini @@ -0,0 +1,212 @@ +# --------------------------------------------------------------------------- + +# +# This file configures the New Relic Python Agent. +# +# The path to the configuration file should be supplied to the function +# newrelic.agent.initialize() when the agent is being initialized. +# +# The configuration file follows a structure similar to what you would +# find for Microsoft Windows INI files. For further information on the +# configuration file format see the Python ConfigParser documentation at: +# +# http://docs.python.org/library/configparser.html +# +# For further discussion on the behaviour of the Python agent that can +# be configured via this configuration file see: +# +# http://newrelic.com/docs/python/python-agent-configuration +# + +# --------------------------------------------------------------------------- + +# Here are the settings that are common to all environments. + +[newrelic] + +# You must specify the license key associated with your New +# Relic account. This key binds the Python Agent's data to your +# account in the New Relic service. +#license_key = +# NOTE: this is specified by NEW_RELIC_LICENSE_KEY environment variable +# so this file can live in version control. + +# The appplication name. Set this to be the name of your +# application as you would like it to show up in New Relic UI. +# The UI will then auto-map instances of your application into a +# entry on your home dashboard page. +app_name = Archweb + +# When "true", the agent collects performance data about your +# application and reports this data to the New Relic UI at +# newrelic.com. This global switch is normally overridden for +# each environment below. +monitor_mode = true + +# Sets the name of a file to log agent messages to. Useful for +# debugging any issues with the agent. This is not set by +# default as it is not known in advance what user your web +# application processes will run as and where they have +# permission to write to. Whatever you set this to you must +# ensure that the permissions for the containing directory and +# the file itself are correct, and that the user that your web +# application runs as can write to the file. If not able to +# write out a log file, it is also possible to say "stderr" and +# output to standard error output. This would normally result in +# output appearing in your web server log. +#log_file = /tmp/newrelic-python-agent.log + +# Sets the level of detail of messages sent to the log file, if +# a log file location has been provided. Possible values, in +# increasing order of detail, are: "critical", "error", "warning", +# "info" and "debug". When reporting any agent issues to New +# Relic technical support, the most useful setting for the +# support engineers is "debug". However, this can generate a lot +# of information very quickly, so it is best not to keep the +# agent at this level for longer than it takes to reproduce the +# problem you are experiencing. +log_level = info + +# The Python Agent communicates with the New Relic service using +# SSL by default. Note that this does result in an increase in +# CPU overhead, over and above what would occur for a non SSL +# connection, to perform the encryption involved in the SSL +# communication. This work is though done in a distinct thread +# to those handling your web requests, so it should not impact +# response times. You can if you wish revert to using a non SSL +# connection, but this will result in information being sent +# over a plain socket connection and will not be as secure. +ssl = true + +# High Security Mode enforces certain security settings, and +# prevents them from being overridden, so that no sensitive data +# is sent to New Relic. Enabling High Security Mode means that +# SSL is turned on, request parameters are not collected, and SQL +# can not be sent to New Relic in its raw form. To activate High +# Security Mode, it must be set to 'true' in this local .ini +# configuration file AND be set to 'true' in the server-side +# configuration in the New Relic user interface. For details, see +# https://docs.newrelic.com/docs/subscriptions/high-security +high_security = false + +# The Python Agent will attempt to connect directly to the New +# Relic service. If there is an intermediate firewall between +# your host and the New Relic service that requires you to use a +# HTTP proxy, then you should set both the "proxy_host" and +# "proxy_port" settings to the required values for the HTTP +# proxy. The "proxy_user" and "proxy_pass" settings should +# additionally be set if proxy authentication is implemented by +# the HTTP proxy. The "proxy_scheme" setting dictates what +# protocol scheme is used in talking to the HTTP proxy. This +# would normally always be set as "http" which will result in the +# agent then using a SSL tunnel through the HTTP proxy for end to +# end encryption. +# proxy_scheme = http +# proxy_host = hostname +# proxy_port = 8080 +# proxy_user = +# proxy_pass = + +# Tells the transaction tracer and error collector (when +# enabled) whether or not to capture the query string for the +# URL and send it as the request parameters for display in the +# UI. When "true", it is still possible to exclude specific +# values from being captured using the "ignored_params" setting. +capture_params = false + +# Space separated list of variables that should be removed from +# the query string captured for display as the request +# parameters in the UI. +ignored_params = + +# The transaction tracer captures deep information about slow +# transactions and sends this to the UI on a periodic basis. The +# transaction tracer is enabled by default. Set this to "false" +# to turn it off. +transaction_tracer.enabled = true + +# Threshold in seconds for when to collect a transaction trace. +# When the response time of a controller action exceeds this +# threshold, a transaction trace will be recorded and sent to +# the UI. Valid values are any positive float value, or (default) +# "apdex_f", which will use the threshold for a dissatisfying +# Apdex controller action - four times the Apdex T value. +transaction_tracer.transaction_threshold = apdex_f + +# When the transaction tracer is on, SQL statements can +# optionally be recorded. The recorder has three modes, "off" +# which sends no SQL, "raw" which sends the SQL statement in its +# original form, and "obfuscated", which strips out numeric and +# string literals. +transaction_tracer.record_sql = obfuscated + +# Threshold in seconds for when to collect stack trace for a SQL +# call. In other words, when SQL statements exceed this +# threshold, then capture and send to the UI the current stack +# trace. This is helpful for pinpointing where long SQL calls +# originate from in an application. +transaction_tracer.stack_trace_threshold = 0.5 + +# Determines whether the agent will capture query plans for slow +# SQL queries. Only supported in MySQL and PostgreSQL. Set this +# to "false" to turn it off. +transaction_tracer.explain_enabled = true + +# Threshold for query execution time below which query plans +# will not not be captured. Relevant only when "explain_enabled" +# is true. +transaction_tracer.explain_threshold = 0.5 + +# Space separated list of function or method names in form +# 'module:function' or 'module:class.function' for which +# additional function timing instrumentation will be added. +transaction_tracer.function_trace = + +# The error collector captures information about uncaught +# exceptions or logged exceptions and sends them to UI for +# viewing. The error collector is enabled by default. Set this +# to "false" to turn it off. +error_collector.enabled = true + +# To stop specific errors from reporting to the UI, set this to +# a space separated list of the Python exception type names to +# ignore. The exception name should be of the form 'module:class'. +error_collector.ignore_errors = + +# Browser monitoring is the Real User Monitoring feature of the UI. +# For those Python web frameworks that are supported, this +# setting enables the auto-insertion of the browser monitoring +# JavaScript fragments. +browser_monitoring.auto_instrument = false + +# A thread profiling session can be scheduled via the UI when +# this option is enabled. The thread profiler will periodically +# capture a snapshot of the call stack for each active thread in +# the application to construct a statistically representative +# call tree. +thread_profiler.enabled = true + +# --------------------------------------------------------------------------- + +# +# The application environments. These are specific settings which +# override the common environment settings. The settings related to a +# specific environment will be used when the environment argument to the +# newrelic.agent.initialize() function has been defined to be either +# "development", "test", "staging" or "production". +# + +[newrelic:development] +monitor_mode = false + +[newrelic:test] +monitor_mode = false + +[newrelic:staging] +app_name = Archweb (Staging) +monitor_mode = true + +[newrelic:production] +monitor_mode = true + +# --------------------------------------------------------------------------- diff --git a/news/admin.py b/news/admin.py index 1b7de1d8..562c16d4 100644 --- a/news/admin.py +++ b/news/admin.py @@ -2,9 +2,14 @@ from django.contrib import admin from .models import News + class NewsAdmin(admin.ModelAdmin): - list_display = ('title', 'author', 'postdate', 'last_modified') - list_filter = ('postdate', 'author') + list_display = ('title', 'author', 'postdate', 'last_modified', 'safe_mode') + list_filter = ('postdate', 'author', 'safe_mode') search_fields = ('title', 'content') + date_hierarchy = 'postdate' + admin.site.register(News, NewsAdmin) + +# vim: set ts=4 sw=4 et: diff --git a/news/migrations/0001_initial.py b/news/migrations/0001_initial.py index e30bf5c9..fc6b6cfb 100644 --- a/news/migrations/0001_initial.py +++ b/news/migrations/0001_initial.py @@ -1,21 +1,37 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models +# -*- coding: utf-8 -*- +from __future__ import unicode_literals -class Migration(SchemaMigration): +from django.db import models, migrations +import django.db.models.deletion +from django.conf import settings - def forwards(self, orm): - pass +class Migration(migrations.Migration): - def backwards(self, orm): - pass + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] - - models = { - - } - - complete_apps = ['news'] + operations = [ + migrations.CreateModel( + name='News', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('slug', models.SlugField(unique=True, max_length=255)), + ('postdate', models.DateTimeField(verbose_name=b'post date', db_index=True)), + ('last_modified', models.DateTimeField(editable=False, db_index=True)), + ('title', models.CharField(max_length=255)), + ('guid', models.CharField(max_length=255, editable=False)), + ('content', models.TextField()), + ('safe_mode', models.BooleanField(default=True)), + ('author', models.ForeignKey(related_name=b'news_author', on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('-postdate',), + 'db_table': 'news', + 'verbose_name_plural': 'news', + 'get_latest_by': 'postdate', + }, + bases=(models.Model,), + ), + ] diff --git a/news/migrations/0002_move_news_in.py b/news/migrations/0002_move_news_in.py deleted file mode 100644 index d6dafad4..00000000 --- a/news/migrations/0002_move_news_in.py +++ /dev/null @@ -1,66 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - depends_on = ( - ('main', '0001_initial'), - ) - - def forwards(self, orm): - pass - - def backwards(self, orm): - pass - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'news.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['news'] diff --git a/news/migrations/0003_new_date_columns_precision.py b/news/migrations/0003_new_date_columns_precision.py deleted file mode 100644 index 21b64443..00000000 --- a/news/migrations/0003_new_date_columns_precision.py +++ /dev/null @@ -1,73 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'News.last_modified' - db.add_column('news', 'last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime.now(), db_index=True, blank=True), keep_default=False) - # Changing field 'News.postdate' - db.alter_column('news', 'postdate', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True)) - # Adding index on 'News', fields ['postdate'] - db.create_index('news', ['postdate']) - - def backwards(self, orm): - # Removing index on 'News', fields ['postdate'] - db.delete_index('news', ['postdate']) - # Deleting field 'News.last_modified' - db.delete_column('news', 'last_modified') - # Changing field 'News.postdate' - db.alter_column('news', 'postdate', self.gf('django.db.models.fields.DateField')(auto_now_add=True)) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'news.news': { - 'Meta': {'ordering': "['-postdate', '-id']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['news'] diff --git a/news/migrations/0004_auto__add_field_news_slug.py b/news/migrations/0004_auto__add_field_news_slug.py deleted file mode 100644 index 7e5dcb79..00000000 --- a/news/migrations/0004_auto__add_field_news_slug.py +++ /dev/null @@ -1,66 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'News.slug' - db.add_column('news', 'slug', self.gf('django.db.models.fields.SlugField')(max_length=255, unique=True, null=True, db_index=True), keep_default=False) - - def backwards(self, orm): - # Deleting field 'News.slug' - db.delete_column('news', 'slug') - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'news.news': { - 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['news'] diff --git a/news/migrations/0005_add_slugs.py b/news/migrations/0005_add_slugs.py deleted file mode 100644 index 2a3b6174..00000000 --- a/news/migrations/0005_add_slugs.py +++ /dev/null @@ -1,78 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -from django.template.defaultfilters import slugify - -class Migration(DataMigration): - - def forwards(self, orm): - existing = list(orm.News.objects.values_list( - 'slug', flat=True).distinct()) - for item in orm.News.objects.all(): - suffixed = slug = slugify(item.title) - suffix = 1 - while suffixed in existing: - suffix += 1 - suffixed = "%s-%d" % (slug, suffix) - - item.slug = suffixed - existing.append(suffixed) - - item.save() - - def backwards(self, orm): - orm.News.obects.all.update(slug=None) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'news.news': { - 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['news'] diff --git a/news/migrations/0006_auto__chg_field_news_slug.py b/news/migrations/0006_auto__chg_field_news_slug.py deleted file mode 100644 index c6c61e84..00000000 --- a/news/migrations/0006_auto__chg_field_news_slug.py +++ /dev/null @@ -1,66 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Changing field 'News.slug' - db.alter_column('news', 'slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=255)) - - def backwards(self, orm): - # Changing field 'News.slug' - db.alter_column('news', 'slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=255, null=True)) - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'news.news': { - 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } - } - - complete_apps = ['news'] diff --git a/news/models.py b/news/models.py index 6c8a7039..a66da8d4 100644 --- a/news/models.py +++ b/news/models.py @@ -1,19 +1,29 @@ from django.db import models from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.utils.safestring import mark_safe +from django.utils.timezone import now + +from main.utils import parse_markdown + class News(models.Model): - id = models.AutoField(primary_key=True) slug = models.SlugField(max_length=255, unique=True) - author = models.ForeignKey(User, related_name='news_author') - postdate = models.DateTimeField("post date", auto_now_add=True, db_index=True) - last_modified = models.DateTimeField(editable=False, - auto_now=True, db_index=True) + author = models.ForeignKey(User, related_name='news_author', + on_delete=models.PROTECT) + postdate = models.DateTimeField("post date", db_index=True) + last_modified = models.DateTimeField(editable=False, db_index=True) title = models.CharField(max_length=255) + guid = models.CharField(max_length=255, editable=False) content = models.TextField() + safe_mode = models.BooleanField(default=True) def get_absolute_url(self): return '/news/%s/' % self.slug + def html(self): + return mark_safe(parse_markdown(self.content, not self.safe_mode)) + def __unicode__(self): return self.title @@ -21,6 +31,23 @@ class News(models.Model): db_table = 'news' verbose_name_plural = 'news' get_latest_by = 'postdate' - ordering = ['-postdate'] + ordering = ('-postdate',) + + +def set_news_fields(sender, **kwargs): + news = kwargs['instance'] + current_time = now() + news.last_modified = current_time + if not news.postdate: + news.postdate = current_time + # http://diveintomark.org/archives/2004/05/28/howto-atom-id + news.guid = 'tag:%s,%s:%s' % (Site.objects.get_current(), + current_time.strftime('%Y-%m-%d'), news.get_absolute_url()) + + +from django.db.models.signals import pre_save + +pre_save.connect(set_news_fields, sender=News, + dispatch_uid="news.models") # vim: set ts=4 sw=4 et: diff --git a/news/urls.py b/news/urls.py new file mode 100644 index 00000000..c13722d4 --- /dev/null +++ b/news/urls.py @@ -0,0 +1,24 @@ +from django.conf.urls import patterns +from django.contrib.auth.decorators import permission_required +from .views import (NewsDetailView, NewsListView, + NewsCreateView, NewsEditView, NewsDeleteView) + + +urlpatterns = patterns('news.views', + (r'^$', NewsListView.as_view(), {}, 'news-list'), + + (r'^preview/$', 'preview'), + # old news URLs, permanent redirect view so we don't break all links + (r'^(?P<object_id>\d+)/$', 'view_redirect'), + + (r'^add/$', + permission_required('news.add_news')(NewsCreateView.as_view())), + (r'^(?P<slug>[-\w]+)/$', + NewsDetailView.as_view()), + (r'^(?P<slug>[-\w]+)/edit/$', + permission_required('news.change_news')(NewsEditView.as_view())), + (r'^(?P<slug>[-\w]+)/delete/$', + permission_required('news.delete_news')(NewsDeleteView.as_view())), +) + +# vim: set ts=4 sw=4 et: diff --git a/news/views.py b/news/views.py index f3d7312f..274ba75d 100644 --- a/news/views.py +++ b/news/views.py @@ -1,91 +1,66 @@ from django import forms -from django.contrib.auth.decorators import permission_required from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect -from django.template.defaultfilters import slugify -from django.views.decorators.cache import never_cache -from django.views.generic import list_detail, create_update -from django.views.generic.simple import direct_to_template - -import markdown +from django.views.decorators.http import require_POST +from django.views.generic import (DetailView, ListView, + CreateView, UpdateView, DeleteView) from .models import News +from main.utils import find_unique_slug, parse_markdown + + +class NewsForm(forms.ModelForm): + class Meta: + model = News + exclude = ('id', 'slug', 'author', 'postdate', 'safe_mode') + + +class NewsDetailView(DetailView): + queryset = News.objects.all().select_related('author') + template_name = "news/view.html" + + +class NewsListView(ListView): + queryset = News.objects.all().select_related('author').defer('content') + template_name = "news/list.html" + paginate_by = 50 + + +class NewsCreateView(CreateView): + model = News + form_class = NewsForm + template_name = "news/add.html" + + def form_valid(self, form): + # special logic, we auto-fill the author and slug fields + newsitem = form.save(commit=False) + newsitem.author = self.request.user + newsitem.slug = find_unique_slug(News, newsitem.title) + newsitem.save() + return super(NewsCreateView, self).form_valid(form) + + +class NewsEditView(UpdateView): + model = News + form_class = NewsForm + template_name = "news/add.html" + + +class NewsDeleteView(DeleteView): + model = News + template_name = "news/delete.html" + success_url = "/news/" + def view_redirect(request, object_id): newsitem = get_object_or_404(News, pk=object_id) return redirect(newsitem, permanent=True) -def view(request, slug=None): - return list_detail.object_detail(request, News.objects.all(), - slug=slug, - template_name="news/view.html", - template_object_name='news') - -#TODO: May as well use a date-based list here sometime -def news_list(request): - return list_detail.object_list(request, - News.objects.all().select_related('author').defer('content'), - paginate_by=50, - template_name="news/list.html", - template_object_name="news") -class NewsForm(forms.ModelForm): - class Meta: - model = News - exclude=('id', 'slug', 'author', 'postdate') - -def find_unique_slug(newsitem): - '''Attempt to find a unique slug for this news item.''' - existing = list(News.objects.values_list('slug', flat=True).distinct()) - - suffixed = slug = slugify(newsitem.title) - suffix = 0 - while suffixed in existing: - suffix += 1 - suffixed = "%s-%d" % (slug, suffix) - - return suffixed - -@permission_required('news.add_news') -@never_cache -def add(request): - if request.POST: - form = NewsForm(request.POST) - if form.is_valid(): - newsitem = form.save(commit=False) - newsitem.author = request.user - newsitem.slug = find_unique_slug(newsitem) - newsitem.save() - return redirect(newsitem.get_absolute_url()) - else: - form = NewsForm() - return direct_to_template(request, 'news/add.html', { 'form': form }) - -@permission_required('news.delete_news') -@never_cache -def delete(request, slug): - return create_update.delete_object(request, - News, - slug=slug, - post_delete_redirect='/news/', - template_name='news/delete.html', - template_object_name='news') - -@permission_required('news.change_news') -@never_cache -def edit(request, slug): - return create_update.update_object(request, - slug=slug, - form_class=NewsForm, - template_name="news/add.html") - -@permission_required('news.change_news') -@never_cache +@require_POST def preview(request): - markup = '' - if request.POST: - data = request.POST.get('data', '') - markup = markdown.markdown(data) + data = request.POST.get('data', '') + markup = parse_markdown(data) return HttpResponse(markup) # vim: set ts=4 sw=4 et: diff --git a/packages/admin.py b/packages/admin.py new file mode 100644 index 00000000..5df0043a --- /dev/null +++ b/packages/admin.py @@ -0,0 +1,62 @@ +from django.contrib import admin + +from .models import (PackageRelation, FlagRequest, + Signoff, SignoffSpecification, Update) + + +class PackageRelationAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'user', 'type', 'created') + list_filter = ('type', 'user') + search_fields = ('pkgbase', 'user__username') + ordering = ('pkgbase', 'user') + date_hierarchy = 'created' + + +class FlagRequestAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'full_version', 'repo', 'created', 'who', + 'is_spam', 'is_legitimate', 'message') + list_filter = ('is_spam', 'is_legitimate', 'repo', 'created') + search_fields = ('pkgbase', 'user_email', 'message') + ordering = ('-created',) + + def get_queryset(self, request): + qs = super(FlagRequestAdmin, self).queryset(request) + return qs.select_related('repo', 'user') + + +class SignoffAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'full_version', 'arch', 'repo', + 'user', 'created', 'revoked') + list_filter = ('arch', 'repo', 'user', 'created') + search_fields = ('pkgbase', 'user__username') + ordering = ('-created',) + + +class SignoffSpecificationAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'full_version', 'arch', 'repo', + 'user', 'created', 'comments') + list_filter = ('arch', 'repo', 'user', 'created') + search_fields = ('pkgbase', 'user__username') + ordering = ('-created',) + + def get_queryset(self, request): + qs = super(SignoffSpecificationAdmin, self).queryset(request) + return qs.select_related('arch', 'repo', 'user') + + +class UpdateAdmin(admin.ModelAdmin): + list_display = ('pkgname', 'repo', 'arch', 'action_flag', + 'old_version', 'new_version', 'created') + list_filter = ('action_flag', 'repo', 'arch', 'created') + search_fields = ('pkgname',) + ordering = ('-created',) + raw_id_fields = ('package',) + + +admin.site.register(PackageRelation, PackageRelationAdmin) +admin.site.register(FlagRequest, FlagRequestAdmin) +admin.site.register(Signoff, SignoffAdmin) +admin.site.register(SignoffSpecification, SignoffSpecificationAdmin) +admin.site.register(Update, UpdateAdmin) + +# vim: set ts=4 sw=4 et: diff --git a/packages/alpm.py b/packages/alpm.py new file mode 100644 index 00000000..3762ea68 --- /dev/null +++ b/packages/alpm.py @@ -0,0 +1,75 @@ +import ctypes +from ctypes.util import find_library +import operator + + +def load_alpm(name=None): + # Load the alpm library and set up some of the functions we might use + if name is None: + name = find_library('alpm') + if name is None: + # couldn't locate the correct library + return None + try: + alpm = ctypes.cdll.LoadLibrary(name) + except OSError: + return None + try: + alpm.alpm_version.argtypes = () + alpm.alpm_version.restype = ctypes.c_char_p + alpm.alpm_pkg_vercmp.argtypes = (ctypes.c_char_p, ctypes.c_char_p) + alpm.alpm_pkg_vercmp.restype = ctypes.c_int + except AttributeError: + return None + + return alpm + + +ALPM = load_alpm() + +class AlpmAPI(object): + OPERATOR_MAP = { + '=': operator.eq, + '==': operator.eq, + '!=': operator.ne, + '<': operator.lt, + '<=': operator.le, + '>': operator.gt, + '>=': operator.ge, + } + + def __init__(self): + self.alpm = ALPM + self.available = ALPM is not None + + def version(self): + if not self.available: + return None + return ALPM.alpm_version() + + def vercmp(self, ver1, ver2): + if not self.available: + return None + return ALPM.alpm_pkg_vercmp(str(ver1), str(ver2)) + + def compare_versions(self, ver1, oper, ver2): + func = self.OPERATOR_MAP.get(oper, None) + if func is None: + raise Exception("Invalid operator %s specified" % oper) + if not self.available: + return None + res = self.vercmp(ver1, ver2) + return func(res, 0) + + +def main(): + api = AlpmAPI() + print api.version() + print api.vercmp(1, 2) + print api.compare_versions(1, '<', 2) + + +if __name__ == '__main__': + main() + +# vim: set ts=4 sw=4 et: diff --git a/packages/management/__init__.py b/packages/management/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/packages/management/__init__.py diff --git a/packages/management/commands/__init__.py b/packages/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/packages/management/commands/__init__.py diff --git a/packages/management/commands/populate_signoffs.py b/packages/management/commands/populate_signoffs.py new file mode 100644 index 00000000..8a025f4e --- /dev/null +++ b/packages/management/commands/populate_signoffs.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +""" +populate_signoffs command + +Pull the latest commit message from SVN for a given package that is +signoff-eligible and does not have an existing comment attached. + +Usage: ./manage.py populate_signoffs +""" + +from datetime import datetime +import logging +import subprocess +import sys +from xml.etree.ElementTree import XML + +from django.conf import settings +from django.core.management.base import NoArgsCommand + +from ...models import SignoffSpecification +from ...utils import get_signoff_groups +from devel.utils import UserFinder + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(NoArgsCommand): + help = """Pull the latest commit message from SVN for a given package that +is signoff-eligible and does not have an existing comment attached""" + + def handle_noargs(self, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + return add_signoff_comments() + +def svn_log(pkgbase, repo): + '''Retrieve the most recent SVN log entry for the given pkgbase and + repository. The configured setting SVN_BASE_URL is used along with the + svn_root for each repository to form the correct URL.''' + path = '%s%s/%s/trunk/' % (settings.SVN_BASE_URL, repo.svn_root, pkgbase) + cmd = ['svn', 'log', '--limit=1', '--xml', path] + log_data = subprocess.check_output(cmd) + # the XML format is very very simple, especially with only one revision + xml = XML(log_data) + revision = int(xml.find('logentry').get('revision')) + date = datetime.strptime(xml.findtext('logentry/date'), + '%Y-%m-%dT%H:%M:%S.%fZ') + return { + 'revision': revision, + 'date': date, + 'author': xml.findtext('logentry/author'), + 'message': xml.findtext('logentry/msg'), + } + +def cached_svn_log(pkgbase, repo): + '''Retrieve the cached version of the SVN log if possible, else delegate to + svn_log() to do the work and cache the result.''' + key = (pkgbase, repo) + if key in cached_svn_log.cache: + return cached_svn_log.cache[key] + log = svn_log(pkgbase, repo) + cached_svn_log.cache[key] = log + return log +cached_svn_log.cache = {} + +def create_specification(package, log, finder): + trimmed_message = log['message'].strip() + required = package.arch.required_signoffs + spec = SignoffSpecification(pkgbase=package.pkgbase, + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, repo=package.repo, + comments=trimmed_message, required=required) + spec.user = finder.find_by_username(log['author']) + return spec + +def add_signoff_comments(): + logger.info("getting all signoff groups") + groups = get_signoff_groups() + logger.info("%d signoff groups found", len(groups)) + + finder = UserFinder() + + for group in groups: + if not group.default_spec: + continue + + logger.debug("getting SVN log for %s (%s)", group.pkgbase, group.repo) + try: + log = cached_svn_log(group.pkgbase, group.repo) + logger.info("creating spec with SVN message for %s", group.pkgbase) + spec = create_specification(group.packages[0], log, finder) + spec.save() + except: + logger.exception("error getting SVN log for %s", group.pkgbase) + +# vim: set ts=4 sw=4 et: diff --git a/packages/management/commands/signoff_report.py b/packages/management/commands/signoff_report.py new file mode 100644 index 00000000..9724e562 --- /dev/null +++ b/packages/management/commands/signoff_report.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +""" +signoff_report command + +Send an email summarizing the state of outstanding signoffs for the given +repository. + +Usage: ./manage.py signoff_report <email> <repository> +""" + +from django.conf import settings +from django.core.mail import send_mail +from django.core.urlresolvers import reverse +from django.core.management.base import BaseCommand, CommandError +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.db.models import Count +from django.template import loader, Context +from django.utils.timezone import now + +from collections import namedtuple +from datetime import timedelta +import logging +from operator import attrgetter +import sys + +from main.models import Repo +from packages.models import Signoff +from packages.utils import get_signoff_groups + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(BaseCommand): + args = "<email> <repository>" + help = "Send a signoff report for the given repository." + + def handle(self, *args, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v >= 2: + logger.level = logging.DEBUG + + if len(args) != 2: + raise CommandError("email and repository must be provided") + + return generate_report(args[0], args[1]) + +def generate_report(email, repo_name): + repo = Repo.objects.get(name__iexact=repo_name) + # Collect all existing signoffs for these packages + signoff_groups = sorted(get_signoff_groups([repo]), + key=attrgetter('target_repo', 'arch', 'pkgbase')) + disabled = [] + bad = [] + complete = [] + incomplete = [] + new = [] + old = [] + + new_hours = 24 + old_days = 14 + current_time = now() + new_cutoff = current_time - timedelta(hours=new_hours) + old_cutoff = current_time - timedelta(days=old_days) + + if len(signoff_groups) == 0: + # no need to send an email at all + return + + for group in signoff_groups: + spec = group.specification + if spec.known_bad: + bad.append(group) + elif not spec.enabled: + disabled.append(group) + elif group.approved(): + complete.append(group) + else: + incomplete.append(group) + + if group.package.last_update > new_cutoff: + new.append(group) + if group.package.last_update < old_cutoff: + old.append(group) + + old.sort(key=attrgetter('last_update')) + + proto = 'https' + domain = Site.objects.get_current().domain + signoffs_url = '%s://%s%s' % (proto, domain, reverse('package-signoffs')) + + # and the fun bit + Leader = namedtuple('Leader', ['user', 'count']) + leaders = Signoff.objects.filter(created__gt=new_cutoff, + revoked__isnull=True).values_list('user').annotate( + signoff_count=Count('pk')).order_by('-signoff_count')[:5] + users = User.objects.in_bulk([l[0] for l in leaders]) + leaders = (Leader(users[l[0]], l[1]) for l in leaders) + + subject = 'Signoff report for [%s]' % repo.name.lower() + t = loader.get_template('packages/signoff_report.txt') + c = Context({ + 'repo': repo, + 'signoffs_url': signoffs_url, + 'disabled': disabled, + 'bad': bad, + 'all': signoff_groups, + 'incomplete': incomplete, + 'complete': complete, + 'new': new, + 'new_hours': new_hours, + 'old': old, + 'old_days': old_days, + 'leaders': leaders, + }) + from_addr = settings.BRANDING_EMAIL + send_mail(subject, t.render(c), from_addr, [email]) + +# vim: set ts=4 sw=4 et: diff --git a/packages/migrations/0001_initial.py b/packages/migrations/0001_initial.py index 76e97340..5ecac84a 100644 --- a/packages/migrations/0001_initial.py +++ b/packages/migrations/0001_initial.py @@ -1,72 +1,205 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models +# -*- coding: utf-8 -*- +from __future__ import unicode_literals -class Migration(SchemaMigration): - def forwards(self, orm): - # Adding model 'PackageRelation' - db.create_table('packages_packagerelation', ( - ('pkgbase', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('type', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='package_relations', to=orm['auth.User'])), - )) - db.send_create_signal('packages', ['PackageRelation']) - # Adding unique constraint on 'PackageRelation', fields ['pkgbase', 'user', 'type'] - db.create_unique('packages_packagerelation', ['pkgbase', 'user_id', 'type']) +from django.db import models, migrations +import django.db.models.deletion +from django.conf import settings - def backwards(self, orm): - # Deleting model 'PackageRelation' - db.delete_table('packages_packagerelation') - # Removing unique constraint on 'PackageRelation', fields ['pkgbase', 'user', 'type'] - db.delete_unique('packages_packagerelation', ['pkgbase', 'user_id', 'type']) - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'packages.packagerelation': { - 'Meta': {'unique_together': "(('pkgbase', 'user', 'type'),)", 'object_name': 'PackageRelation'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'type': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_relations'", 'to': "orm['auth.User']"}) - } - } +class Migration(migrations.Migration): - complete_apps = ['packages'] + dependencies = [ + ('main', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Conflict', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255, db_index=True)), + ('version', models.CharField(default=b'', max_length=255)), + ('comparison', models.CharField(default=b'', max_length=255)), + ('pkg', models.ForeignKey(related_name=b'conflicts', to='main.Package')), + ], + options={ + 'ordering': ('name',), + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Depend', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255, db_index=True)), + ('version', models.CharField(default=b'', max_length=255)), + ('comparison', models.CharField(default=b'', max_length=255)), + ('description', models.TextField(null=True, blank=True)), + ('deptype', models.CharField(default=b'D', max_length=1, choices=[(b'D', b'Depend'), (b'O', b'Optional Depend'), (b'M', b'Make Depend'), (b'C', b'Check Depend')])), + ('pkg', models.ForeignKey(related_name=b'depends', to='main.Package')), + ], + options={ + 'ordering': ('name',), + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='FlagRequest', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('user_email', models.EmailField(max_length=75, verbose_name=b'email address')), + ('created', models.DateTimeField(editable=False, db_index=True)), + ('ip_address', models.GenericIPAddressField(verbose_name=b'IP address', unpack_ipv4=True)), + ('pkgbase', models.CharField(max_length=255, db_index=True)), + ('pkgver', models.CharField(max_length=255)), + ('pkgrel', models.CharField(max_length=255)), + ('epoch', models.PositiveIntegerField(default=0)), + ('num_packages', models.PositiveIntegerField(default=1, verbose_name=b'number of packages')), + ('message', models.TextField(verbose_name=b'message to developer', blank=True)), + ('is_spam', models.BooleanField(default=False, help_text=b'Is this comment from a real person?')), + ('is_legitimate', models.BooleanField(default=True, help_text=b'Is this actually an out-of-date flag request?')), + ('repo', models.ForeignKey(to='main.Repo')), + ('user', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True)), + ], + options={ + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='License', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255)), + ('pkg', models.ForeignKey(related_name=b'licenses', to='main.Package')), + ], + options={ + 'ordering': ('name',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PackageGroup', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255, db_index=True)), + ('pkg', models.ForeignKey(related_name=b'groups', to='main.Package')), + ], + options={ + 'ordering': ('name',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PackageRelation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgbase', models.CharField(max_length=255)), + ('type', models.PositiveIntegerField(default=1, choices=[(1, b'Maintainer'), (2, b'Watcher')])), + ('created', models.DateTimeField(editable=False)), + ('user', models.ForeignKey(related_name=b'package_relations', to=settings.AUTH_USER_MODEL)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Provision', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255, db_index=True)), + ('version', models.CharField(default=b'', max_length=255)), + ('pkg', models.ForeignKey(related_name=b'provides', to='main.Package')), + ], + options={ + 'ordering': ('name',), + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Replacement', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255, db_index=True)), + ('version', models.CharField(default=b'', max_length=255)), + ('comparison', models.CharField(default=b'', max_length=255)), + ('pkg', models.ForeignKey(related_name=b'replaces', to='main.Package')), + ], + options={ + 'ordering': ('name',), + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Signoff', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgbase', models.CharField(max_length=255, db_index=True)), + ('pkgver', models.CharField(max_length=255)), + ('pkgrel', models.CharField(max_length=255)), + ('epoch', models.PositiveIntegerField(default=0)), + ('created', models.DateTimeField(editable=False, db_index=True)), + ('revoked', models.DateTimeField(null=True)), + ('comments', models.TextField(null=True, blank=True)), + ('arch', models.ForeignKey(to='main.Arch')), + ('repo', models.ForeignKey(to='main.Repo')), + ('user', models.ForeignKey(related_name=b'package_signoffs', to=settings.AUTH_USER_MODEL)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='SignoffSpecification', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgbase', models.CharField(max_length=255, db_index=True)), + ('pkgver', models.CharField(max_length=255)), + ('pkgrel', models.CharField(max_length=255)), + ('epoch', models.PositiveIntegerField(default=0)), + ('created', models.DateTimeField(editable=False)), + ('required', models.PositiveIntegerField(default=2, help_text=b'How many signoffs are required for this package?')), + ('enabled', models.BooleanField(default=True, help_text=b'Is this package eligible for signoffs?')), + ('known_bad', models.BooleanField(default=False, help_text=b'Is package is known to be broken in some way?')), + ('comments', models.TextField(null=True, blank=True)), + ('arch', models.ForeignKey(to='main.Arch')), + ('repo', models.ForeignKey(to='main.Repo')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Update', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgname', models.CharField(max_length=255, db_index=True)), + ('pkgbase', models.CharField(max_length=255)), + ('action_flag', models.PositiveSmallIntegerField(verbose_name=b'action flag', choices=[(1, b'Addition'), (2, b'Change'), (3, b'Deletion')])), + ('created', models.DateTimeField(editable=False, db_index=True)), + ('old_pkgver', models.CharField(max_length=255, null=True)), + ('old_pkgrel', models.CharField(max_length=255, null=True)), + ('old_epoch', models.PositiveIntegerField(null=True)), + ('new_pkgver', models.CharField(max_length=255, null=True)), + ('new_pkgrel', models.CharField(max_length=255, null=True)), + ('new_epoch', models.PositiveIntegerField(null=True)), + ('arch', models.ForeignKey(related_name=b'updates', to='main.Arch')), + ('package', models.ForeignKey(related_name=b'updates', on_delete=django.db.models.deletion.SET_NULL, to='main.Package', null=True)), + ('repo', models.ForeignKey(related_name=b'updates', to='main.Repo')), + ], + options={ + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='packagerelation', + unique_together=set([('pkgbase', 'user', 'type')]), + ), + ] diff --git a/packages/migrations/0002_populate_package_relation.py b/packages/migrations/0002_populate_package_relation.py deleted file mode 100644 index 738e068f..00000000 --- a/packages/migrations/0002_populate_package_relation.py +++ /dev/null @@ -1,235 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - depends_on = ( - ("main", "0003_migrate_maintainer"), - ) - - def forwards(self, orm): - "Write your forwards methods here." - # search by pkgbase first and insert those records - qs = orm['main.Package'].objects.exclude(maintainer=None).exclude( - pkgbase=None).distinct().values('pkgbase', 'maintainer_id') - for row in qs: - pr, created = orm.PackageRelation.objects.get_or_create( - pkgbase=row['pkgbase'], user__id=row['maintainer_id'], - defaults={'user_id': row['maintainer_id']}) - - # next search by pkgname first and insert those records - qs = orm['main.Package'].objects.exclude(maintainer=None).filter( - pkgbase=None).distinct().values('pkgname', 'maintainer_id') - for row in qs: - pr, created = orm.PackageRelation.objects.get_or_create( - pkgbase=row['pkgname'], user__id=row['maintainer_id'], - defaults={'user_id': row['maintainer_id']}) - - def backwards(self, orm): - "Write your backwards methods here." - if not db.dry_run: - orm.PackageRelation.objects.all().delete() - pass - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.altforum': { - 'Meta': {'object_name': 'AltForum', 'db_table': "'alt_forums'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.donor': { - 'Meta': {'object_name': 'Donor', 'db_table': "'donors'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.externalproject': { - 'Meta': {'object_name': 'ExternalProject'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) - }, - 'main.mirror': { - 'Meta': {'object_name': 'Mirror'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), - 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), - 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), - 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Mirror']", 'null': 'True'}) - }, - 'main.mirrorprotocol': { - 'Meta': {'object_name': 'MirrorProtocol'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) - }, - 'main.mirrorrsync': { - 'Meta': {'object_name': 'MirrorRsync'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"}) - }, - 'main.mirrorurl': { - 'Meta': {'object_name': 'MirrorUrl'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}), - 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.news': { - 'Meta': {'object_name': 'News', 'db_table': "'news'"}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}), - 'content': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}), - 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.packagedepend': { - 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, - 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.packagefile': { - 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.press': { - 'Meta': {'object_name': 'Press', 'db_table': "'press'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'main.signoff': { - 'Meta': {'object_name': 'Signoff'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolist': { - 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'main.todolistpkg': { - 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, - 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'main.userprofile': { - 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, - 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}), - 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), - 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), - 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}), - 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - }, - 'packages.packagerelation': { - 'Meta': {'unique_together': "(('pkgbase', 'user', 'type'),)", 'object_name': 'PackageRelation'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'type': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_relations'", 'to': "orm['auth.User']"}) - } - } - - complete_apps = ['main', 'packages'] diff --git a/packages/migrations/0003_auto__add_packagegroup.py b/packages/migrations/0003_auto__add_packagegroup.py deleted file mode 100644 index c40b6429..00000000 --- a/packages/migrations/0003_auto__add_packagegroup.py +++ /dev/null @@ -1,109 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding model 'PackageGroup' - db.create_table('packages_packagegroup', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('pkg', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['main.Package'])), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - )) - db.send_create_signal('packages', ['PackageGroup']) - - - def backwards(self, orm): - - # Deleting model 'PackageGroup' - db.delete_table('packages_packagegroup') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'main.arch': { - 'Meta': {'object_name': 'Arch', 'db_table': "'arches'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) - }, - 'main.package': { - 'Meta': {'object_name': 'Package', 'db_table': "'packages'"}, - 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), - 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), - 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), - 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) - }, - 'main.repo': { - 'Meta': {'object_name': 'Repo', 'db_table': "'repos'"}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) - }, - 'packages.packagegroup': { - 'Meta': {'object_name': 'PackageGroup'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) - }, - 'packages.packagerelation': { - 'Meta': {'unique_together': "(('pkgbase', 'user', 'type'),)", 'object_name': 'PackageRelation'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'type': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_relations'", 'to': "orm['auth.User']"}) - } - } - - complete_apps = ['packages'] diff --git a/packages/models.py b/packages/models.py index 70ac4fe5..03f03422 100644 --- a/packages/models.py +++ b/packages/models.py @@ -1,6 +1,15 @@ +from collections import namedtuple + from django.db import models +from django.db.models.signals import pre_save +from django.contrib.admin.models import ADDITION, CHANGE, DELETION from django.contrib.auth.models import User +from main.models import Arch, Repo, Package +from main.utils import set_created_field, database_vendor +from packages.alpm import AlpmAPI + + class PackageRelation(models.Model): ''' Represents maintainership (or interest) in a package by a given developer. @@ -17,15 +26,488 @@ class PackageRelation(models.Model): pkgbase = models.CharField(max_length=255) user = models.ForeignKey(User, related_name="package_relations") type = models.PositiveIntegerField(choices=TYPE_CHOICES, default=MAINTAINER) + created = models.DateTimeField(editable=False) + class Meta: unique_together = (('pkgbase', 'user', 'type'),) + def get_associated_packages(self): + return Package.objects.normal().filter(pkgbase=self.pkgbase) + + def repositories(self): + packages = self.get_associated_packages() + return sorted({p.repo for p in packages}) + + def last_update(self): + return Update.objects.filter(pkgbase=self.pkgbase).latest() + + def __unicode__(self): + return u'%s: %s (%s)' % ( + self.pkgbase, self.user, self.get_type_display()) + + +class SignoffSpecificationManager(models.Manager): + def get_from_package(self, pkg): + '''Utility method to pull all relevant name-version fields from a + package and get a matching signoff specification.''' + return self.get( + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + + def get_or_default_from_package(self, pkg): + '''utility method to pull all relevant name-version fields from a + package and get a matching signoff specification, or return the default + base case.''' + try: + return self.get( + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + except SignoffSpecification.DoesNotExist: + return fake_signoff_spec(pkg.arch) + + +class SignoffSpecification(models.Model): + ''' + A specification for the signoff policy for this particular revision of a + package. The default is requiring two signoffs for a given package. These + are created only if necessary; e.g., if one wanted to override the + required=2 attribute, otherwise a sane default object is used. + ''' + pkgbase = models.CharField(max_length=255, db_index=True) + pkgver = models.CharField(max_length=255) + pkgrel = models.CharField(max_length=255) + epoch = models.PositiveIntegerField(default=0) + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) + user = models.ForeignKey(User, null=True) + created = models.DateTimeField(editable=False) + required = models.PositiveIntegerField(default=2, + help_text="How many signoffs are required for this package?") + enabled = models.BooleanField(default=True, + help_text="Is this package eligible for signoffs?") + known_bad = models.BooleanField(default=False, + help_text="Is package is known to be broken in some way?") + comments = models.TextField(null=True, blank=True) + + objects = SignoffSpecificationManager() + + @property + def full_version(self): + if self.epoch > 0: + return u'%d:%s-%s' % (self.epoch, self.pkgver, self.pkgrel) + return u'%s-%s' % (self.pkgver, self.pkgrel) + + def __unicode__(self): + return u'%s-%s' % (self.pkgbase, self.full_version) + + +# Fake signoff specs for when we don't have persisted ones in the database. +# These have all necessary attributes of the real thing but are lighter weight +# and have no chance of being persisted. +FakeSignoffSpecification = namedtuple('FakeSignoffSpecification', + ('required', 'enabled', 'known_bad', 'comments')) + + +def fake_signoff_spec(arch): + return FakeSignoffSpecification(arch.required_signoffs, True, False, u'') + + +class SignoffManager(models.Manager): + def get_from_package(self, pkg, user, revoked=False): + '''Utility method to pull all relevant name-version fields from a + package and get a matching signoff.''' + not_revoked = not revoked + return self.get( + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, + revoked__isnull=not_revoked, user=user) + + def get_or_create_from_package(self, pkg, user): + '''Utility method to pull all relevant name-version fields from a + package and get or create a matching signoff.''' + return self.get_or_create( + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, + revoked=None, user=user) + + def for_package(self, pkg): + return self.select_related('user').filter( + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + +class Signoff(models.Model): + ''' + A signoff for a package (by pkgbase) at a given point in time. These are + not keyed directly to a Package object so they don't ever get deleted when + Packages come and go from testing repositories. + ''' + pkgbase = models.CharField(max_length=255, db_index=True) + pkgver = models.CharField(max_length=255) + pkgrel = models.CharField(max_length=255) + epoch = models.PositiveIntegerField(default=0) + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) + user = models.ForeignKey(User, related_name="package_signoffs") + created = models.DateTimeField(editable=False, db_index=True) + revoked = models.DateTimeField(null=True) + comments = models.TextField(null=True, blank=True) + + objects = SignoffManager() + + @property + def packages(self): + return Package.objects.normal().filter(pkgbase=self.pkgbase, + pkgver=self.pkgver, pkgrel=self.pkgrel, epoch=self.epoch, + arch=self.arch, repo=self.repo) + + @property + def full_version(self): + if self.epoch > 0: + return u'%d:%s-%s' % (self.epoch, self.pkgver, self.pkgrel) + return u'%s-%s' % (self.pkgver, self.pkgrel) + + def __unicode__(self): + revoked = u'' + if self.revoked: + revoked = u' (revoked)' + return u'%s-%s: %s%s' % ( + self.pkgbase, self.full_version, self.user, revoked) + + +class FlagRequest(models.Model): + ''' + A notification the package is out-of-date submitted through the web site. + ''' + user = models.ForeignKey(User, blank=True, null=True) + user_email = models.EmailField('email address') + created = models.DateTimeField(editable=False, db_index=True) + ip_address = models.GenericIPAddressField('IP address', unpack_ipv4=True) + pkgbase = models.CharField(max_length=255, db_index=True) + pkgver = models.CharField(max_length=255) + pkgrel = models.CharField(max_length=255) + epoch = models.PositiveIntegerField(default=0) + repo = models.ForeignKey(Repo) + num_packages = models.PositiveIntegerField('number of packages', default=1) + message = models.TextField('message to developer', blank=True) + is_spam = models.BooleanField(default=False, + help_text="Is this comment from a real person?") + is_legitimate = models.BooleanField(default=True, + help_text="Is this actually an out-of-date flag request?") + + class Meta: + get_latest_by = 'created' + + def who(self): + if self.user: + return self.user.get_full_name() + return self.user_email + + @property + def full_version(self): + # Difference here from other implementations at the moment: we need to + # handle the case of pkgver and pkgrel being null as this table didn't + # originally have version columns. + if self.pkgver == '' and self.pkgrel == '': + return u'' + if self.epoch > 0: + return u'%d:%s-%s' % (self.epoch, self.pkgver, self.pkgrel) + return u'%s-%s' % (self.pkgver, self.pkgrel) + + def get_associated_packages(self): + return Package.objects.normal().filter( + pkgbase=self.pkgbase, + repo__testing=self.repo.testing, + repo__staging=self.repo.staging).order_by( + 'pkgname', 'repo__name', 'arch__name') + + def __unicode__(self): + return u'%s from %s on %s' % (self.pkgbase, self.who(), self.created) + + +class UpdateManager(models.Manager): + def log_update(self, old_pkg, new_pkg): + '''Utility method to help log an update. This will determine the type + based on how many packages are passed in, and will pull the relevant + necesary fields off the given packages. + Note that in some cases, this is a no-op if we know this database type + supports triggers to add these rows instead.''' + if database_vendor(Package, 'write') in ('sqlite', 'postgresql'): + # we log updates using database triggers for these backends + return + update = Update() + if new_pkg: + update.action_flag = ADDITION + update.package = new_pkg + update.arch = new_pkg.arch + update.repo = new_pkg.repo + update.pkgname = new_pkg.pkgname + update.pkgbase = new_pkg.pkgbase + update.new_pkgver = new_pkg.pkgver + update.new_pkgrel = new_pkg.pkgrel + update.new_epoch = new_pkg.epoch + if old_pkg: + if new_pkg: + update.action_flag = CHANGE + # ensure we should even be logging this + if (old_pkg.pkgver == new_pkg.pkgver and + old_pkg.pkgrel == new_pkg.pkgrel and + old_pkg.epoch == new_pkg.epoch): + # all relevant fields were the same; e.g. a force update + return + else: + update.action_flag = DELETION + update.arch = old_pkg.arch + update.repo = old_pkg.repo + update.pkgname = old_pkg.pkgname + update.pkgbase = old_pkg.pkgbase + + update.old_pkgver = old_pkg.pkgver + update.old_pkgrel = old_pkg.pkgrel + update.old_epoch = old_pkg.epoch + + update.save(force_insert=True) + return update + + +class Update(models.Model): + UPDATE_ACTION_CHOICES = ( + (ADDITION, 'Addition'), + (CHANGE, 'Change'), + (DELETION, 'Deletion'), + ) + + package = models.ForeignKey(Package, related_name="updates", + null=True, on_delete=models.SET_NULL) + repo = models.ForeignKey(Repo, related_name="updates") + arch = models.ForeignKey(Arch, related_name="updates") + pkgname = models.CharField(max_length=255, db_index=True) + pkgbase = models.CharField(max_length=255) + action_flag = models.PositiveSmallIntegerField('action flag', + choices=UPDATE_ACTION_CHOICES) + created = models.DateTimeField(editable=False, db_index=True) + + old_pkgver = models.CharField(max_length=255, null=True) + old_pkgrel = models.CharField(max_length=255, null=True) + old_epoch = models.PositiveIntegerField(null=True) + + new_pkgver = models.CharField(max_length=255, null=True) + new_pkgrel = models.CharField(max_length=255, null=True) + new_epoch = models.PositiveIntegerField(null=True) + + objects = UpdateManager() + + class Meta: + get_latest_by = 'created' + + def is_addition(self): + return self.action_flag == ADDITION + + def is_change(self): + return self.action_flag == CHANGE + + def is_deletion(self): + return self.action_flag == DELETION + + @property + def old_version(self): + if self.action_flag == ADDITION: + return None + if self.old_epoch > 0: + return u'%d:%s-%s' % (self.old_epoch, self.old_pkgver, self.old_pkgrel) + return u'%s-%s' % (self.old_pkgver, self.old_pkgrel) + + @property + def new_version(self): + if self.action_flag == DELETION: + return None + if self.new_epoch > 0: + return u'%d:%s-%s' % (self.new_epoch, self.new_pkgver, self.new_pkgrel) + return u'%s-%s' % (self.new_pkgver, self.new_pkgrel) + + def elsewhere(self): + return Package.objects.normal().filter( + pkgname=self.pkgname, arch=self.arch) + + def replacements(self): + pkgs = Package.objects.normal().filter( + replaces__name=self.pkgname) + if not self.arch.agnostic: + # make sure we match architectures if possible + arches = set(Arch.objects.filter(agnostic=True)) + arches.add(self.arch) + pkgs = pkgs.filter(arch__in=arches) + return pkgs + + def __unicode__(self): + return u'%s of %s on %s' % (self.get_action_flag_display(), + self.pkgname, self.created) + + class PackageGroup(models.Model): ''' Represents a group a package is in. There is no actual group entity, only names that link to given packages. ''' - pkg = models.ForeignKey('main.Package') + pkg = models.ForeignKey(Package, related_name='groups') + name = models.CharField(max_length=255, db_index=True) + + def __unicode__(self): + return "%s: %s" % (self.name, self.pkg) + + class Meta: + ordering = ('name',) + + +class License(models.Model): + pkg = models.ForeignKey(Package, related_name='licenses') name = models.CharField(max_length=255) + def __unicode__(self): + return self.name + + class Meta: + ordering = ('name',) + + +class RelatedToBase(models.Model): + '''A base class for conflicts/provides/replaces/etc.''' + name = models.CharField(max_length=255, db_index=True) + version = models.CharField(max_length=255, default='') + + def get_best_satisfier(self): + '''Find a satisfier for this related package that best matches the + given criteria. It will not search provisions, but will find packages + named and matching repo characteristics if possible.''' + pkgs = Package.objects.normal().filter(pkgname=self.name) + # TODO: this may in fact be faster- select only the fields we know will + # actually get used, saving us some bandwidth and hopefully query + # construction time. However, reality hasn't quite proved it out yet. + #pkgs = Package.objects.select_related('repo', 'arch').only( + # 'id', 'pkgname', 'epoch', 'pkgver', 'pkgrel', + # 'repo__id', 'repo__name', 'repo__testing', 'repo__staging', + # 'arch__id', 'arch__name').filter(pkgname=self.name) + if not self.pkg.arch.agnostic: + # make sure we match architectures if possible + arches = self.pkg.applicable_arches() + pkgs = pkgs.filter(arch__in=arches) + # if we have a comparison operation, make sure the packages we grab + # actually satisfy the requirements + if self.comparison and self.version: + alpm = AlpmAPI() + pkgs = [pkg for pkg in pkgs if not alpm.available or + alpm.compare_versions(pkg.full_version, self.comparison, + self.version)] + if len(pkgs) == 0: + # couldn't find a package in the DB + # it should be a virtual depend (or a removed package) + return None + if len(pkgs) == 1: + return pkgs[0] + # more than one package, see if we can't shrink it down + # grab the first though in case we fail + pkg = pkgs[0] + # prevents yet more DB queries, these lists should be short; + # after each grab the best available in case we remove all entries + pkgs = [p for p in pkgs if p.repo.staging == self.pkg.repo.staging] + if len(pkgs) > 0: + pkg = pkgs[0] + + pkgs = [p for p in pkgs if p.repo.testing == self.pkg.repo.testing] + if len(pkgs) > 0: + pkg = pkgs[0] + + return pkg + + def get_providers(self): + '''Return providers of this related package. Does *not* include exact + matches as it checks the Provision names only, use get_best_satisfier() + instead for exact matches.''' + pkgs = Package.objects.normal().filter( + provides__name=self.name).order_by().distinct() + if not self.pkg.arch.agnostic: + # make sure we match architectures if possible + arches = self.pkg.applicable_arches() + pkgs = pkgs.filter(arch__in=arches) + + # If we have a comparison operation, make sure the packages we grab + # actually satisfy the requirements. + alpm = AlpmAPI() + if alpm.available and self.comparison and self.version: + pkgs = pkgs.prefetch_related('provides') + new_pkgs = [] + for package in pkgs: + for provide in package.provides.all(): + if provide.name != self.name: + continue + if alpm.compare_versions(provide.version, + self.comparison, self.version): + new_pkgs.append(package) + pkgs = new_pkgs + + # Sort providers by preference. We sort those in same staging/testing + # combination first, followed by others. We sort by a (staging, + # testing) match tuple that will be (True, True) in the best case. + key_func = lambda x: (x.repo.staging == self.pkg.repo.staging, + x.repo.testing == self.pkg.repo.testing) + return sorted(pkgs, key=key_func, reverse=True) + + def __unicode__(self): + if self.version: + return u'%s%s%s' % (self.name, self.comparison, self.version) + return self.name + + class Meta: + abstract = True + ordering = ('name',) + + +class Depend(RelatedToBase): + DEPTYPE_CHOICES = ( + ('D', 'Depend'), + ('O', 'Optional Depend'), + ('M', 'Make Depend'), + ('C', 'Check Depend'), + ) + + pkg = models.ForeignKey(Package, related_name='depends') + comparison = models.CharField(max_length=255, default='') + description = models.TextField(null=True, blank=True) + deptype = models.CharField(max_length=1, default='D', + choices=DEPTYPE_CHOICES) + + def __unicode__(self): + '''For depends, we may also have a description and a modifier.''' + to_str = super(Depend, self).__unicode__() + if self.description: + return u'%s: %s' % (to_str, self.description) + return to_str + + +class Conflict(RelatedToBase): + pkg = models.ForeignKey(Package, related_name='conflicts') + comparison = models.CharField(max_length=255, default='') + + +class Provision(RelatedToBase): + pkg = models.ForeignKey(Package, related_name='provides') + # comparison must be '=' for provides + + @property + def comparison(self): + if self.version is not None and self.version != '': + return '=' + return None + + +class Replacement(RelatedToBase): + pkg = models.ForeignKey(Package, related_name='replaces') + comparison = models.CharField(max_length=255, default='') + + +# hook up some signals +for sender in (FlagRequest, PackageRelation, + SignoffSpecification, Signoff, Update): + pre_save.connect(set_created_field, sender=sender, + dispatch_uid="packages.models") + # vim: set ts=4 sw=4 et: diff --git a/packages/sql/search_indexes.postgresql_psycopg2.sql b/packages/sql/search_indexes.postgresql_psycopg2.sql new file mode 100644 index 00000000..a7eaf998 --- /dev/null +++ b/packages/sql/search_indexes.postgresql_psycopg2.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE INDEX packages_pkgname_trgm_gist ON packages USING gist (UPPER(pkgname) gist_trgm_ops); +CREATE INDEX packages_pkgdesc_trgm_gist ON packages USING gist (UPPER(pkgdesc) gist_trgm_ops); diff --git a/packages/sql/update.postgresql_psycopg2.sql b/packages/sql/update.postgresql_psycopg2.sql new file mode 100644 index 00000000..6d678387 --- /dev/null +++ b/packages/sql/update.postgresql_psycopg2.sql @@ -0,0 +1,45 @@ +CREATE OR REPLACE FUNCTION packages_on_insert() RETURNS trigger AS $body$ +BEGIN + INSERT INTO packages_update + (action_flag, created, package_id, arch_id, repo_id, pkgname, pkgbase, new_pkgver, new_pkgrel, new_epoch) + VALUES (1, now(), NEW.id, NEW.arch_id, NEW.repo_id, NEW.pkgname, NEW.pkgbase, NEW.pkgver, NEW.pkgrel, NEW.epoch); + RETURN NULL; +END; +$body$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION packages_on_update() RETURNS trigger AS $body$ +BEGIN + INSERT INTO packages_update + (action_flag, created, package_id, arch_id, repo_id, pkgname, pkgbase, old_pkgver, old_pkgrel, old_epoch, new_pkgver, new_pkgrel, new_epoch) + VALUES (2, now(), NEW.id, NEW.arch_id, NEW.repo_id, NEW.pkgname, NEW.pkgbase, OLD.pkgver, OLD.pkgrel, OLD.epoch, NEW.pkgver, NEW.pkgrel, NEW.epoch); + RETURN NULL; +END; +$body$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION packages_on_delete() RETURNS trigger AS $body$ +BEGIN + INSERT INTO packages_update + (action_flag, created, arch_id, repo_id, pkgname, pkgbase, old_pkgver, old_pkgrel, old_epoch) + VALUES (3, now(), OLD.arch_id, OLD.repo_id, OLD.pkgname, OLD.pkgbase, OLD.pkgver, OLD.pkgrel, OLD.epoch); + RETURN NULL; +END; +$body$ LANGUAGE plpgsql; + +DROP TRIGGER IF EXISTS packages_insert ON packages; +CREATE TRIGGER packages_insert + AFTER INSERT ON packages + FOR EACH ROW + EXECUTE PROCEDURE packages_on_insert(); + +DROP TRIGGER IF EXISTS packages_update ON packages; +CREATE TRIGGER packages_update + AFTER UPDATE ON packages + FOR EACH ROW + WHEN (OLD.pkgver != NEW.pkgver OR OLD.pkgrel != NEW.pkgrel OR OLD.epoch != NEW.epoch) + EXECUTE PROCEDURE packages_on_update(); + +DROP TRIGGER IF EXISTS packages_delete ON packages; +CREATE TRIGGER packages_delete + AFTER DELETE ON packages + FOR EACH ROW + EXECUTE PROCEDURE packages_on_delete(); diff --git a/packages/sql/update.sqlite3.sql b/packages/sql/update.sqlite3.sql new file mode 100644 index 00000000..6f151bdd --- /dev/null +++ b/packages/sql/update.sqlite3.sql @@ -0,0 +1,30 @@ +DROP TRIGGER IF EXISTS packages_insert; +CREATE TRIGGER packages_insert + AFTER INSERT ON packages + FOR EACH ROW + BEGIN + INSERT INTO packages_update + (action_flag, created, package_id, arch_id, repo_id, pkgname, pkgbase, new_pkgver, new_pkgrel, new_epoch) + VALUES (1, strftime('%Y-%m-%d %H:%M:%f', 'now'), NEW.id, NEW.arch_id, NEW.repo_id, NEW.pkgname, NEW.pkgbase, NEW.pkgver, NEW.pkgrel, NEW.epoch); + END; + +DROP TRIGGER IF EXISTS packages_update; +CREATE TRIGGER packages_update + AFTER UPDATE ON packages + FOR EACH ROW + WHEN (OLD.pkgver != NEW.pkgver OR OLD.pkgrel != NEW.pkgrel OR OLD.epoch != NEW.epoch) + BEGIN + INSERT INTO packages_update + (action_flag, created, package_id, arch_id, repo_id, pkgname, pkgbase, old_pkgver, old_pkgrel, old_epoch, new_pkgver, new_pkgrel, new_epoch) + VALUES (2, strftime('%Y-%m-%d %H:%M:%f', 'now'), NEW.id, NEW.arch_id, NEW.repo_id, NEW.pkgname, NEW.pkgbase, OLD.pkgver, OLD.pkgrel, OLD.epoch, NEW.pkgver, NEW.pkgrel, NEW.epoch); + END; + +DROP TRIGGER IF EXISTS packages_delete; +CREATE TRIGGER packages_delete + AFTER DELETE ON packages + FOR EACH ROW + BEGIN + INSERT INTO packages_update + (action_flag, created, arch_id, repo_id, pkgname, pkgbase, old_pkgver, old_pkgrel, old_epoch) + VALUES (3, strftime('%Y-%m-%d %H:%M:%f', 'now'), OLD.arch_id, OLD.repo_id, OLD.pkgname, OLD.pkgbase, OLD.pkgver, OLD.pkgrel, OLD.epoch); + END; diff --git a/packages/templatetags/jinja2.py b/packages/templatetags/jinja2.py new file mode 100644 index 00000000..f0b42a09 --- /dev/null +++ b/packages/templatetags/jinja2.py @@ -0,0 +1,91 @@ +from urllib import urlencode, quote as urlquote, unquote +from django.utils.html import escape +from django_jinja import library +from main.templatetags import pgp + + +@library.filter +def url_unquote(original_url): + try: + url = original_url + if isinstance(url, unicode): + url = url.encode('ascii') + url = unquote(url).decode('utf-8') + return url + except UnicodeError: + return original_url + + +def link_encode(url, query): + # massage the data into all utf-8 encoded strings first, so urlencode + # doesn't barf at the data we pass it + query = {k: unicode(v).encode('utf-8') for k, v in query.items()} + data = urlencode(query) + return "%s?%s" % (url, data) + + +@library.global_function +def pgp_key_link(key_id, link_text=None): + return pgp.pgp_key_link(key_id, link_text) + + +@library.global_function +def scm_link(package, operation): + parts = ("abslibre", operation, package.repo.name.lower(), package.pkgbase) + linkbase = ( + "https://projects.parabola.nu/%s.git/%s/%s/%s") + return linkbase % tuple(urlquote(part.encode('utf-8')) for part in parts) + + +@library.global_function +def wiki_link(package): + url = "https://wiki.parabola.nu/index.php" + data = { + 'title': "Special:Search", + 'search': package.pkgname, + } + return link_encode(url, data) + +@library.global_function +def bugs_list(package): + if package.arch.name == 'mips64el': + project = "mips64el" + else: + project = "issue-tracker" + url = "https://labs.parabola.nu/projects/%s/search" % project + data = { + 'titles_only': '1', + 'issues': '1', + 'q': package.pkgname, + } + return link_encode(url, data) + + +@library.global_function +def bug_report(package): + url = "https://labs.parabola.nu/projects/" + if package.arch.name == 'mips64el': + url = url + "mips64el/issues/new" + else: + url = url + "issue-tracker/issues/new" + data = { + 'issue[subject]': '[%s] PLEASE ENTER SUMMARY' % package.pkgname, + } + return link_encode(url, data) + +@library.global_function +def flag_unfree(package): + url = "https://labs.parabola.nu/projects/" + if package.arch.name == 'mips64el': + url = url + "mips64el/issues/new" + else: + url = url + "issue-tracker/issues/new" + data = { + 'issue[tracker_id]': '4', # "freedom issue" + 'issue[priority_id]': '1', # "freedom issue" + 'issue[watcher_user_ids][]': '62', # "dev-list" + 'issue[subject]': '[%s] Please put your reasons here (register first if you haven\'t)' % package.pkgname, + } + return link_encode(url, data) + +# vim: set ts=4 sw=4 et: diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 3cd2b91b..73a39092 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -1,23 +1,37 @@ -import cgi, urllib +from urllib import urlencode +try: + from urlparse import parse_qs +except ImportError: + from cgi import parse_qs + from django import template -from django.utils.html import escape + register = template.Library() + class BuildQueryStringNode(template.Node): def __init__(self, sortfield): self.sortfield = sortfield + super(BuildQueryStringNode, self).__init__() def render(self, context): - qs = dict(cgi.parse_qsl(context['current_query'][1:])) - if qs.has_key('sort') and qs['sort'] == self.sortfield: + qs = parse_qs(context['current_query']) + # This is really dirty. The crazy round trips we do on our query string + # mean we get things like u'\xe2\x98\x83' in our views, when we should + # have simply u'\u2603' or a byte string of the UTF-8 value. Force the + # keys and list of values to be byte strings only. + qs = {k.encode('latin-1'): [v.encode('latin-1') for v in vals] + for k, vals in qs.items()} + if 'sort' in qs and self.sortfield in qs['sort']: if self.sortfield.startswith('-'): - qs['sort'] = self.sortfield[1:] + qs['sort'] = [self.sortfield[1:]] else: - qs['sort'] = '-' + self.sortfield + qs['sort'] = ['-' + self.sortfield] else: - qs['sort'] = self.sortfield - return '?' + urllib.urlencode(qs) + qs['sort'] = [self.sortfield] + return urlencode(qs, True).replace('&', '&') + @register.tag(name='buildsortqs') def do_buildsortqs(parser, token): @@ -25,35 +39,24 @@ def do_buildsortqs(parser, token): tagname, sortfield = token.split_contents() except ValueError: raise template.TemplateSyntaxError( - "%r tag requires a single argument" % tagname) + "%r tag requires a single argument" % token) if not (sortfield[0] == sortfield[-1] and sortfield[0] in ('"', "'")): raise template.TemplateSyntaxError( - "%r tag's argument should be in quotes" % tagname) + "%r tag's argument should be in quotes" % token) return BuildQueryStringNode(sortfield[1:-1]) -@register.tag -def userpkgs(parser, token): - try: - tagname, user = token.split_contents() - except ValueError: - raise template.TemplateSyntaxError( - "%r tag requires a single argument" % tagname) - return UserPkgsNode(user) -class UserPkgsNode(template.Node): - def __init__(self, user): - self.user = template.Variable(user) +@register.simple_tag +def pkg_details_link(pkg, link_title=None, honor_flagged=False): + if not pkg: + return link_title or '' + if link_title is None: + link_title = pkg.pkgname + link_content = link_title + if honor_flagged and pkg.flag_date: + link_content = '<span class="flagged">%s</span>' % link_title + link = '<a href="%s" title="View package details for %s">%s</a>' + return link % (pkg.get_absolute_url(), pkg.pkgname, link_content) - def render(self, context): - try: - real_user = self.user.resolve(context) - # TODO don't hardcode - title = escape('View packages maintained by ' + real_user.get_full_name()) - return '<a href="/packages/search/?maintainer=%s" title="%s">%s</a>' % ( - real_user.username, - title, - real_user.get_full_name(), - ) - except template.VariableDoesNotExist: - return '' - pass + +# vim: set ts=4 sw=4 et: diff --git a/packages/tests.py b/packages/tests.py new file mode 100644 index 00000000..bbe9f00e --- /dev/null +++ b/packages/tests.py @@ -0,0 +1,46 @@ +import unittest + +from .alpm import AlpmAPI + + +alpm = AlpmAPI() + + +class AlpmTestCase(unittest.TestCase): + + @unittest.skipUnless(alpm.available, "ALPM is unavailable") + def test_version(self): + version = alpm.version() + self.assertIsNotNone(version) + version = version.split('.') + # version is a 3-tuple, e.g., '7.0.2' + self.assertEqual(3, len(version)) + + @unittest.skipUnless(alpm.available, "ALPM is unavailable") + def test_vercmp(self): + self.assertEqual(0, alpm.vercmp("1.0", "1.0")) + self.assertEqual(1, alpm.vercmp("1.1", "1.0")) + + @unittest.skipUnless(alpm.available, "ALPM is unavailable") + def test_compare_versions(self): + self.assertTrue(alpm.compare_versions("1.0", "<=", "2.0")) + self.assertTrue(alpm.compare_versions("1.0", "<", "2.0")) + self.assertFalse(alpm.compare_versions("1.0", ">=", "2.0")) + self.assertFalse(alpm.compare_versions("1.0", ">", "2.0")) + self.assertTrue(alpm.compare_versions("1:1.0", ">", "2.0")) + self.assertFalse(alpm.compare_versions("1.0.2", ">=", "2.1.0")) + + self.assertTrue(alpm.compare_versions("1.0", "=", "1.0")) + self.assertTrue(alpm.compare_versions("1.0", "=", "1.0-1")) + self.assertFalse(alpm.compare_versions("1.0", "!=", "1.0")) + + def test_behavior_when_unavailable(self): + mock_alpm = AlpmAPI() + mock_alpm.available = False + + self.assertIsNone(mock_alpm.version()) + self.assertIsNone(mock_alpm.vercmp("1.0", "1.0")) + self.assertIsNone(mock_alpm.compare_versions("1.0", "=", "1.0")) + + +# vim: set ts=4 sw=4 et: diff --git a/packages/urls.py b/packages/urls.py new file mode 100644 index 00000000..dfe19207 --- /dev/null +++ b/packages/urls.py @@ -0,0 +1,42 @@ +from django.conf.urls import include, patterns + +from .views.search import SearchListView + +package_patterns = patterns('packages.views', + (r'^$', 'details'), + (r'^json/$', 'details_json'), + (r'^files/$', 'files'), + (r'^files/json/$', 'files_json'), + (r'^flag/$', 'flag'), + (r'^flag/done/$', 'flag_confirmed', {}, 'package-flag-confirmed'), + (r'^unflag/$', 'unflag'), + (r'^unflag/all/$', 'unflag_all'), + (r'^signoff/$', 'signoff_package'), + (r'^signoff/revoke/$', 'signoff_package', {'revoke': True}), + (r'^signoff/options/$', 'signoff_options'), + (r'^download/$', 'download'), +) + +urlpatterns = patterns('packages.views', + (r'^flaghelp/$', 'flaghelp'), + (r'^signoffs/$', 'signoffs', {}, 'package-signoffs'), + (r'^signoffs/json/$', 'signoffs_json', {}, 'package-signoffs-json'), + (r'^update/$', 'update'), + + (r'^$', SearchListView.as_view(), {}, 'packages-search'), + (r'^search/json/$', 'search_json'), + + (r'^differences/$', 'arch_differences', {}, 'packages-differences'), + (r'^stale_relations/$', 'stale_relations'), + (r'^stale_relations/update/$','stale_relations_update'), + + (r'^(?P<name>[^ /]+)/$', + 'details'), + (r'^(?P<repo>[A-z0-9~\-]+)/(?P<name>[^ /]+)/$', + 'details'), + # canonical package url. subviews defined above + (r'^(?P<repo>[A-z0-9~\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[^ /]+)/', + include(package_patterns)), +) + +# vim: set ts=4 sw=4 et: diff --git a/packages/urls_groups.py b/packages/urls_groups.py new file mode 100644 index 00000000..49ced145 --- /dev/null +++ b/packages/urls_groups.py @@ -0,0 +1,9 @@ +from django.conf.urls import patterns + +urlpatterns = patterns('packages.views', + (r'^$', 'groups', {}, 'groups-list'), + (r'^(?P<arch>[A-z0-9]+)/$', 'groups'), + (r'^(?P<arch>[A-z0-9]+)/(?P<name>[^ /]+)/$', 'group_details'), +) + +# vim: set ts=4 sw=4 et: diff --git a/packages/utils.py b/packages/utils.py index 55b7acf9..c38aa840 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -1,17 +1,42 @@ +from collections import defaultdict +from itertools import chain +from operator import attrgetter, itemgetter +import re + +from django.core.serializers.json import DjangoJSONEncoder from django.db import connection -from django.db.models import Count, Max +from django.db.models import Count, Max, F +from django.db.models.query import QuerySet +from django.contrib.auth.models import User + +from main.models import Package, PackageFile, Arch, Repo +from main.utils import (database_vendor, + groupby_preserve_order, PackageStandin) +from .models import (PackageGroup, PackageRelation, + License, Depend, Conflict, Provision, Replacement, + SignoffSpecification, Signoff, fake_signoff_spec) + + +VERSION_RE = re.compile(r'^((\d+):)?(.+)-([^-]+)$') + -from operator import itemgetter +def parse_version(version): + match = VERSION_RE.match(version) + if not match: + return None, None, 0 + ver = match.group(3) + rel = match.group(4) + if match.group(2): + epoch = int(match.group(2)) + else: + epoch = 0 + return ver, rel, epoch -from main.models import Package -from main.utils import cache_function -from .models import PackageGroup -@cache_function(300) -def get_group_info(): +def get_group_info(include_arches=None): raw_groups = PackageGroup.objects.values_list( 'name', 'pkg__arch__name').order_by('name').annotate( - cnt=Count('pkg'), last_update=Max('pkg__last_update')) + cnt=Count('pkg'), last_update=Max('pkg__last_update')) # now for post_processing. we need to seperate things out and add # the count in for 'any' to all of the other architectures. group_mapping = {} @@ -38,12 +63,30 @@ def get_group_info(): new_g['arch'] = arch arch_groups[grp['name']] = new_g - # now transform it back into a sorted list + # now transform it back into a sorted list, including only the specified + # architectures if we got a list groups = [] - for val in group_mapping.itervalues(): - groups.extend(val.itervalues()) + for key, val in group_mapping.iteritems(): + if not include_arches or key in include_arches: + groups.extend(val.itervalues()) return sorted(groups, key=itemgetter('name', 'arch')) + +def get_split_packages_info(): + '''Return info on split packages that do not have an actual package name + matching the split pkgbase.''' + pkgnames = Package.objects.values('pkgname') + split_pkgs = Package.objects.exclude(pkgname=F('pkgbase')).exclude( + pkgbase__in=pkgnames).values('pkgbase', 'repo', 'arch').annotate( + last_update=Max('last_update')).order_by().distinct() + all_arches = Arch.objects.in_bulk({s['arch'] for s in split_pkgs}) + all_repos = Repo.objects.in_bulk({s['repo'] for s in split_pkgs}) + for split in split_pkgs: + split['arch'] = all_arches[split['arch']] + split['repo'] = all_repos[split['repo']] + return split_pkgs + + class Difference(object): def __init__(self, pkgname, repo, pkg_a, pkg_b): self.pkgname = pkgname @@ -65,12 +108,17 @@ class Difference(object): css_classes.append(self.pkg_b.arch.name) return ' '.join(css_classes) - def __cmp__(self, other): - if isinstance(other, Difference): - return cmp(self.__dict__, other.__dict__) - return False + def __key(self): + return (self.pkgname, hash(self.repo), + hash(self.pkg_a), hash(self.pkg_b)) + + def __eq__(self, other): + return self.__key() == other.__key() + + def __hash__(self): + return hash(self.__key()) + -@cache_function(300) def get_differences_info(arch_a, arch_b): # This is a monster. Join packages against itself, looking for packages in # our non-'any' architectures only, and not having a corresponding package @@ -89,24 +137,25 @@ SELECT p.id, q.id ) WHERE p.arch_id IN (%s, %s) AND ( + q.arch_id IN (%s, %s) + OR q.id IS NULL + ) + AND ( q.id IS NULL - OR - p.pkgver != q.pkgver - OR - p.pkgrel != q.pkgrel + OR p.pkgver != q.pkgver + OR p.pkgrel != q.pkgrel + OR p.epoch != q.epoch ) """ cursor = connection.cursor() - cursor.execute(sql, [arch_a.id, arch_b.id]) + cursor.execute(sql, [arch_a.id, arch_b.id, arch_a.id, arch_b.id]) results = cursor.fetchall() - to_fetch = [] - for row in results: - # column A will always have a value, column B might be NULL - to_fetch.append(row[0]) + # column A will always have a value, column B might be NULL + to_fetch = {row[0] for row in results} # fetch all of the necessary packages - pkgs = Package.objects.in_bulk(to_fetch) - # now build a list of tuples containing differences - differences = [] + pkgs = Package.objects.normal().in_bulk(to_fetch) + # now build a set containing differences + differences = set() for row in results: pkg_a = pkgs.get(row[0]) pkg_b = pkgs.get(row[1]) @@ -119,11 +168,342 @@ SELECT p.id, q.id name = pkg_a.pkgname if pkg_a else pkg_b.pkgname repo = pkg_a.repo if pkg_a else pkg_b.repo item = Difference(name, repo, pkg_b, pkg_a) - if item not in differences: - differences.append(item) + differences.add(item) # now sort our list by repository, package name - differences.sort(key=lambda a: (a.repo.name, a.pkgname)) + key_func = attrgetter('repo.name', 'pkgname') + differences = sorted(differences, key=key_func) return differences + +def multilib_differences(): + # Query for checking multilib out of date-ness + if database_vendor(Package) == 'sqlite': + pkgname_sql = """ + CASE WHEN ml.pkgname LIKE %s + THEN SUBSTR(ml.pkgname, 7) + WHEN ml.pkgname LIKE %s + THEN SUBSTR(ml.pkgname, 1, LENGTH(ml.pkgname) - 9) + ELSE + ml.pkgname + END + """ + else: + pkgname_sql = """ + CASE WHEN ml.pkgname LIKE %s + THEN SUBSTRING(ml.pkgname, 7) + WHEN ml.pkgname LIKE %s + THEN SUBSTRING(ml.pkgname FROM 1 FOR CHAR_LENGTH(ml.pkgname) - 9) + ELSE + ml.pkgname + END + """ + sql = """ +SELECT ml.id, reg.id + FROM packages ml + JOIN packages reg + ON ( + reg.pkgname = (""" + pkgname_sql + """) + AND reg.pkgver != ml.pkgver + ) + JOIN repos r ON reg.repo_id = r.id + WHERE ml.repo_id = %s + AND r.testing = %s + AND r.staging = %s + AND reg.arch_id = %s + ORDER BY ml.last_update + """ + multilib = Repo.objects.get(name__iexact='multilib') + i686 = Arch.objects.get(name='i686') + params = ['lib32-%', '%-multilib', multilib.id, False, False, i686.id] + + cursor = connection.cursor() + cursor.execute(sql, params) + results = cursor.fetchall() + + # fetch all of the necessary packages + to_fetch = set(chain.from_iterable(results)) + pkgs = Package.objects.normal().in_bulk(to_fetch) + + return [(pkgs[ml], pkgs[reg]) for ml, reg in results] + + +def get_wrong_permissions(): + sql = """ +SELECT DISTINCT id + FROM ( + SELECT pr.id, p.repo_id, pr.user_id + FROM packages p + JOIN packages_packagerelation pr ON p.pkgbase = pr.pkgbase + WHERE pr.type = %s + ) mp + LEFT JOIN ( + SELECT user_id, repo_id FROM user_profiles_allowed_repos ar + INNER JOIN user_profiles up ON ar.userprofile_id = up.id + ) ur + ON mp.user_id = ur.user_id AND mp.repo_id = ur.repo_id + WHERE ur.user_id IS NULL; +""" + cursor = connection.cursor() + cursor.execute(sql, [PackageRelation.MAINTAINER]) + to_fetch = [row[0] for row in cursor.fetchall()] + relations = PackageRelation.objects.select_related( + 'user', 'user__userprofile').filter( + id__in=to_fetch) + return relations + + +def attach_maintainers(packages): + '''Given a queryset or something resembling it of package objects, find all + the maintainers and attach them to the packages to prevent N+1 query + cascading.''' + if isinstance(packages, QuerySet): + pkgbases = packages.values('pkgbase') + else: + packages = list(packages) + pkgbases = {p.pkgbase for p in packages if p is not None} + rels = PackageRelation.objects.filter(type=PackageRelation.MAINTAINER, + pkgbase__in=pkgbases).values_list( + 'pkgbase', 'user_id').order_by().distinct() + + # get all the user objects we will need + user_ids = {rel[1] for rel in rels} + users = User.objects.in_bulk(user_ids) + + # now build a pkgbase -> [maintainers...] map + maintainers = defaultdict(list) + for rel in rels: + maintainers[rel[0]].append(users[rel[1]]) + + annotated = [] + # and finally, attach the maintainer lists on the original packages + for package in packages: + if package is None: + continue + package.maintainers = maintainers[package.pkgbase] + annotated.append(package) + + return annotated + + +def approved_by_signoffs(signoffs, spec): + if signoffs: + good_signoffs = sum(1 for s in signoffs if not s.revoked) + return good_signoffs >= spec.required + return False + + +class PackageSignoffGroup(object): + '''Encompasses all packages in testing with the same pkgbase.''' + def __init__(self, packages): + if len(packages) == 0: + raise Exception + self.packages = packages + self.user = None + self.target_repo = None + self.signoffs = set() + self.default_spec = True + + first = packages[0] + self.pkgbase = first.pkgbase + self.arch = first.arch + self.repo = first.repo + self.version = '' + self.last_update = first.last_update + self.packager = first.packager + self.maintainers = first.maintainers + self.specification = fake_signoff_spec(first.arch) + + version = first.full_version + if all(version == pkg.full_version for pkg in packages): + self.version = version + + @property + def package(self): + '''Try and return a relevant single package object representing this + group. Start by seeing if there is only one package, then look for the + matching package by name, finally falling back to a standin package + object.''' + if len(self.packages) == 1: + return self.packages[0] + + same_pkgs = [p for p in self.packages if p.pkgname == p.pkgbase] + if same_pkgs: + return same_pkgs[0] + + return PackageStandin(self.packages[0]) + + def find_signoffs(self, all_signoffs): + '''Look through a list of Signoff objects for ones matching this + particular group and store them on the object.''' + for s in all_signoffs: + if s.pkgbase != self.pkgbase: + continue + if self.version and not s.full_version == self.version: + continue + if s.arch_id == self.arch.id and s.repo_id == self.repo.id: + self.signoffs.add(s) + + def find_specification(self, specifications): + for spec in specifications: + if spec.pkgbase != self.pkgbase: + continue + if self.version and not spec.full_version == self.version: + continue + if spec.arch_id == self.arch.id and spec.repo_id == self.repo.id: + self.specification = spec + self.default_spec = False + return + + def approved(self): + return approved_by_signoffs(self.signoffs, self.specification) + + @property + def completed(self): + return sum(1 for s in self.signoffs if not s.revoked) + + @property + def required(self): + return self.specification.required + + def user_signed_off(self, user=None): + '''Did a given user signoff on this package? user can be passed as an + argument, or attached to the group object itself so this can be called + from a template.''' + if user is None: + user = self.user + return user in (s.user for s in self.signoffs if not s.revoked) + + def __unicode__(self): + return u'%s-%s (%s): %d' % ( + self.pkgbase, self.version, self.arch, len(self.signoffs)) + + +def signoffs_id_query(model, repos): + sql = """ +SELECT DISTINCT s.id + FROM %s s + JOIN packages p ON ( + s.pkgbase = p.pkgbase + AND s.pkgver = p.pkgver + AND s.pkgrel = p.pkgrel + AND s.epoch = p.epoch + AND s.arch_id = p.arch_id + AND s.repo_id = p.repo_id + ) + WHERE p.repo_id IN (%s) + AND s.repo_id IN (%s) + """ + cursor = connection.cursor() + # query pre-process- fill in table name and placeholders for IN + repo_sql = ','.join(['%s' for _ in repos]) + sql = sql % (model._meta.db_table, repo_sql, repo_sql) + repo_ids = [r.pk for r in repos] + # repo_ids are needed twice, so double the array + cursor.execute(sql, repo_ids * 2) + + results = cursor.fetchall() + return [row[0] for row in results] + + +def get_current_signoffs(repos): + '''Returns a list of signoff objects for the given repos.''' + to_fetch = signoffs_id_query(Signoff, repos) + return Signoff.objects.select_related('user').in_bulk(to_fetch).values() + + +def get_current_specifications(repos): + '''Returns a list of signoff specification objects for the given repos.''' + to_fetch = signoffs_id_query(SignoffSpecification, repos) + return SignoffSpecification.objects.select_related('arch').in_bulk( + to_fetch).values() + + +def get_target_repo_map(repos): + sql = """ +SELECT DISTINCT p1.pkgbase, r.name + FROM packages p1 + JOIN repos r ON p1.repo_id = r.id + JOIN packages p2 ON p1.pkgbase = p2.pkgbase + WHERE r.staging = %s + AND r.testing = %s + AND p2.repo_id IN ( + """ + sql += ','.join(['%s' for _ in repos]) + sql += ")" + + params = [False, False] + params.extend(r.pk for r in repos) + + cursor = connection.cursor() + cursor.execute(sql, params) + return dict(cursor.fetchall()) + + +def get_signoff_groups(repos=None, user=None): + if repos is None: + repos = Repo.objects.filter(testing=True) + repo_ids = [r.pk for r in repos] + + test_pkgs = Package.objects.select_related( + 'arch', 'repo', 'packager').filter(repo__in=repo_ids) + packages = test_pkgs.order_by('pkgname') + packages = attach_maintainers(packages) + + # Filter by user if asked to do so + if user is not None: + packages = [p for p in packages if user == p.packager + or user in p.maintainers] + + # Collect all pkgbase values in testing repos + pkgtorepo = get_target_repo_map(repos) + + # Collect all possible signoffs and specifications for these packages + signoffs = get_current_signoffs(repos) + specs = get_current_specifications(repos) + + same_pkgbase_key = lambda x: (x.repo.name, x.arch.name, x.pkgbase) + grouped = groupby_preserve_order(packages, same_pkgbase_key) + signoff_groups = [] + for group in grouped: + signoff_group = PackageSignoffGroup(group) + signoff_group.target_repo = pkgtorepo.get(signoff_group.pkgbase, + "Unknown") + signoff_group.find_signoffs(signoffs) + signoff_group.find_specification(specs) + signoff_groups.append(signoff_group) + + return signoff_groups + + +class PackageJSONEncoder(DjangoJSONEncoder): + pkg_attributes = ['pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', + 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', + 'installed_size', 'build_date', 'last_update', 'flag_date', + 'maintainers', 'packager'] + pkg_list_attributes = ['groups', 'licenses', 'conflicts', + 'provides', 'replaces', 'depends'] + + def default(self, obj): + if hasattr(obj, '__iter__'): + # mainly for queryset serialization + return list(obj) + if isinstance(obj, Package): + data = {attr: getattr(obj, attr) for attr in self.pkg_attributes} + for attr in self.pkg_list_attributes: + data[attr] = getattr(obj, attr).all() + return data + if isinstance(obj, PackageFile): + filename = obj.filename or '' + return obj.directory + filename + if isinstance(obj, (Repo, Arch)): + return obj.name.lower() + if isinstance(obj, (PackageGroup, License)): + return obj.name + if isinstance(obj, (Depend, Conflict, Provision, Replacement)): + return unicode(obj) + elif isinstance(obj, User): + return obj.username + return super(PackageJSONEncoder, self).default(obj) + # vim: set ts=4 sw=4 et: diff --git a/packages/views.py b/packages/views.py deleted file mode 100644 index 4cc4cc2f..00000000 --- a/packages/views.py +++ /dev/null @@ -1,379 +0,0 @@ -from django import forms -from django.contrib import messages -from django.core.mail import send_mail -from django.template import loader, Context, RequestContext -from django.http import HttpResponse, Http404 -from django.shortcuts import get_object_or_404, redirect -from django.contrib.auth.models import User -from django.contrib.auth.decorators import permission_required -from django.contrib.admin.widgets import AdminDateWidget -from django.views.decorators.cache import never_cache -from django.views.decorators.vary import vary_on_headers -from django.views.generic import list_detail -from django.views.generic.simple import direct_to_template -from django.db.models import Q - -from datetime import datetime -import string - -from main.models import Package, PackageFile -from main.models import Arch, Repo, Signoff -from main.utils import make_choice -from mirrors.models import MirrorUrl -from .models import PackageRelation -from .utils import get_group_info, get_differences_info - -def opensearch(request): - if request.is_secure(): - domain = "https://%s" % request.META['HTTP_HOST'] - else: - domain = "http://%s" % request.META['HTTP_HOST'] - - return direct_to_template(request, 'packages/opensearch.xml', - {'domain': domain}, - mimetype='application/opensearchdescription+xml') - -@permission_required('main.change_package') -def update(request): - ids = request.POST.getlist('pkgid') - mode = None - if request.POST.has_key('adopt'): - mode = 'adopt' - if request.POST.has_key('disown'): - mode = 'disown' - - if mode: - repos = request.user.userprofile_user.all()[0].allowed_repos.all() - pkgs = Package.objects.filter(id__in=ids, repo__in=repos) - disallowed_pkgs = Package.objects.filter(id__in=ids).exclude( - repo__in=repos) - count = 0 - for pkg in pkgs: - maints = pkg.maintainers - if mode == 'adopt' and request.user not in maints: - prel = PackageRelation(pkgbase=pkg.pkgbase, - user=request.user, - type=PackageRelation.MAINTAINER) - count += 1 - prel.save() - elif mode == 'disown' and request.user in maints: - rels = PackageRelation.objects.filter(pkgbase=pkg.pkgbase, - user=request.user) - count += rels.count() - rels.delete() - - messages.info(request, "%d base packages %sed." % (count, mode)) - if disallowed_pkgs: - messages.warning(request, - "You do not have permission to %s: %s" % ( - mode, ' '.join([p.pkgname for p in disallowed_pkgs]) - )) - else: - messages.error(request, "Are you trying to adopt or disown?") - return redirect('/packages/') - -def details(request, name='', repo='', arch=''): - if all([name, repo, arch]): - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - return direct_to_template(request, 'packages/details.html', {'pkg': pkg, }) - else: - return redirect("/packages/?arch=%s&repo=%s&q=%s" % ( - arch.lower(), repo.title(), name)) - -def groups(request): - grps = get_group_info() - return direct_to_template(request, 'packages/groups.html', {'groups': grps}) - -def group_details(request, arch, name): - arch = get_object_or_404(Arch, name=arch) - arches = [ arch ] - arches.extend(Arch.objects.filter(agnostic=True)) - pkgs = Package.objects.filter(packagegroup__name=name, - arch__in=arches) - pkgs = pkgs.order_by('pkgname') - if len(pkgs) == 0: - raise Http404 - context = { - 'groupname': name, - 'arch': arch, - 'packages': pkgs, - } - return direct_to_template(request, 'packages/group_details.html', context) - -def getmaintainer(request, name, repo, arch): - "Returns the maintainers as plaintext." - - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - names = [m.username for m in pkg.maintainers] - - return HttpResponse(str('\n'.join(names)), mimetype='text/plain') - -class PackageSearchForm(forms.Form): - repo = forms.ChoiceField(required=False) - arch = forms.ChoiceField(required=False) - q = forms.CharField(required=False) - maintainer = forms.ChoiceField(required=False) - last_update = forms.DateField(required=False, widget=AdminDateWidget(), - label='Last Updated After') - flagged = forms.ChoiceField( - choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), - required=False) - limit = forms.ChoiceField( - choices=make_choice([50, 100, 250]) + [('all', 'All')], - required=False, - initial=50) - - def clean_limit(self): - limit = self.cleaned_data['limit'] - if limit == 'all': - limit = None - elif limit: - try: - limit = int(limit) - except: - raise forms.ValidationError("Should be an integer") - else: - limit = 50 - return limit - - - def __init__(self, *args, **kwargs): - super(PackageSearchForm, self).__init__(*args, **kwargs) - self.fields['repo'].choices = [('', 'All')] + make_choice( - [repo.name for repo in Repo.objects.all()]) - self.fields['arch'].choices = [('', 'All')] + make_choice( - [arch.name for arch in Arch.objects.all()]) - self.fields['q'].widget.attrs.update({"size": "30"}) - maints = User.objects.filter(is_active=True).order_by('username') - self.fields['maintainer'].choices = \ - [('', 'All'), ('orphan', 'Orphan')] + \ - [(m.username, m.get_full_name()) for m in maints] - -def search(request, page=None): - current_query = '?' - limit = 50 - packages = Package.objects.select_related('arch', 'repo') - - if request.GET: - current_query += request.GET.urlencode() - form = PackageSearchForm(data=request.GET) - if form.is_valid(): - if form.cleaned_data['repo']: - packages = packages.filter( - repo__name=form.cleaned_data['repo']) - - if form.cleaned_data['arch']: - packages = packages.filter( - arch__name=form.cleaned_data['arch']) - - if form.cleaned_data['maintainer'] == 'orphan': - inner_q = PackageRelation.objects.all().values('pkgbase') - packages = packages.exclude(pkgbase__in=inner_q) - elif form.cleaned_data['maintainer']: - inner_q = PackageRelation.objects.filter(user__username=form.cleaned_data['maintainer']).values('pkgbase') - packages = packages.filter(pkgbase__in=inner_q) - - if form.cleaned_data['flagged'] == 'Flagged': - packages=packages.filter(flag_date__isnull=False) - elif form.cleaned_data['flagged'] == 'Not Flagged': - packages = packages.filter(flag_date__isnull=True) - - if form.cleaned_data['q']: - query = form.cleaned_data['q'] - q = Q(pkgname__icontains=query) | Q(pkgdesc__icontains=query) - packages = packages.filter(q) - if form.cleaned_data['last_update']: - lu = form.cleaned_data['last_update'] - packages = packages.filter(last_update__gte= - datetime(lu.year, lu.month, lu.day, 0, 0)) - limit = form.cleaned_data['limit'] - else: - form = PackageSearchForm() - - page_dict = {'search_form': form, - 'current_query': current_query - } - if packages.count() == 1: - return redirect(packages[0]) - - allowed_sort = ["arch", "repo", "pkgname", "last_update"] - allowed_sort += ["-" + s for s in allowed_sort] - sort = request.GET.get('sort', None) - # TODO: sorting by multiple fields makes using a DB index much harder - if sort in allowed_sort: - packages = packages.order_by( - request.GET['sort'], 'repo', 'arch', 'pkgname') - page_dict['sort'] = sort - else: - packages = packages.order_by('repo', 'arch', '-last_update', 'pkgname') - - return list_detail.object_list(request, packages, - template_name="packages/search.html", - page=page, - paginate_by=limit, - template_object_name="package", - extra_context=page_dict) - -@vary_on_headers('X-Requested-With') -def files(request, name='', repo='', arch=''): - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - fileslist = PackageFile.objects.filter(pkg=pkg).order_by('path') - template = 'packages/files.html' - if request.is_ajax(): - template = 'packages/files-list.html' - return direct_to_template(request, template, - {'pkg':pkg, 'files':fileslist}) - -@permission_required('main.change_package') -def unflag(request, name='', repo='', arch=''): - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - pkg.flag_date = None - pkg.save() - return redirect(pkg) - -@permission_required('main.change_package') -@never_cache -def signoffs(request): - packages = Package.objects.select_related('arch', 'repo', 'signoffs').filter(repo__testing=True).order_by("pkgname") - package_list = [] - - q_pkgname = Package.objects.filter(repo__testing=True).values('pkgname').distinct().query - package_repos = Package.objects.values('pkgname', 'repo__name').exclude(repo__testing=True).filter(pkgname__in=q_pkgname) - pkgtorepo = dict() - for pr in package_repos: - pkgtorepo[pr['pkgname']] = pr['repo__name'] - - for package in packages: - if package.pkgname in pkgtorepo: - repo = pkgtorepo[package.pkgname] - else: - repo = "Unknown" - package_list.append((package, repo)) - return direct_to_template(request, 'packages/signoffs.html', - {'packages': package_list}) - -@permission_required('main.change_package') -@never_cache -def signoff_package(request, arch, pkgname): - pkg = get_object_or_404(Package, - arch__name=arch, - pkgname=pkgname, - repo__testing=True) - - signoff, created = Signoff.objects.get_or_create( - pkg=pkg, - pkgver=pkg.pkgver, - pkgrel=pkg.pkgrel, - packager=request.user) - - if created: - messages.info(request, - "You have successfully signed off for %s on %s." % \ - (pkg.pkgname, pkg.arch)) - else: - messages.warning(request, - "You have already signed off for %s on %s." % \ - (pkg.pkgname, pkg.arch)) - return signoffs(request) - -def flaghelp(request): - return direct_to_template(request, 'packages/flaghelp.html') - -class FlagForm(forms.Form): - email = forms.EmailField(label='* E-mail Address') - usermessage = forms.CharField(label='Message To Dev', - widget=forms.Textarea, required=False) - # The field below is used to filter out bots that blindly fill out all input elements - website = forms.CharField(label='', - widget=forms.TextInput(attrs={'style': 'display:none;'}), - required=False) - -@never_cache -def flag(request, name='', repo='', arch=''): - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - context = {'pkg': pkg} - if pkg.flag_date is not None: - # already flagged. do nothing. - return direct_to_template(request, 'packages/flagged.html', context) - - if request.POST: - form = FlagForm(request.POST) - if form.is_valid() and form.cleaned_data['website'] == '': - # find all packages from (hopefully) the same PKGBUILD - pkgs = Package.objects.filter( - pkgbase=pkg.pkgbase, repo__testing=pkg.repo.testing) - pkgs.update(flag_date=datetime.now()) - - maints = pkg.maintainers - if not maints: - toemail = ['arch-notifications@archlinux.org'] - subject = 'Orphan %s package [%s] marked out-of-date' % \ - (pkg.repo.name, pkg.pkgname) - else: - toemail = [] - subject = '%s package [%s] marked out-of-date' % \ - (pkg.repo.name, pkg.pkgname) - for maint in maints: - if maint.get_profile().notify == True: - toemail.append(maint.email) - - if toemail: - # send notification email to the maintainer - t = loader.get_template('packages/outofdate.txt') - c = Context({ - 'email': form.cleaned_data['email'], - 'message': form.cleaned_data['usermessage'], - 'pkg': pkg, - 'weburl': pkg.get_full_url(), - }) - send_mail(subject, - t.render(c), - 'Arch Website Notification <nobody@archlinux.org>', - toemail, - fail_silently=True) - - context['confirmed'] = True - else: - form = FlagForm() - - context['form'] = form - - return direct_to_template(request, 'packages/flag.html', context) - -def download(request, name='', repo='', arch=''): - pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) - mirrorurl = MirrorUrl.objects.filter(mirror__country='Any', - mirror__public=True, mirror__active=True, - protocol__protocol__iexact='HTTP')[0] - arch = pkg.arch.name - if pkg.arch.agnostic: - # grab the first non-any arch to fake the download path - arch = Arch.objects.exclude(agnostic=True)[0].name - details = { - 'host': mirrorurl.url, - 'arch': arch, - 'repo': pkg.repo.name.lower(), - 'file': pkg.filename, - } - url = string.Template('${host}${repo}/os/${arch}/${file}').substitute(details) - return redirect(url) - -def arch_differences(request): - # TODO: we have some hardcoded magic here with respect to the arches. - arch_a = Arch.objects.get(name='i686') - arch_b = Arch.objects.get(name='x86_64') - differences = get_differences_info(arch_a, arch_b) - context = { - 'arch_a': arch_a, - 'arch_b': arch_b, - 'differences': differences, - } - return direct_to_template(request, 'packages/differences.html', context) - -# vim: set ts=4 sw=4 et: diff --git a/packages/views/__init__.py b/packages/views/__init__.py new file mode 100644 index 00000000..84ca37f2 --- /dev/null +++ b/packages/views/__init__.py @@ -0,0 +1,153 @@ +import hashlib +import json + +from django.contrib import messages +from django.contrib.auth.decorators import permission_required +from django.contrib.auth.models import User +from django.core.cache import cache +from django.db.models import Q +from django.http import HttpResponse +from django.shortcuts import redirect, render +from django.views.decorators.cache import cache_control +from django.views.decorators.http import require_safe, require_POST + +from main.models import Package, Arch +from ..models import PackageRelation +from ..utils import (get_differences_info, + multilib_differences, get_wrong_permissions) + +# make other views available from this same package +from .display import (details, groups, group_details, files, details_json, + files_json, download) +from .flag import flaghelp, flag, flag_confirmed, unflag, unflag_all +from .search import search_json +from .signoff import signoffs, signoff_package, signoff_options, signoffs_json + + +@require_safe +@cache_control(public=True, max_age=86400) +def opensearch(request): + domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) + + return render(request, 'packages/opensearch.xml', + {'domain': domain}, + content_type='application/opensearchdescription+xml') + + +@require_safe +@cache_control(public=True, max_age=613) +def opensearch_suggest(request): + search_term = request.GET.get('q', '') + if search_term == '': + return HttpResponse('', content_type='application/x-suggestions+json') + + cache_key = 'opensearch:packages:' + \ + hashlib.md5(search_term.encode('utf-8')).hexdigest() + to_json = cache.get(cache_key, None) + if to_json is None: + q = Q(pkgname__startswith=search_term) + lookup = search_term.lower() + if search_term != lookup: + # package names are lowercase by convention, so include that in + # search if original wasn't lowercase already + q |= Q(pkgname__startswith=lookup) + names = Package.objects.filter(q).values_list( + 'pkgname', flat=True).order_by('pkgname').distinct()[:10] + results = [search_term, list(names)] + to_json = json.dumps(results, ensure_ascii=False) + cache.set(cache_key, to_json, 613) + return HttpResponse(to_json, content_type='application/x-suggestions+json') + + +@permission_required('main.change_package') +@require_POST +def update(request): + ids = request.POST.getlist('pkgid') + count = 0 + + if request.POST.has_key('adopt'): + repos = request.user.userprofile.allowed_repos.all() + pkgs = Package.objects.filter(id__in=ids, repo__in=repos) + disallowed_pkgs = Package.objects.filter(id__in=ids).exclude( + repo__in=repos) + + if disallowed_pkgs: + messages.warning(request, + "You do not have permission to adopt: %s." % ( + ' '.join([p.pkgname for p in disallowed_pkgs]) + )) + + for pkg in pkgs: + if request.user not in pkg.maintainers: + prel = PackageRelation(pkgbase=pkg.pkgbase, + user=request.user, + type=PackageRelation.MAINTAINER) + count += 1 + prel.save() + + messages.info(request, "%d base packages adopted." % count) + + elif request.POST.has_key('disown'): + # allow disowning regardless of allowed repos, helps things like + # [community] -> [extra] moves + for pkg in Package.objects.filter(id__in=ids): + if request.user in pkg.maintainers: + rels = PackageRelation.objects.filter(pkgbase=pkg.pkgbase, + user=request.user, + type=PackageRelation.MAINTAINER) + count += rels.count() + rels.delete() + + messages.info(request, "%d base packages disowned." % count) + + else: + messages.error(request, "Are you trying to adopt or disown?") + return redirect('/packages/') + + +def arch_differences(request): + # TODO: we have some hardcoded magic here with respect to the arches. + arch_a = Arch.objects.get(name=request.GET.get('arch_a', 'i686')) + arch_b = Arch.objects.get(name=request.GET.get('arch_b', 'x86_64')) + arch_c = Arch.objects.get(name=request.GET.get('arch_c', 'armv7h')) + differences = get_differences_info(arch_a, arch_b) + multilib_diffs = multilib_differences() + context = { + 'arch_a': arch_a, + 'arch_b': arch_b, + 'arch_c': arch_c, + 'differences': differences, + 'arches': Arch.objects.filter(agnostic=False), + 'multilib_differences': multilib_diffs + } + return render(request, 'packages/differences.html', context) + +@permission_required('main.change_package') +def stale_relations(request): + relations = PackageRelation.objects.select_related('user') + pkgbases = Package.objects.all().values('pkgbase') + + inactive_user = relations.filter(user__is_active=False) + missing_pkgbase = relations.exclude( + pkgbase__in=pkgbases).order_by('pkgbase') + wrong_permissions = get_wrong_permissions() + + context = { + 'inactive_user': inactive_user, + 'missing_pkgbase': missing_pkgbase, + 'wrong_permissions': wrong_permissions, + } + return render(request, 'packages/stale_relations.html', context) + +@permission_required('packages.delete_packagerelation') +@require_POST +def stale_relations_update(request): + ids = set(request.POST.getlist('relation_id')) + + if ids: + PackageRelation.objects.filter(id__in=ids).delete() + + messages.info(request, "%d package relations deleted." % len(ids)) + return redirect('/packages/stale_relations/') + +# vim: set ts=4 sw=4 et: diff --git a/packages/views/display.py b/packages/views/display.py new file mode 100644 index 00000000..021c7ed8 --- /dev/null +++ b/packages/views/display.py @@ -0,0 +1,235 @@ +import datetime +import json +from urllib import urlencode + +from django.http import HttpResponse, Http404 +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.timezone import now + +from main.models import Package, PackageFile, Arch, Repo +from main.utils import empty_response +from mirrors.utils import get_mirror_url_for_download +from ..models import Update +from ..utils import get_group_info, PackageJSONEncoder + + +def arch_plus_agnostic(arch): + arches = [ arch ] + arches.extend(Arch.objects.filter(agnostic=True).order_by()) + return arches + + +def split_package_details(request, name, repo, arch): + '''Check if we have a split package (e.g. pkgbase) value matching this + name. If so, we can show a listing page for the entire set of packages.''' + arches = arch_plus_agnostic(arch) + pkgs = Package.objects.normal().filter(pkgbase=name, + repo__testing=repo.testing, repo__staging=repo.staging, + arch__in=arches).order_by('pkgname') + if len(pkgs) == 0: + return None + # we have packages, but ensure at least one is in the given repo + if not any(True for pkg in pkgs if pkg.repo == repo): + return None + context = { + 'list_title': 'Split Package Details', + 'name': name, + 'arch': arch, + 'packages': pkgs, + } + return render(request, 'packages/packages_list.html', context) + + +CUTOFF = datetime.timedelta(days=60) + + +def recently_removed_package(request, name, repo, arch, cutoff=CUTOFF): + '''Check our packages update table to see if this package has existed in + this repo before. If so, we can show a 410 Gone page and point the + requester in the right direction.''' + arches = arch_plus_agnostic(arch) + match = Update.objects.select_related('arch', 'repo').filter( + pkgname=name, repo=repo, arch__in=arches) + if cutoff is not None: + when = now() - cutoff + match = match.filter(created__gte=when) + try: + update = match.latest() + elsewhere = update.elsewhere() + if len(elsewhere) == 0: + elsewhere = update.replacements() + if len(elsewhere) == 1: + return redirect(elsewhere[0]) + context = { + 'update': update, + 'elsewhere': elsewhere, + 'name': name, + 'version': update.old_version, + 'arch': arch, + 'repo': repo, + } + return render(request, 'packages/removed.html', context, status=410) + except Update.DoesNotExist: + return None + + +def replaced_package(request, name, repo, arch): + '''Check our package replacements to see if this is a package we used to + have but no longer do.''' + match = Package.objects.filter(replaces__name=name, repo=repo, arch=arch) + if len(match) == 1: + return redirect(match[0], permanent=True) + elif len(match) > 1: + context = { + 'elsewhere': match, + 'name': name, + 'version': '', + 'arch': arch, + 'repo': repo, + } + return render(request, 'packages/removed.html', context, status=410) + return None + + +def redirect_agnostic(request, name, repo, arch): + '''For arch='any' packages, we can issue a redirect to them if we have a + single non-ambiguous option by changing the arch to match any arch-agnostic + package.''' + if not arch.agnostic: + # limit to 2 results, we only need to know whether there is anything + # except only one matching result + pkgs = Package.objects.select_related( + 'arch', 'repo', 'packager').filter(pkgname=name, + repo=repo, arch__agnostic=True)[:2] + if len(pkgs) == 1: + return redirect(pkgs[0], permanent=True) + return None + + +def redirect_to_search(request, name, repo, arch): + if request.GET.get('q'): + name = request.GET.get('q') + pkg_data = [ + ('arch', arch.lower()), + ('repo', repo.lower()), + ('q', name), + ] + # only include non-blank values in the query we generate + pkg_data = [(x, y.encode('utf-8')) for x, y in pkg_data if y] + return redirect("/packages/?%s" % urlencode(pkg_data)) + + +def details(request, name='', repo='', arch=''): + if all([name, repo, arch]): + arch_obj = get_object_or_404(Arch, name=arch) + repo_obj = get_object_or_404(Repo, name__iexact=repo) + try: + pkg = Package.objects.select_related( + 'arch', 'repo', 'packager').get(pkgname=name, + repo=repo_obj, arch=arch_obj) + if request.method == 'HEAD': + return empty_response() + return render(request, 'packages/details.html', {'pkg': pkg}) + except Package.DoesNotExist: + # attempt a variety of fallback options before 404ing + options = (redirect_agnostic, split_package_details, + recently_removed_package, replaced_package) + for method in options: + ret = method(request, name, repo_obj, arch_obj) + if ret: + return ret + # we've tried everything at this point, nothing to see + raise Http404 + else: + return redirect_to_search(request, name, repo, arch) + + +def groups(request, arch=None): + arches = [] + if arch: + get_object_or_404(Arch, name=arch, agnostic=False) + arches.append(arch) + grps = get_group_info(arches) + context = { + 'groups': grps, + 'arch': arch, + } + return render(request, 'packages/groups.html', context) + + +def group_details(request, arch, name): + arch = get_object_or_404(Arch, name=arch) + arches = arch_plus_agnostic(arch) + pkgs = Package.objects.normal().filter( + groups__name=name, arch__in=arches).order_by('pkgname') + if len(pkgs) == 0: + raise Http404 + context = { + 'list_title': 'Group Details', + 'name': name, + 'arch': arch, + 'packages': pkgs, + } + return render(request, 'packages/packages_list.html', context) + + +def files(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + # files are inserted in sorted order, so preserve that + fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') + dir_count = sum(1 for f in fileslist if f.is_directory) + files_count = len(fileslist) - dir_count + context = { + 'pkg': pkg, + 'files': fileslist, + 'files_count': files_count, + 'dir_count': dir_count, + } + template = 'packages/files.html' + return render(request, template, context) + + +def details_json(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + to_json = json.dumps(pkg, ensure_ascii=False, cls=PackageJSONEncoder) + return HttpResponse(to_json, content_type='application/json') + + +def files_json(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + # files are inserted in sorted order, so preserve that + fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') + dir_count = sum(1 for f in fileslist if f.is_directory) + files_count = len(fileslist) - dir_count + data = { + 'pkgname': pkg.pkgname, + 'repo': pkg.repo.name.lower(), + 'arch': pkg.arch.name.lower(), + 'pkg_last_update': pkg.last_update, + 'files_last_update': pkg.files_last_update, + 'files_count': files_count, + 'dir_count': dir_count, + 'files': fileslist, + } + to_json = json.dumps(data, ensure_ascii=False, cls=PackageJSONEncoder) + return HttpResponse(to_json, content_type='application/json') + + +def download(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + url = get_mirror_url_for_download() + if not url: + raise Http404 + arch = pkg.arch.name + if pkg.arch.agnostic: + # grab the first non-any arch to fake the download path + arch = Arch.objects.exclude(agnostic=True)[0].name + url = '{host}{repo}/os/{arch}/{filename}'.format(host=url.url, + repo=pkg.repo.name.lower(), arch=arch, filename=pkg.filename) + return redirect(url) + +# vim: set ts=4 sw=4 et: diff --git a/packages/views/flag.py b/packages/views/flag.py new file mode 100644 index 00000000..c6936ac4 --- /dev/null +++ b/packages/views/flag.py @@ -0,0 +1,178 @@ +import re + +from django import forms +from django.conf import settings +from django.contrib.auth.decorators import permission_required +from django.core.mail import EmailMessage +from django.db import transaction +from django.db.models import Q +from django.shortcuts import get_object_or_404, redirect, render +from django.template import loader, Context +from django.utils.timezone import now +from django.views.decorators.cache import cache_page, never_cache + +from ..models import FlagRequest +from main.models import Package + + +class FlagForm(forms.Form): + email = forms.EmailField(label='E-mail Address') + message = forms.CharField(label='Message To Developer', + widget=forms.Textarea) + # The field below is used to filter out bots that blindly fill out all + # input elements + website = forms.CharField(label='', + widget=forms.TextInput(attrs={'style': 'display:none;'}), + required=False) + + def __init__(self, *args, **kwargs): + # we remove the 'email' field if this form is being shown to a + # logged-in user, e.g., a developer. + auth = kwargs.pop('authenticated', False) + super(FlagForm, self).__init__(*args, **kwargs) + if auth: + del self.fields['email'] + + def clean_message(self): + data = self.cleaned_data['message'] + # make sure the message isn't garbage (only punctuation or whitespace) + # and ensure a certain minimum length + if re.match(r'^[^0-9A-Za-z]+$', data) or len(data) < 3: + raise forms.ValidationError( + "Enter a valid and useful out-of-date message.") + return data + + +@cache_page(3600) +def flaghelp(request): + return render(request, 'packages/flaghelp.html') + + +@never_cache +def flag(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + if pkg.flag_date is not None: + # already flagged. do nothing. + return render(request, 'packages/flagged.html', {'pkg': pkg}) + # find all packages from (hopefully) the same PKGBUILD + pkgs = Package.objects.normal().filter( + pkgbase=pkg.pkgbase, flag_date__isnull=True, + repo__testing=pkg.repo.testing, + repo__staging=pkg.repo.staging).filter( + Q(arch__name='mips64el') | Q(repo__name='Libre') | Q(repo__name='Pcr')).order_by( + 'pkgname', 'repo__name', 'arch__name') + + authenticated = request.user.is_authenticated() + + if request.POST: + form = FlagForm(request.POST, authenticated=authenticated) + if form.is_valid() and form.cleaned_data['website'] == '': + # save the package list for later use + flagged_pkgs = list(pkgs) + + # find a common version if there is one available to store + versions = set((pkg.pkgver, pkg.pkgrel, pkg.epoch) + for pkg in flagged_pkgs) + if len(versions) == 1: + version = versions.pop() + else: + version = ('', '', 0) + + message = form.cleaned_data['message'] + ip_addr = request.META.get('REMOTE_ADDR') + if authenticated: + email = request.user.email + else: + email = form.cleaned_data['email'] + + @transaction.atomic + def perform_updates(): + current_time = now() + pkgs.update(flag_date=current_time) + # store our flag request + flag_request = FlagRequest(created=current_time, + user_email=email, message=message, + ip_address=ip_addr, pkgbase=pkg.pkgbase, + repo=pkg.repo, pkgver=version[0], pkgrel=version[1], + epoch=version[2], num_packages=len(flagged_pkgs)) + if authenticated: + flag_request.user = request.user + flag_request.save() + + perform_updates() + + maints = pkg.maintainers + if not maints: + toemail = settings.NOTIFICATIONS + subject = 'Orphan %s package [%s] marked out-of-date' % \ + (pkg.repo.name, pkg.pkgname) + else: + toemail = [] + subject = '%s package [%s] marked out-of-date' % \ + (pkg.repo.name, pkg.pkgname) + for maint in maints: + if maint.userprofile.notify is True: + toemail.append(maint.email) + + if toemail: + # send notification email to the maintainers + tmpl = loader.get_template('packages/outofdate.txt') + ctx = Context({ + 'email': email, + 'message': message, + 'pkg': pkg, + 'packages': flagged_pkgs, + }) + msg = EmailMessage(subject, + tmpl.render(ctx), + settings.BRANDING_EMAIL, + toemail, + headers={"Reply-To": email } + ) + msg.send(fail_silently=True) + + return redirect('package-flag-confirmed', name=name, repo=repo, + arch=arch) + else: + form = FlagForm(authenticated=authenticated) + + context = { + 'package': pkg, + 'packages': pkgs, + 'form': form + } + return render(request, 'packages/flag.html', context) + +def flag_confirmed(request, name, repo, arch): + pkg = get_object_or_404(Package, + pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgs = Package.objects.normal().filter( + pkgbase=pkg.pkgbase, flag_date=pkg.flag_date, + repo__testing=pkg.repo.testing, + repo__staging=pkg.repo.staging).order_by( + 'pkgname', 'repo__name', 'arch__name') + + context = {'package': pkg, 'packages': pkgs} + + return render(request, 'packages/flag_confirmed.html', context) + +@permission_required('main.change_package') +def unflag(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkg.flag_date = None + pkg.save() + return redirect(pkg) + +@permission_required('main.change_package') +def unflag_all(request, name, repo, arch): + pkg = get_object_or_404(Package.objects.normal(), + pkgname=name, repo__name__iexact=repo, arch__name=arch) + # find all packages from (hopefully) the same PKGBUILD + pkgs = Package.objects.filter(pkgbase=pkg.pkgbase, + repo__testing=pkg.repo.testing, repo__staging=pkg.repo.staging) + pkgs.update(flag_date=None) + return redirect(pkg) + +# vim: set ts=4 sw=4 et: diff --git a/packages/views/search.py b/packages/views/search.py new file mode 100644 index 00000000..6e892251 --- /dev/null +++ b/packages/views/search.py @@ -0,0 +1,172 @@ +import json + +from django import forms +from django.contrib.auth.models import User +from django.db.models import Q +from django.http import HttpResponse +from django.views.generic import ListView + +from devel.models import UserProfile +from main.models import Package, Arch, Repo +from main.utils import empty_response, make_choice +from ..models import PackageRelation +from ..utils import attach_maintainers, PackageJSONEncoder + + +class PackageSearchForm(forms.Form): + repo = forms.MultipleChoiceField(required=False) + arch = forms.MultipleChoiceField(required=False) + name = forms.CharField(required=False) + desc = forms.CharField(required=False) + q = forms.CharField(required=False) + sort = forms.CharField(required=False, widget=forms.HiddenInput()) + maintainer = forms.ChoiceField(required=False) + packager = forms.ChoiceField(required=False) + flagged = forms.ChoiceField( + choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), + required=False) + + def __init__(self, *args, **kwargs): + show_staging = kwargs.pop('show_staging', False) + super(PackageSearchForm, self).__init__(*args, **kwargs) + repos = Repo.objects.all() + if not show_staging: + repos = repos.filter(staging=False) + self.fields['repo'].choices = make_choice( + [repo.name for repo in repos]) + self.fields['arch'].choices = make_choice( + [arch.name for arch in Arch.objects.all()]) + self.fields['q'].widget.attrs.update({"size": "30"}) + + profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') + people = User.objects.filter( + is_active=True, userprofile__id__in=profile_ids).order_by( + 'first_name', 'last_name') + maintainers = [('', 'All'), ('orphan', 'Orphan')] + \ + [(p.username, p.get_full_name()) for p in people] + packagers = [('', 'All'), ('unknown', 'Unknown')] + \ + [(p.username, p.get_full_name()) for p in people] + + self.fields['maintainer'].choices = maintainers + self.fields['packager'].choices = packagers + + def exact_matches(self): + # only do exact match search if 'q' is sole parameter + if self.changed_data != ['q']: + return [] + return Package.objects.normal().filter(pkgname=self.cleaned_data['q']) + + +def parse_form(form, packages): + if form.cleaned_data['repo']: + packages = packages.filter( + repo__name__in=form.cleaned_data['repo']) + + if form.cleaned_data['arch']: + packages = packages.filter( + arch__name__in=form.cleaned_data['arch']) + + if form.cleaned_data['maintainer'] == 'orphan': + inner_q = PackageRelation.objects.all().values('pkgbase') + packages = packages.exclude(pkgbase__in=inner_q) + elif form.cleaned_data['maintainer']: + inner_q = PackageRelation.objects.filter( + user__username=form.cleaned_data['maintainer']).values('pkgbase') + packages = packages.filter(pkgbase__in=inner_q) + + if form.cleaned_data['packager'] == 'unknown': + packages = packages.filter(packager__isnull=True) + elif form.cleaned_data['packager']: + packages = packages.filter( + packager__username=form.cleaned_data['packager']) + + if form.cleaned_data['flagged'] == 'Flagged': + packages = packages.filter(flag_date__isnull=False) + elif form.cleaned_data['flagged'] == 'Not Flagged': + packages = packages.filter(flag_date__isnull=True) + + if form.cleaned_data['name']: + name = form.cleaned_data['name'] + packages = packages.filter(pkgname=name) + + if form.cleaned_data['desc']: + desc = form.cleaned_data['desc'] + packages = packages.filter(pkgdesc__icontains=desc) + + if form.cleaned_data['q']: + query = form.cleaned_data['q'] + q = Q(pkgname__icontains=query) | Q(pkgdesc__icontains=query) + packages = packages.filter(q) + + return packages + + +class SearchListView(ListView): + template_name = "packages/search.html" + paginate_by = 100 + + sort_fields = ("arch", "repo", "pkgname", "pkgbase", "compressed_size", + "installed_size", "build_date", "last_update", "flag_date") + allowed_sort = list(sort_fields) + ["-" + s for s in sort_fields] + + def get(self, request, *args, **kwargs): + if request.method == 'HEAD': + return empty_response() + self.form = PackageSearchForm(data=request.GET, + show_staging=self.request.user.is_authenticated()) + return super(SearchListView, self).get(request, *args, **kwargs) + + def get_queryset(self): + packages = Package.objects.normal() + if not self.request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) + if self.form.is_valid(): + packages = parse_form(self.form, packages) + sort = self.form.cleaned_data['sort'] + if sort in self.allowed_sort: + packages = packages.order_by(sort) + else: + packages = packages.order_by('pkgname') + return packages + + # Form had errors so don't return any results + return Package.objects.none() + + def get_context_data(self, **kwargs): + context = super(SearchListView, self).get_context_data(**kwargs) + query_params = self.request.GET.copy() + query_params.pop('page', None) + context['current_query'] = query_params.urlencode() + context['search_form'] = self.form + return context + + +def search_json(request): + limit = 250 + + container = { + 'version': 2, + 'limit': limit, + 'valid': False, + 'results': [], + } + + if request.GET: + form = PackageSearchForm(data=request.GET, + show_staging=request.user.is_authenticated()) + if form.is_valid(): + packages = Package.objects.select_related('arch', 'repo', + 'packager') + if not request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) + packages = parse_form(form, packages)[:limit] + packages = packages.prefetch_related('groups', 'licenses', + 'conflicts', 'provides', 'replaces', 'depends') + attach_maintainers(packages) + container['results'] = packages + container['valid'] = True + + to_json = json.dumps(container, ensure_ascii=False, cls=PackageJSONEncoder) + return HttpResponse(to_json, content_type='application/json') + +# vim: set ts=4 sw=4 et: diff --git a/packages/views/signoff.py b/packages/views/signoff.py new file mode 100644 index 00000000..fcc6de45 --- /dev/null +++ b/packages/views/signoff.py @@ -0,0 +1,187 @@ +import json +from operator import attrgetter + +from django import forms +from django.contrib.auth.decorators import permission_required +from django.contrib.auth.models import User +from django.core.serializers.json import DjangoJSONEncoder +from django.db import transaction +from django.http import HttpResponse, Http404 +from django.shortcuts import get_list_or_404, redirect, render +from django.utils.timezone import now +from django.views.decorators.cache import never_cache + +from main.models import Package, Arch, Repo +from ..models import SignoffSpecification, Signoff +from ..utils import (get_signoff_groups, approved_by_signoffs, + PackageSignoffGroup) + +@permission_required('main.change_package') +def signoffs(request): + signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) + for group in signoff_groups: + group.user = request.user + + context = { + 'signoff_groups': signoff_groups, + 'arches': Arch.objects.all(), + 'repo_names': sorted({g.target_repo for g in signoff_groups}), + } + return render(request, 'packages/signoffs.html', context) + +@permission_required('main.change_package') +@never_cache +def signoff_package(request, name, repo, arch, revoke=False): + packages = get_list_or_404(Package, pkgbase=name, + arch__name=arch, repo__name__iexact=repo, repo__testing=True) + package = packages[0] + + spec = SignoffSpecification.objects.get_or_default_from_package(package) + + if revoke: + try: + signoff = Signoff.objects.get_from_package( + package, request.user, False) + except Signoff.DoesNotExist: + raise Http404 + signoff.revoked = now() + signoff.save(update_fields=('revoked',)) + created = False + else: + # ensure we should even be accepting signoffs + if spec.known_bad or not spec.enabled: + return render(request, '403.html', status=403) + signoff, created = Signoff.objects.get_or_create_from_package( + package, request.user) + + all_signoffs = Signoff.objects.for_package(package) + + if request.is_ajax(): + data = { + 'created': created, + 'revoked': bool(signoff.revoked), + 'approved': approved_by_signoffs(all_signoffs, spec), + 'required': spec.required, + 'enabled': spec.enabled, + 'known_bad': spec.known_bad, + 'user': str(request.user), + } + return HttpResponse(json.dumps(data, ensure_ascii=False), + content_type='application/json') + + return redirect('package-signoffs') + +class SignoffOptionsForm(forms.ModelForm): + apply_all = forms.BooleanField(required=False, + help_text="Apply these options to all architectures?") + + class Meta: + model = SignoffSpecification + fields = ('required', 'enabled', 'known_bad', 'comments') + +def _signoff_options_all(request, name, repo): + seen_ids = set() + with transaction.atomic(): + # find or create a specification for all architectures, then + # graft the form data onto them + packages = Package.objects.filter(pkgbase=name, + repo__name__iexact=repo, repo__testing=True) + for package in packages: + try: + spec = SignoffSpecification.objects.get_from_package(package) + if spec.pk in seen_ids: + continue + except SignoffSpecification.DoesNotExist: + spec = SignoffSpecification(pkgbase=package.pkgbase, + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, + repo=package.repo) + + if spec.user is None: + spec.user = request.user + + form = SignoffOptionsForm(request.POST, instance=spec) + if form.is_valid(): + form.save() + seen_ids.add(form.instance.pk) + +@permission_required('main.change_package') +@never_cache +def signoff_options(request, name, repo, arch): + packages = get_list_or_404(Package, pkgbase=name, + arch__name=arch, repo__name__iexact=repo, repo__testing=True) + package = packages[0] + + if request.user != package.packager and \ + request.user not in package.maintainers: + return render(request, '403.html', status=403) + + try: + spec = SignoffSpecification.objects.get_from_package(package) + except SignoffSpecification.DoesNotExist: + # create a fake one, but don't save it just yet + spec = SignoffSpecification(pkgbase=package.pkgbase, + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, repo=package.repo) + + if spec.user is None: + spec.user = request.user + + if request.POST: + form = SignoffOptionsForm(request.POST, instance=spec) + if form.is_valid(): + if form.cleaned_data['apply_all']: + _signoff_options_all(request, name, repo) + else: + form.save() + return redirect('package-signoffs') + else: + form = SignoffOptionsForm(instance=spec) + + context = { + 'packages': packages, + 'package': package, + 'form': form, + } + return render(request, 'packages/signoff_options.html', context) + +class SignoffJSONEncoder(DjangoJSONEncoder): + '''Base JSONEncoder extended to handle all serialization of all classes + related to signoffs.''' + signoff_group_attrs = ['arch', 'last_update', 'maintainers', 'packager', + 'pkgbase', 'repo', 'signoffs', 'target_repo', 'version'] + signoff_spec_attrs = ['required', 'enabled', 'known_bad', 'comments'] + signoff_attrs = ['user', 'created', 'revoked'] + + def default(self, obj): + if isinstance(obj, PackageSignoffGroup): + data = {attr: getattr(obj, attr) + for attr in self.signoff_group_attrs} + data['pkgnames'] = [p.pkgname for p in obj.packages] + data['package_count'] = len(obj.packages) + data['approved'] = obj.approved() + data.update((attr, getattr(obj.specification, attr)) + for attr in self.signoff_spec_attrs) + return data + elif isinstance(obj, Signoff): + return {attr: getattr(obj, attr) for attr in self.signoff_attrs} + elif isinstance(obj, Arch) or isinstance(obj, Repo): + return unicode(obj) + elif isinstance(obj, User): + return obj.username + elif isinstance(obj, set): + return list(obj) + return super(SignoffJSONEncoder, self).default(obj) + +@permission_required('main.change_package') +def signoffs_json(request): + signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) + data = { + 'version': 2, + 'signoff_groups': signoff_groups, + } + to_json = json.dumps(data, ensure_ascii=False, cls=SignoffJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + +# vim: set ts=4 sw=4 et: diff --git a/public/models.py b/public/models.py deleted file mode 100644 index 3668574e..00000000 --- a/public/models.py +++ /dev/null @@ -1 +0,0 @@ -# Needed for django to recognize this as an app for testing diff --git a/public/static/logos/archlinux-logo-black-1200dpi.png b/public/static/logos/archlinux-logo-black-1200dpi.png Binary files differnew file mode 100644 index 00000000..3b6b6e48 --- /dev/null +++ b/public/static/logos/archlinux-logo-black-1200dpi.png diff --git a/public/static/logos/archlinux-logo-black-90dpi.png b/public/static/logos/archlinux-logo-black-90dpi.png Binary files differnew file mode 100644 index 00000000..528f9d62 --- /dev/null +++ b/public/static/logos/archlinux-logo-black-90dpi.png diff --git a/media/logos/archlinux-logo-black-scalable.svg b/public/static/logos/archlinux-logo-black-scalable.svg index 10d6c4af..10d6c4af 100644 --- a/media/logos/archlinux-logo-black-scalable.svg +++ b/public/static/logos/archlinux-logo-black-scalable.svg diff --git a/public/static/logos/archlinux-logo-dark-1200dpi.png b/public/static/logos/archlinux-logo-dark-1200dpi.png Binary files differnew file mode 100644 index 00000000..62eeba12 --- /dev/null +++ b/public/static/logos/archlinux-logo-dark-1200dpi.png diff --git a/public/static/logos/archlinux-logo-dark-90dpi.png b/public/static/logos/archlinux-logo-dark-90dpi.png Binary files differnew file mode 100644 index 00000000..8830fe11 --- /dev/null +++ b/public/static/logos/archlinux-logo-dark-90dpi.png diff --git a/media/logos/archlinux-logo-dark-scalable.svg b/public/static/logos/archlinux-logo-dark-scalable.svg index 5a80cc4d..5a80cc4d 100644 --- a/media/logos/archlinux-logo-dark-scalable.svg +++ b/public/static/logos/archlinux-logo-dark-scalable.svg diff --git a/public/static/logos/archlinux-logo-light-1200dpi.png b/public/static/logos/archlinux-logo-light-1200dpi.png Binary files differnew file mode 100644 index 00000000..d5399e9a --- /dev/null +++ b/public/static/logos/archlinux-logo-light-1200dpi.png diff --git a/public/static/logos/archlinux-logo-light-90dpi.png b/public/static/logos/archlinux-logo-light-90dpi.png Binary files differnew file mode 100644 index 00000000..e5f4055d --- /dev/null +++ b/public/static/logos/archlinux-logo-light-90dpi.png diff --git a/media/logos/archlinux-logo-light-scalable.svg b/public/static/logos/archlinux-logo-light-scalable.svg index 5fd0716f..5fd0716f 100644 --- a/media/logos/archlinux-logo-light-scalable.svg +++ b/public/static/logos/archlinux-logo-light-scalable.svg diff --git a/public/static/logos/archlinux-logo-only.svg b/public/static/logos/archlinux-logo-only.svg new file mode 100644 index 00000000..09be94a7 --- /dev/null +++ b/public/static/logos/archlinux-logo-only.svg @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="200" + height="200" + id="svg2424"> + <metadata + id="metadata3206"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs2426" /> + <path + d="M 99.982978,9.4299079 C 91.920693,29.201751 87.057917,42.128656 78.081625,61.311918 83.585216,67.143195 90.340614,73.933635 101.31135,81.606952 89.516733,76.756627 81.471355,71.884513 75.458912,66.827107 63.970969,90.7953 45.972667,124.94368 9.4483145,190.57009 38.155229,173.99182 60.408321,163.77892 81.147131,159.87687 c -0.890533,-3.82576 -1.396835,-7.9676 -1.362448,-12.29473 l 0.03406,-0.91557 c 0.455512,-18.39852 10.022891,-32.53528 21.356367,-31.57611 11.33348,0.95916 20.14288,16.65456 19.68737,35.05308 -0.0857,3.45517 -0.47603,6.79044 -1.15808,9.87502 20.51365,4.01105 42.52879,14.20216 70.84729,30.55153 -5.58386,-10.27831 -10.56793,-19.54295 -15.32754,-28.37161 -7.49716,-5.80948 -15.31706,-13.37379 -31.26818,-21.5594 10.96388,2.84479 18.81388,6.13649 24.9328,9.80965 C 120.49649,60.352755 116.57776,48.374114 99.982978,9.4299079 z" + id="path2518" + style="fill:#1793d1;fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <g + transform="matrix(0.8746356,0,0,0.8746356,-26.046795,-109.83508)" + id="text2638" + style="font-size:8.25130367px;font-style:normal;font-weight:normal;fill:#1793d1;fill-opacity:1;stroke:none;font-family:DejaVu Sans Mono"> + <path + d="m 239.84053,313.69965 0,-5.20945 -1.94598,0 0,-0.697 4.68164,0 0,0.697 -1.95404,0 0,5.20945 -0.78162,0" + id="path3940" + style="fill:#1793d1;fill-opacity:1" /> + <path + d="m 243.39004,313.69965 0,-5.90645 1.17646,0 1.39805,4.18205 c 0.12892,0.38947 0.22293,0.6809 0.28202,0.87429 0.0671,-0.21488 0.1719,-0.53048 0.31426,-0.94681 l 1.41417,-4.10953 1.05155,0 0,5.90645 -0.75341,0 0,-4.94353 -1.71634,4.94353 -0.70506,0 -1.70828,-5.02814 0,5.02814 -0.75342,0" + id="path3942" + style="fill:#1793d1;fill-opacity:1" /> + </g> +</svg> diff --git a/public/static/logos/archlinux-logo-white-1200dpi.png b/public/static/logos/archlinux-logo-white-1200dpi.png Binary files differnew file mode 100644 index 00000000..4c287e32 --- /dev/null +++ b/public/static/logos/archlinux-logo-white-1200dpi.png diff --git a/public/static/logos/archlinux-logo-white-90dpi.png b/public/static/logos/archlinux-logo-white-90dpi.png Binary files differnew file mode 100644 index 00000000..3c7173bc --- /dev/null +++ b/public/static/logos/archlinux-logo-white-90dpi.png diff --git a/media/logos/archlinux-logo-white-scalable.svg b/public/static/logos/archlinux-logo-white-scalable.svg index 70eb2dfe..70eb2dfe 100644 --- a/media/logos/archlinux-logo-white-scalable.svg +++ b/public/static/logos/archlinux-logo-white-scalable.svg diff --git a/public/static/logos/legacy/arch-legacy-aqua-blue.png b/public/static/logos/legacy/arch-legacy-aqua-blue.png Binary files differnew file mode 100644 index 00000000..4bbb215d --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-aqua-blue.png diff --git a/media/logos/legacy/arch-legacy-aqua-blue.svg b/public/static/logos/legacy/arch-legacy-aqua-blue.svg index f4c80109..f4c80109 100644 --- a/media/logos/legacy/arch-legacy-aqua-blue.svg +++ b/public/static/logos/legacy/arch-legacy-aqua-blue.svg diff --git a/public/static/logos/legacy/arch-legacy-aqua-white.png b/public/static/logos/legacy/arch-legacy-aqua-white.png Binary files differnew file mode 100644 index 00000000..68ae73b6 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-aqua-white.png diff --git a/media/logos/legacy/arch-legacy-aqua-white.svg b/public/static/logos/legacy/arch-legacy-aqua-white.svg index 60b554fa..60b554fa 100644 --- a/media/logos/legacy/arch-legacy-aqua-white.svg +++ b/public/static/logos/legacy/arch-legacy-aqua-white.svg diff --git a/public/static/logos/legacy/arch-legacy-aqua.png b/public/static/logos/legacy/arch-legacy-aqua.png Binary files differnew file mode 100644 index 00000000..8cc7da47 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-aqua.png diff --git a/media/logos/legacy/arch-legacy-aqua.svg b/public/static/logos/legacy/arch-legacy-aqua.svg index 30860912..30860912 100644 --- a/media/logos/legacy/arch-legacy-aqua.svg +++ b/public/static/logos/legacy/arch-legacy-aqua.svg diff --git a/public/static/logos/legacy/arch-legacy-blue1.png b/public/static/logos/legacy/arch-legacy-blue1.png Binary files differnew file mode 100644 index 00000000..403a0661 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-blue1.png diff --git a/media/logos/legacy/arch-legacy-blue1.svg b/public/static/logos/legacy/arch-legacy-blue1.svg index 5a6f2c71..5a6f2c71 100644 --- a/media/logos/legacy/arch-legacy-blue1.svg +++ b/public/static/logos/legacy/arch-legacy-blue1.svg diff --git a/public/static/logos/legacy/arch-legacy-blue2.png b/public/static/logos/legacy/arch-legacy-blue2.png Binary files differnew file mode 100644 index 00000000..809ad4f0 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-blue2.png diff --git a/media/logos/legacy/arch-legacy-blue2.svg b/public/static/logos/legacy/arch-legacy-blue2.svg index 48b28338..48b28338 100644 --- a/media/logos/legacy/arch-legacy-blue2.svg +++ b/public/static/logos/legacy/arch-legacy-blue2.svg diff --git a/public/static/logos/legacy/arch-legacy-noodle-blue.png b/public/static/logos/legacy/arch-legacy-noodle-blue.png Binary files differnew file mode 100644 index 00000000..cf7c00ed --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-noodle-blue.png diff --git a/media/logos/legacy/arch-legacy-noodle-blue.svg b/public/static/logos/legacy/arch-legacy-noodle-blue.svg index 7b6485b8..7b6485b8 100644 --- a/media/logos/legacy/arch-legacy-noodle-blue.svg +++ b/public/static/logos/legacy/arch-legacy-noodle-blue.svg diff --git a/public/static/logos/legacy/arch-legacy-noodle-box.png b/public/static/logos/legacy/arch-legacy-noodle-box.png Binary files differnew file mode 100644 index 00000000..78d76a6a --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-noodle-box.png diff --git a/media/logos/legacy/arch-legacy-noodle-box.svg b/public/static/logos/legacy/arch-legacy-noodle-box.svg index 8f17f00a..8f17f00a 100644 --- a/media/logos/legacy/arch-legacy-noodle-box.svg +++ b/public/static/logos/legacy/arch-legacy-noodle-box.svg diff --git a/public/static/logos/legacy/arch-legacy-noodle-cup.png b/public/static/logos/legacy/arch-legacy-noodle-cup.png Binary files differnew file mode 100644 index 00000000..c62cceee --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-noodle-cup.png diff --git a/media/logos/legacy/arch-legacy-noodle-cup.svg b/public/static/logos/legacy/arch-legacy-noodle-cup.svg index 8d6a0442..8d6a0442 100644 --- a/media/logos/legacy/arch-legacy-noodle-cup.svg +++ b/public/static/logos/legacy/arch-legacy-noodle-cup.svg diff --git a/public/static/logos/legacy/arch-legacy-noodle-white.png b/public/static/logos/legacy/arch-legacy-noodle-white.png Binary files differnew file mode 100644 index 00000000..04c17c53 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-noodle-white.png diff --git a/media/logos/legacy/arch-legacy-noodle-white.svg b/public/static/logos/legacy/arch-legacy-noodle-white.svg index 03e1b15a..03e1b15a 100644 --- a/media/logos/legacy/arch-legacy-noodle-white.svg +++ b/public/static/logos/legacy/arch-legacy-noodle-white.svg diff --git a/public/static/logos/legacy/arch-legacy-ribbon1.png b/public/static/logos/legacy/arch-legacy-ribbon1.png Binary files differnew file mode 100644 index 00000000..dba79302 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon1.png diff --git a/public/static/logos/legacy/arch-legacy-ribbon2.png b/public/static/logos/legacy/arch-legacy-ribbon2.png Binary files differnew file mode 100644 index 00000000..eccd61be --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon2.png diff --git a/public/static/logos/legacy/arch-legacy-ribbon3.png b/public/static/logos/legacy/arch-legacy-ribbon3.png Binary files differnew file mode 100644 index 00000000..df412335 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon3.png diff --git a/public/static/logos/legacy/arch-legacy-ribbon4.png b/public/static/logos/legacy/arch-legacy-ribbon4.png Binary files differnew file mode 100644 index 00000000..8f0ed3a0 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon4.png diff --git a/public/static/logos/legacy/arch-legacy-ribbon5.png b/public/static/logos/legacy/arch-legacy-ribbon5.png Binary files differnew file mode 100644 index 00000000..e48dc537 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon5.png diff --git a/public/static/logos/legacy/arch-legacy-ribbon6.png b/public/static/logos/legacy/arch-legacy-ribbon6.png Binary files differnew file mode 100644 index 00000000..c3091240 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-ribbon6.png diff --git a/public/static/logos/legacy/arch-legacy-wombat-lg.png b/public/static/logos/legacy/arch-legacy-wombat-lg.png Binary files differnew file mode 100644 index 00000000..661ec0a9 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-wombat-lg.png diff --git a/public/static/logos/legacy/arch-legacy-wombat.png b/public/static/logos/legacy/arch-legacy-wombat.png Binary files differnew file mode 100644 index 00000000..52678145 --- /dev/null +++ b/public/static/logos/legacy/arch-legacy-wombat.png diff --git a/public/tests.py b/public/tests.py index 565d57ec..1e741f16 100644 --- a/public/tests.py +++ b/public/tests.py @@ -13,25 +13,36 @@ class PublicTest(TestCase): def test_art(self): response = self.client.get('/art/') - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].startswith( + 'https://projects.parabola.nu/artwork.git/') def test_svn(self): response = self.client.get('/svn/') - self.assertEqual(response.status_code, 200) + # Parabola has no SVN. + self.assertEqual(response.status_code, 404) - def test_developers(self): + def test_developers_old(self): response = self.client.get('/developers/') + self.assertEqual(response.status_code, 301) + self.assertTrue(response['Location'].endswith('/hackers/')) + + def test_hackers(self): + response = self.client.get('/hackers/') self.assertEqual(response.status_code, 200) - def test_fellows(self): + def test_fellows_old(self): response = self.client.get('/fellows/') - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 301) def test_donate(self): response = self.client.get('/donate/') - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) + self.assertEqual(response['Location'], + 'https://wiki.parabola.nu/Donations') def test_download(self): response = self.client.get('/download/') - self.assertEqual(response.status_code, 200) - + self.assertEqual(response.status_code, 302) + self.assertEqual(response['Location'], + 'https://wiki.parabola.nu/Get_Parabola') diff --git a/public/utils.py b/public/utils.py index 2801c939..11091883 100644 --- a/public/utils.py +++ b/public/utils.py @@ -1,32 +1,89 @@ +from collections import defaultdict from operator import attrgetter -from main.models import Arch, Package -from main.utils import cache_function +from main.models import Arch, Repo, Package +from main.utils import groupby_preserve_order, PackageStandin + +class RecentUpdate(object): + def __init__(self, packages): + if len(packages) == 0: + raise Exception + first = packages[0] + self.pkgbase = first.pkgbase + self.repo = first.repo + self.version = '' + self.classes = set() + + self.classes.add(self.repo.name.lower()) + if self.repo.testing: + self.classes.add('testing') + if self.repo.staging: + self.classes.add('staging') + + packages = sorted(packages, key=attrgetter('arch', 'pkgname')) + # split the packages into two lists. we need to prefer packages + # matching pkgbase as our primary, and group everything else in other. + self.packages = [pkg for pkg in packages if pkg.pkgname == pkg.pkgbase] + self.others = [pkg for pkg in packages if pkg.pkgname != pkg.pkgbase] + + if self.packages: + version = self.packages[0].full_version + if all(version == pkg.full_version for pkg in self.packages): + self.version = version + elif self.others: + version = self.others[0].full_version + if all(version == pkg.full_version for pkg in self.others): + self.version = version + + def package_links(self): + '''Returns either actual packages or package-standins for virtual + pkgbase packages.''' + if self.packages: + # we have real packages- just yield each in sequence + for package in self.packages: + yield package + else: + # fake out the template- this is slightly hacky but yields one + # 'package-like' object per arch which is what the normal loop does + by_arch = defaultdict(list) + for package in self.others: + by_arch[package.arch].append(package) + for arch, packages in by_arch.items(): + if len(packages) == 1: + yield packages[0] + else: + yield PackageStandin(packages[0]) + + def __unicode__(self): + return "RecentUpdate '%s %s' <%d packages>" % ( + self.pkgbase, self.version, len(self.packages)) + +def get_recent_updates(number=15, testing=True, staging=False): + repos = Repo.objects.all() + if not testing: + repos = repos.exclude(testing=True) + if not staging: + repos = repos.exclude(staging=True) -@cache_function(300) -def get_recent_updates(): # This is a bit of magic. We are going to show 15 on the front page, but we # want to try and eliminate cross-architecture wasted space. Pull enough # packages that we can later do some screening and trim out the fat. pkgs = [] + # grab a few extra so we can hopefully catch everything we need + fetch = number * 6 for arch in Arch.objects.all(): - # grab a few extra so we can hopefully catch everything we need - pkgs += list(Package.objects.select_related( - 'arch', 'repo').filter(arch=arch).order_by('-last_update')[:50]) - pkgs.sort(key=lambda q: q.last_update) + pkgs += list(Package.objects.normal().filter( + arch=arch, repo__in=repos).order_by('-last_update')[:fetch]) + pkgs.sort(key=attrgetter('last_update'), reverse=True) + + same_pkgbase_key = lambda x: (x.repo.name, x.pkgbase) + grouped = groupby_preserve_order(pkgs, same_pkgbase_key) + updates = [] - ctr = 0 - while ctr < 15 and len(pkgs) > 0: - # not particularly happy with this logic, but it works. - p = pkgs.pop() - is_same = lambda q: p.is_same_version(q) and p.repo == q.repo - samepkgs = filter(is_same, pkgs) - samepkgs.append(p) - samepkgs.sort(key=attrgetter('arch.name')) - updates.append(samepkgs) - for q in samepkgs: - if p != q: pkgs.remove(q) - ctr += 1 - return updates + for group in grouped: + update = RecentUpdate(group) + updates.append(update) + + return updates[:number] # vim: set ts=4 sw=4 et: diff --git a/public/views.py b/public/views.py index fa97adef..1002c8c7 100644 --- a/public/views.py +++ b/public/views.py @@ -1,62 +1,153 @@ +from datetime import datetime +import json +from operator import attrgetter + +from django.conf import settings +from django.contrib.auth.models import User +from django.db.models import Count, Q +from django.http import HttpResponse +from django.shortcuts import get_object_or_404, render +from django.views.decorators.cache import cache_control, cache_page + +from devel.models import MasterKey, DeveloperKey, PGPSignature, StaffGroup, UserProfile from main.models import Arch, Repo, Donor from mirrors.models import MirrorUrl from news.models import News -from . import utils - -from django.contrib.auth.models import User -from django.db.models import Q -from django.views.generic import list_detail -from django.views.generic.simple import direct_to_template +from releng.models import Release +from .utils import get_recent_updates +@cache_control(max_age=307) def index(request): - pkgs = utils.get_recent_updates() + if request.user.is_authenticated(): + def updates(): + return get_recent_updates(testing=True, staging=True) + else: + def updates(): + return get_recent_updates() + domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) context = { - 'news_updates': News.objects.order_by('-postdate', '-id')[:10], - 'pkg_updates': pkgs, + 'news_updates': News.objects.order_by('-postdate', '-id')[:15], + 'pkg_updates': updates, + 'staff_groups': StaffGroup.objects.all(), + 'domain': domain, } - return direct_to_template(request, 'public/index.html', context) - -def userlist(request, type='Developers'): - users = User.objects.order_by('username') - if type == 'Developers': - users = users.filter(is_active=True, groups__name="Developers") - msg = "This is a list of the current Arch Linux Developers. They maintain the [core] and [extra] package repositories in addition to doing any other developer duties." - elif type == 'Trusted Users': - users = users.filter(is_active=True, groups__name="Trusted Users") - msg = "Here are all your friendly Arch Linux Trusted Users who are in charge of the [community] repository." - elif type == 'Fellows': - users = users.filter(is_active=False) - msg = "Below you can find a list of ex-developers (aka project fellows). These folks helped make Arch what it is today. Thanks!" + return render(request, 'public/index.html', context) - context = { - 'user_type': type, - 'description': msg, - 'users': users, - } - return direct_to_template(request, 'public/userlist.html', context) -def donate(request): - context = { - 'donors': Donor.objects.order_by('name'), - } - return direct_to_template(request, 'public/donate.html', context) - -def download(request): - qset = MirrorUrl.objects.filter( - Q(protocol__protocol__iexact='HTTP') | Q(protocol__protocol__iexact='FTP'), - mirror__public=True, mirror__active=True, mirror__isos=True - ) - return list_detail.object_list(request, - qset.order_by('mirror__country', 'mirror__name', 'protocol'), - template_name="public/download.html", - template_object_name="mirror_url") +@cache_control(max_age=307) +def people(request, slug): + group = get_object_or_404(StaffGroup, slug=slug) + users = User.objects.filter(groups=group.group).order_by( + 'first_name', 'last_name').select_related('userprofile') + + context = {'group': group, 'users': users} + return render(request, 'public/userlist.html', context) + + +def _mirror_urls(): + '''In order to ensure this is lazily evaluated since we can't do + sorting at the database level, make it a callable.''' + urls = MirrorUrl.objects.select_related('mirror').filter( + active=True, protocol__default=True, + mirror__public=True, mirror__active=True, mirror__isos=True) + sort_by = attrgetter('country.name', 'mirror.name') + return sorted(urls, key=sort_by) + +@cache_control(max_age=307) def feeds(request): + repos = Repo.objects.all() + if not request.user.is_authenticated(): + repos = repos.filter(staging=False) context = { 'arches': Arch.objects.all(), - 'repos': Repo.objects.all(), + 'repos': repos, } - return direct_to_template(request, 'public/feeds.html', context) + return render(request, 'public/feeds.html', context) + + +@cache_control(max_age=307) +def keys(request): + profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') + users = User.objects.filter( + is_active=True, userprofile__id__in=profile_ids).select_related( + 'userprofile__pgp_key').order_by('first_name', 'last_name') + user_key_ids = frozenset(user.userprofile.pgp_key[-16:] for user in users + if user.userprofile.pgp_key) + + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) + master_keys = MasterKey.objects.select_related('owner', 'revoker', + 'owner__userprofile', 'revoker__userprofile').filter( + revoked__isnull=True) + + sig_counts = PGPSignature.objects.filter(not_expired, revoked__isnull=True, + signee__in=user_key_ids).order_by().values_list('signer').annotate( + Count('signer')) + sig_counts = {key_id[-16:]: ct for key_id, ct in sig_counts} + + for key in master_keys: + key.signature_count = sig_counts.get(key.pgp_key[-16:], 0) + + # frozenset because we are going to do lots of __contains__ lookups + signatures = frozenset(PGPSignature.objects.filter( + not_expired, revoked__isnull=True).values_list('signer', 'signee')) + + restrict = Q(signer__in=user_key_ids) & Q(signee__in=user_key_ids) + cross_signatures = PGPSignature.objects.filter( + not_expired, revoked__isnull=True).order_by('created') + # filter in python so we aren't sending a crazy long query to the DB + cross_signatures = [s for s in cross_signatures + if s.signer in user_key_ids and s.signee in user_key_ids] + + developer_keys = DeveloperKey.objects.select_related( + 'owner').filter(owner__isnull=False) + developer_keys = {key.key[-16:]: key for key in developer_keys} + + context = { + 'keys': master_keys, + 'active_users': users, + 'signatures': signatures, + 'cross_signatures': cross_signatures, + 'developer_keys': developer_keys, + } + return render(request, 'public/keys.html', context) + + +@cache_page(1789) +def keys_json(request): + profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') + users = User.objects.filter( + is_active=True, userprofile__id__in=profile_ids).select_related( + 'userprofile__pgp_key').order_by('first_name', 'last_name') + node_list = [{ + 'name': user.get_full_name(), + 'key': user.userprofile.pgp_key, + 'group': 'packager' + } for user in users] + + master_keys = MasterKey.objects.select_related('owner').filter( + revoked__isnull=True) + node_list.extend({ + 'name': 'Master Key (%s)' % key.owner.get_full_name(), + 'key': key.pgp_key, + 'group': 'master' + } for key in master_keys) + + node_list.append({ + 'name': 'CA Cert Signing Authority', + 'key': 'A31D4F81EF4EBD07B456FA04D2BB0D0165D0FD58', + 'group': 'cacert', + }) + + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) + signatures = PGPSignature.objects.filter(not_expired, revoked__isnull=True) + edge_list = [{ 'signee': sig.signee, 'signer': sig.signer } + for sig in signatures] + + data = { 'nodes': node_list, 'edges': edge_list } + + to_json = json.dumps(data, ensure_ascii=False) + return HttpResponse(to_json, content_type='application/json') # vim: set ts=4 sw=4 et: diff --git a/releng/__init__.py b/releng/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/__init__.py diff --git a/releng/admin.py b/releng/admin.py new file mode 100644 index 00000000..9c93c4be --- /dev/null +++ b/releng/admin.py @@ -0,0 +1,34 @@ +from django.contrib import admin + +from .models import (Architecture, BootType, Bootloader, ClockChoice, + Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source, + Test, Release) + +class IsoAdmin(admin.ModelAdmin): + list_display = ('name', 'created', 'active', 'removed') + list_filter = ('active', 'created') + date_hierarchy = 'created' + +class TestAdmin(admin.ModelAdmin): + list_display = ('user_name', 'user_email', 'created', 'ip_address', + 'iso', 'success') + list_filter = ('success', 'iso') + +class ReleaseAdmin(admin.ModelAdmin): + list_display = ('version', 'release_date', 'kernel_version', 'available', + 'created') + list_filter = ('available', 'release_date') + readonly_fields = ('created', 'last_modified') + + +SIMPLE_MODELS = (Architecture, BootType, Bootloader, ClockChoice, Filesystem, + HardwareType, InstallType, IsoType, Module, Source) + +for model in SIMPLE_MODELS: + admin.site.register(model) + +admin.site.register(Iso, IsoAdmin) +admin.site.register(Test, TestAdmin) +admin.site.register(Release, ReleaseAdmin) + +# vim: set ts=4 sw=4 et: diff --git a/releng/fixtures/architecture.json b/releng/fixtures/architecture.json new file mode 100644 index 00000000..0bf9b8bf --- /dev/null +++ b/releng/fixtures/architecture.json @@ -0,0 +1,30 @@ +[ + { + "pk": 1, + "model": "releng.architecture", + "fields": { + "name": "dual, option i686" + } + }, + { + "pk": 2, + "model": "releng.architecture", + "fields": { + "name": "dual, option x86_64" + } + }, + { + "pk": 3, + "model": "releng.architecture", + "fields": { + "name": "i686" + } + }, + { + "pk": 4, + "model": "releng.architecture", + "fields": { + "name": "x86_64" + } + } +] diff --git a/releng/fixtures/bootloaders.json b/releng/fixtures/bootloaders.json new file mode 100644 index 00000000..bee02f2b --- /dev/null +++ b/releng/fixtures/bootloaders.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.bootloader", + "fields": { + "name": "grub" + } + }, + { + "pk": 2, + "model": "releng.bootloader", + "fields": { + "name": "syslinux" + } + }, + { + "pk": 3, + "model": "releng.bootloader", + "fields": { + "name": "other/manual" + } + } +] diff --git a/releng/fixtures/boottype.json b/releng/fixtures/boottype.json new file mode 100644 index 00000000..ed4636eb --- /dev/null +++ b/releng/fixtures/boottype.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.boottype", + "fields": { + "name": "optical" + } + }, + { + "pk": 2, + "model": "releng.boottype", + "fields": { + "name": "usb" + } + }, + { + "pk": 3, + "model": "releng.boottype", + "fields": { + "name": "pxe" + } + } +] diff --git a/releng/fixtures/clockchoices.json b/releng/fixtures/clockchoices.json new file mode 100644 index 00000000..d2d4eb80 --- /dev/null +++ b/releng/fixtures/clockchoices.json @@ -0,0 +1,72 @@ +[ + { + "pk": 1, + "model": "releng.clockchoice", + "fields": { + "name": "default region/timezone, keep clock" + } + }, + { + "pk": 2, + "model": "releng.clockchoice", + "fields": { + "name": "default region/timezone, change clock manually (UTC)" + } + }, + { + "pk": 3, + "model": "releng.clockchoice", + "fields": { + "name": "default region/timezone, change clock with NTP (UTC)" + } + }, + { + "pk": 4, + "model": "releng.clockchoice", + "fields": { + "name": "default region/timezone, change clock manually (localtime)" + } + }, + { + "pk": 5, + "model": "releng.clockchoice", + "fields": { + "name": "default region/timezone, change clock with NTP (localtime)" + } + }, + { + "pk": 6, + "model": "releng.clockchoice", + "fields": { + "name": "update region/timezone, keep clock" + } + }, + { + "pk": 7, + "model": "releng.clockchoice", + "fields": { + "name": "update region/timezone, change clock manually (UTC)" + } + }, + { + "pk": 8, + "model": "releng.clockchoice", + "fields": { + "name": "update region/timezone, change clock with NTP (UTC)" + } + }, + { + "pk": 9, + "model": "releng.clockchoice", + "fields": { + "name": "update region/timezone, change clock manually (localtime)" + } + }, + { + "pk": 10, + "model": "releng.clockchoice", + "fields": { + "name": "update region/timezone, change clock with NTP (localtime)" + } + } +] diff --git a/releng/fixtures/filesystems.json b/releng/fixtures/filesystems.json new file mode 100644 index 00000000..208f5c73 --- /dev/null +++ b/releng/fixtures/filesystems.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.filesystem", + "fields": { + "name": "autoprepare" + } + }, + { + "pk": 2, + "model": "releng.filesystem", + "fields": { + "name": "manual" + } + }, + { + "pk": 3, + "model": "releng.filesystem", + "fields": { + "name": "from config file" + } + } +] diff --git a/releng/fixtures/hardware.json b/releng/fixtures/hardware.json new file mode 100644 index 00000000..a2bb9ec0 --- /dev/null +++ b/releng/fixtures/hardware.json @@ -0,0 +1,44 @@ +[ + { + "pk": 1, + "model": "releng.hardwaretype", + "fields": { + "name": "virtualbox" + } + }, + { + "pk": 2, + "model": "releng.hardwaretype", + "fields": { + "name": "qemu" + } + }, + { + "pk": 3, + "model": "releng.hardwaretype", + "fields": { + "name": "intel i686" + } + }, + { + "pk": 4, + "model": "releng.hardwaretype", + "fields": { + "name": "intel x86_64" + } + }, + { + "pk": 5, + "model": "releng.hardwaretype", + "fields": { + "name": "amd i686" + } + }, + { + "pk": 6, + "model": "releng.hardwaretype", + "fields": { + "name": "amd x86_64" + } + } +] diff --git a/releng/fixtures/installtype.json b/releng/fixtures/installtype.json new file mode 100644 index 00000000..07d17f28 --- /dev/null +++ b/releng/fixtures/installtype.json @@ -0,0 +1,30 @@ +[ + { + "pk": 1, + "model": "releng.installtype", + "fields": { + "name": "interactive install" + } + }, + { + "pk": 2, + "model": "releng.installtype", + "fields": { + "name": "automatic install generic example" + } + }, + { + "pk": 3, + "model": "releng.installtype", + "fields": { + "name": "automatic install fancy example" + } + }, + { + "pk": 4, + "model": "releng.installtype", + "fields": { + "name": "automatic install custom config (if special, specify in comments)" + } + } +] diff --git a/releng/fixtures/isotypes.json b/releng/fixtures/isotypes.json new file mode 100644 index 00000000..a529b181 --- /dev/null +++ b/releng/fixtures/isotypes.json @@ -0,0 +1,16 @@ +[ + { + "pk": 1, + "model": "releng.isotype", + "fields": { + "name": "core" + } + }, + { + "pk": 2, + "model": "releng.isotype", + "fields": { + "name": "net" + } + } +] diff --git a/releng/fixtures/modules.json b/releng/fixtures/modules.json new file mode 100644 index 00000000..9cdf1a8d --- /dev/null +++ b/releng/fixtures/modules.json @@ -0,0 +1,86 @@ +[ + { + "pk": 1, + "model": "releng.module", + "fields": { + "name": "lvm2" + } + }, + { + "pk": 2, + "model": "releng.module", + "fields": { + "name": "dm_crypt" + } + }, + { + "pk": 3, + "model": "releng.module", + "fields": { + "name": "softraid" + } + }, + { + "pk": 4, + "model": "releng.module", + "fields": { + "name": "nilfs2" + } + }, + { + "pk": 5, + "model": "releng.module", + "fields": { + "name": "btrfs" + } + }, + { + "pk": 6, + "model": "releng.module", + "fields": { + "name": "ext2" + } + }, + { + "pk": 7, + "model": "releng.module", + "fields": { + "name": "ext3" + } + }, + { + "pk": 8, + "model": "releng.module", + "fields": { + "name": "ext4" + } + }, + { + "pk": 9, + "model": "releng.module", + "fields": { + "name": "swap" + } + }, + { + "pk": 10, + "model": "releng.module", + "fields": { + "name": "xfs" + } + }, + { + "pk": 11, + "model": "releng.module", + "fields": { + "name": "jfs" + } + }, + { + "pk": 12, + "model": "releng.module", + "fields": { + "name": "reiserFS" + } + } +] diff --git a/releng/fixtures/source.json b/releng/fixtures/source.json new file mode 100644 index 00000000..9d1950a5 --- /dev/null +++ b/releng/fixtures/source.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.source", + "fields": { + "name": "net install manual networking config (verify network, rc.conf, resolv.conf, mirrorlist)" + } + }, + { + "pk": 2, + "model": "releng.source", + "fields": { + "name": "net install dhcp (verify network, rc.conf, mirrorlist)" + } + }, + { + "pk": 3, + "model": "releng.source", + "fields": { + "name": "core" + } + } +] diff --git a/releng/management/__init__.py b/releng/management/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/management/__init__.py diff --git a/releng/management/commands/__init__.py b/releng/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/management/commands/__init__.py diff --git a/releng/management/commands/syncisos.py b/releng/management/commands/syncisos.py new file mode 100644 index 00000000..f182cc33 --- /dev/null +++ b/releng/management/commands/syncisos.py @@ -0,0 +1,61 @@ +import re +import urllib +from HTMLParser import HTMLParser, HTMLParseError + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.utils.timezone import now + +from releng.models import Iso + + +class IsoListParser(HTMLParser): + def __init__(self): + HTMLParser.__init__(self) + + self.hyperlinks = [] + self.url_re = re.compile('(?!\.{2})/$') + + def handle_starttag(self, tag, attrs): + if tag == 'a': + for name, value in attrs: + if name == "href": + if value != '../' and self.url_re.search(value) is not None: + self.hyperlinks.append(value[:-1]) + + def parse(self, url): + try: + remote_file = urllib.urlopen(url) + data = remote_file.read() + remote_file.close() + self.feed(data) + self.close() + return self.hyperlinks + except HTMLParseError: + raise CommandError('Couldn\'t parse "%s"' % url) + +class Command(BaseCommand): + help = 'Gets new ISOs from %s' % settings.ISO_LIST_URL + + def handle(self, *args, **options): + parser = IsoListParser() + isonames = Iso.objects.values_list('name', flat=True) + active_isos = parser.parse(settings.ISO_LIST_URL) + + for iso in active_isos: + # create any names that don't already exist + if iso not in isonames: + new = Iso(name=iso, active=True) + new.save() + # update those that do if they were marked inactive + else: + existing = Iso.objects.get(name=iso) + if not existing.active: + existing.active = True + existing.removed = None + existing.save(update_fields=('active', 'removed')) + # and then mark all other names as no longer active + Iso.objects.filter(active=True).exclude(name__in=active_isos).update( + active=False, removed=now()) + +# vim: set ts=4 sw=4 et: diff --git a/releng/migrations/0001_initial.py b/releng/migrations/0001_initial.py new file mode 100644 index 00000000..b56f389d --- /dev/null +++ b/releng/migrations/0001_initial.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Architecture', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Bootloader', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='BootType', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='ClockChoice', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Filesystem', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='HardwareType', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='InstallType', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Iso', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=255)), + ('created', models.DateTimeField(editable=False)), + ('removed', models.DateTimeField(default=None, null=True, blank=True)), + ('active', models.BooleanField(default=True)), + ], + options={ + 'verbose_name': 'ISO', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='IsoType', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'verbose_name': 'ISO type', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Module', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Release', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('release_date', models.DateField(db_index=True)), + ('version', models.CharField(unique=True, max_length=50)), + ('kernel_version', models.CharField(max_length=50, blank=True)), + ('md5_sum', models.CharField(max_length=32, verbose_name=b'MD5 digest', blank=True)), + ('sha1_sum', models.CharField(max_length=40, verbose_name=b'SHA1 digest', blank=True)), + ('created', models.DateTimeField(editable=False)), + ('available', models.BooleanField(default=True)), + ('info', models.TextField(verbose_name=b'Public information', blank=True)), + ('torrent_data', models.TextField(help_text=b'base64-encoded torrent file', blank=True)), + ], + options={ + 'ordering': ('-release_date', '-version'), + 'get_latest_by': 'release_date', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Source', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Test', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('user_name', models.CharField(max_length=500)), + ('user_email', models.EmailField(max_length=75, verbose_name=b'email address')), + ('ip_address', models.GenericIPAddressField(verbose_name=b'IP address', unpack_ipv4=True)), + ('created', models.DateTimeField(editable=False)), + ('success', models.BooleanField(default=True)), + ('comments', models.TextField(null=True, blank=True)), + ('architecture', models.ForeignKey(to='releng.Architecture')), + ('boot_type', models.ForeignKey(to='releng.BootType')), + ('bootloader', models.ForeignKey(to='releng.Bootloader')), + ('clock_choice', models.ForeignKey(to='releng.ClockChoice')), + ('filesystem', models.ForeignKey(to='releng.Filesystem')), + ('hardware_type', models.ForeignKey(to='releng.HardwareType')), + ('install_type', models.ForeignKey(to='releng.InstallType')), + ('iso', models.ForeignKey(to='releng.Iso')), + ('iso_type', models.ForeignKey(to='releng.IsoType')), + ('modules', models.ManyToManyField(to='releng.Module', null=True, blank=True)), + ('rollback_filesystem', models.ForeignKey(related_name=b'rollback_test_set', blank=True, to='releng.Filesystem', null=True)), + ('rollback_modules', models.ManyToManyField(related_name=b'rollback_test_set', null=True, to='releng.Module', blank=True)), + ('source', models.ForeignKey(to='releng.Source')), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/releng/migrations/0002_release_last_modified.py b/releng/migrations/0002_release_last_modified.py new file mode 100644 index 00000000..58502452 --- /dev/null +++ b/releng/migrations/0002_release_last_modified.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='release', + name='last_modified', + field=models.DateTimeField(default=datetime.datetime(2001, 1, 1, tzinfo=utc), editable=False), + preserve_default=False, + ), + ] diff --git a/releng/migrations/0003_release_populate_last_modified.py b/releng/migrations/0003_release_populate_last_modified.py new file mode 100644 index 00000000..ec7b6fda --- /dev/null +++ b/releng/migrations/0003_release_populate_last_modified.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + +def forwards(apps, schema_editor): + Release = apps.get_model('releng', 'Release') + Release.objects.update(last_modified=models.F('created')) + +def backwards(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0002_release_last_modified'), + ] + + operations = [ + migrations.RunPython(forwards, backwards) + ] diff --git a/releng/migrations/__init__.py b/releng/migrations/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/migrations/__init__.py diff --git a/releng/models.py b/releng/models.py new file mode 100644 index 00000000..a4af81ab --- /dev/null +++ b/releng/models.py @@ -0,0 +1,193 @@ +from base64 import b64decode +from bencode import bdecode, bencode +from datetime import datetime +import hashlib +from pytz import utc + +from django.conf import settings +from django.core.urlresolvers import reverse +from django.db import models +from django.db.models.signals import pre_save +from django.utils.safestring import mark_safe + +from main.fields import PositiveBigIntegerField +from main.utils import set_created_field, parse_markdown + + +class IsoOption(models.Model): + name = models.CharField(max_length=200) + + def __unicode__(self): + return self.name + + class Meta: + abstract = True + + +class RollbackOption(IsoOption): + class Meta: + abstract = True + + +class Iso(models.Model): + name = models.CharField(max_length=255) + created = models.DateTimeField(editable=False) + removed = models.DateTimeField(null=True, blank=True, default=None) + active = models.BooleanField(default=True) + + def get_absolute_url(self): + return reverse('releng-results-iso', args=[self.pk]) + + def __unicode__(self): + return self.name + + class Meta: + verbose_name = 'ISO' + + +class Architecture(IsoOption): + pass + + +class IsoType(IsoOption): + class Meta: + verbose_name = 'ISO type' + + +class BootType(IsoOption): + pass + + +class HardwareType(IsoOption): + pass + + +class InstallType(IsoOption): + pass + + +class Source(IsoOption): + pass + + +class ClockChoice(IsoOption): + pass + + +class Filesystem(RollbackOption): + pass + + +class Module(RollbackOption): + pass + + +class Bootloader(IsoOption): + pass + + +class Test(models.Model): + user_name = models.CharField(max_length=500) + user_email = models.EmailField('email address') + ip_address = models.GenericIPAddressField('IP address', unpack_ipv4=True) + created = models.DateTimeField(editable=False) + + iso = models.ForeignKey(Iso) + architecture = models.ForeignKey(Architecture) + iso_type = models.ForeignKey(IsoType) + boot_type = models.ForeignKey(BootType) + hardware_type = models.ForeignKey(HardwareType) + install_type = models.ForeignKey(InstallType) + source = models.ForeignKey(Source) + clock_choice = models.ForeignKey(ClockChoice) + filesystem = models.ForeignKey(Filesystem) + modules = models.ManyToManyField(Module, null=True, blank=True) + bootloader = models.ForeignKey(Bootloader) + rollback_filesystem = models.ForeignKey(Filesystem, + related_name="rollback_test_set", null=True, blank=True) + rollback_modules = models.ManyToManyField(Module, + related_name="rollback_test_set", null=True, blank=True) + + success = models.BooleanField(default=True) + comments = models.TextField(null=True, blank=True) + + +class Release(models.Model): + release_date = models.DateField(db_index=True) + version = models.CharField(max_length=50, unique=True) + kernel_version = models.CharField(max_length=50, blank=True) + md5_sum = models.CharField('MD5 digest', max_length=32, blank=True) + sha1_sum = models.CharField('SHA1 digest', max_length=40, blank=True) + created = models.DateTimeField(editable=False) + last_modified = models.DateTimeField(editable=False) + available = models.BooleanField(default=True) + info = models.TextField('Public information', blank=True) + torrent_data = models.TextField(blank=True, + help_text="base64-encoded torrent file") + + class Meta: + get_latest_by = 'release_date' + ordering = ('-release_date', '-version') + + def __unicode__(self): + return self.version + + def get_absolute_url(self): + return reverse('releng-release-detail', args=[self.version]) + + def dir_path(self): + return "iso/%s/" % self.version + + def iso_url(self): + return "iso/%s/%s-%s-dual.iso" % (self.version, settings.BRANDING_SLUG, self.version) + + def magnet_uri(self): + query = [ + ('dn', "%s-%s-dual.iso" % (settings.BRANDING_SLUG, self.version)), + ] + if settings.TORRENT_TRACKERS: + query.extend(('tr', uri) for uri in settings.TORRENT_TRACKERS) + metadata = self.torrent() + if metadata and 'info_hash' in metadata: + query.insert(0, ('xt', "urn:btih:%s" % metadata['info_hash'])) + return "magnet:?%s" % '&'.join(['%s=%s' % (k, v) for k, v in query]) + + def info_html(self): + return mark_safe(parse_markdown(self.info)) + + def torrent(self): + try: + data = b64decode(self.torrent_data.encode('utf-8')) + except TypeError: + return None + if not data: + return None + data = bdecode(data) + # transform the data into a template-friendly dict + info = data.get('info', {}) + metadata = { + 'comment': data.get('comment', None), + 'created_by': data.get('created by', None), + 'creation_date': None, + 'announce': data.get('announce', None), + 'file_name': info.get('name', None), + 'file_length': info.get('length', None), + 'piece_count': len(info.get('pieces', '')) / 20, + 'piece_length': info.get('piece length', None), + 'url_list': data.get('url-list', []), + 'info_hash': None, + } + if 'creation date' in data: + created= datetime.utcfromtimestamp(data['creation date']) + metadata['creation_date'] = created.replace(tzinfo=utc) + if info: + metadata['info_hash'] = hashlib.sha1(bencode(info)).hexdigest() + + return metadata + + +for model in (Iso, Test, Release): + pre_save.connect(set_created_field, sender=model, + dispatch_uid="releng.models") + +# vim: set ts=4 sw=4 et: diff --git a/releng/urls.py b/releng/urls.py new file mode 100644 index 00000000..ca76eb25 --- /dev/null +++ b/releng/urls.py @@ -0,0 +1,30 @@ +from django.conf.urls import include, patterns + +from .views import ReleaseListView, ReleaseDetailView + +feedback_patterns = patterns('releng.views', + (r'^$', 'test_results_overview', {}, 'releng-test-overview'), + (r'^submit/$', 'submit_test_result', {}, 'releng-test-submit'), + (r'^thanks/$', 'submit_test_thanks', {}, 'releng-test-thanks'), + (r'^iso/(?P<iso_id>\d+)/$', 'test_results_iso', {}, 'releng-results-iso'), + (r'^(?P<option>.+)/(?P<value>\d+)/$','test_results_for', {}, 'releng-results-for'), + (r'^iso/overview/$', 'iso_overview', {}, 'releng-iso-overview'), +) + +releases_patterns = patterns('releng.views', + (r'^$', + ReleaseListView.as_view(), {}, 'releng-release-list'), + (r'^json/$', + 'releases_json', {}, 'releng-release-list-json'), + (r'^(?P<version>[-.\w]+)/$', + ReleaseDetailView.as_view(), {}, 'releng-release-detail'), + (r'^(?P<version>[-.\w]+)/torrent/$', + 'release_torrent', {}, 'releng-release-torrent'), +) + +urlpatterns = patterns('', + (r'^feedback/', include(feedback_patterns)), + (r'^releases/', include(releases_patterns)), +) + +# vim: set ts=4 sw=4 et: diff --git a/releng/views.py b/releng/views.py new file mode 100644 index 00000000..0fb55b29 --- /dev/null +++ b/releng/views.py @@ -0,0 +1,283 @@ +from base64 import b64decode +import json + +from django import forms +from django.conf import settings +from django.core.serializers.json import DjangoJSONEncoder +from django.core.urlresolvers import reverse +from django.db.models import Count, Max +from django.http import Http404, HttpResponse +from django.shortcuts import get_object_or_404, redirect, render +from django.views.generic import DetailView, ListView + +from .models import (Architecture, BootType, Bootloader, ClockChoice, + Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source, + Test, Release) + + +def standard_field(model, empty_label=None, help_text=None, required=True): + return forms.ModelChoiceField(queryset=model.objects.all(), + widget=forms.RadioSelect(), empty_label=empty_label, + help_text=help_text, required=required) + + +class TestForm(forms.ModelForm): + iso = forms.ModelChoiceField(queryset=Iso.objects.filter( + active=True).order_by('-id')) + architecture = standard_field(Architecture) + iso_type = standard_field(IsoType) + boot_type = standard_field(BootType) + hardware_type = standard_field(HardwareType) + install_type = standard_field(InstallType) + source = standard_field(Source) + clock_choice = standard_field(ClockChoice) + filesystem = standard_field(Filesystem, + help_text="Verify /etc/fstab, `df -hT` output and commands like " + "lvdisplay for special modules.") + modules = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), + widget=forms.CheckboxSelectMultiple(), required=False) + bootloader = standard_field(Bootloader, + help_text="Verify that the entries in the bootloader config " + "looks OK.") + rollback_filesystem = standard_field(Filesystem, + help_text="If you did a rollback followed by a new attempt to " + "setup your blockdevices/filesystems, select which option you " + "took here.", + empty_label="N/A (did not rollback)", required=False) + rollback_modules = forms.ModelMultipleChoiceField( + queryset=Module.objects.all(), + help_text="If you did a rollback followed by a new attempt to " + "setup your blockdevices/filesystems, select which option you " + "took here.", + widget=forms.CheckboxSelectMultiple(), required=False) + success = forms.BooleanField( + help_text="Only check this if everything went fine. " + "If you ran into problems please create a ticket on <a " + "href=\""+settings.BUGTRACKER_RELENG_URL+"\">the " + "bugtracker</a> (or check that one already exists) and link to " + "it in the comments.", + required=False) + website = forms.CharField(label='', + widget=forms.TextInput(attrs={'style': 'display:none;'}), + required=False) + + class Meta: + model = Test + fields = ("user_name", "user_email", "iso", "architecture", + "iso_type", "boot_type", "hardware_type", + "install_type", "source", "clock_choice", "filesystem", + "modules", "bootloader", "rollback_filesystem", + "rollback_modules", "success", "comments") + widgets = { + "modules": forms.CheckboxSelectMultiple(), + } + + +def submit_test_result(request): + if request.POST: + form = TestForm(request.POST) + if form.is_valid() and request.POST['website'] == '': + test = form.save(commit=False) + test.ip_address = request.META.get("REMOTE_ADDR", None) + test.save() + form.save_m2m() + return redirect('releng-test-thanks') + else: + form = TestForm() + + context = {'form': form} + return render(request, 'releng/add.html', context) + + +def calculate_option_overview(field_name): + field = Test._meta.get_field(field_name) + model = field.rel.to + is_rollback = field_name.startswith('rollback_') + option = { + 'option': model, + 'field_name': field_name, + 'name': model._meta.verbose_name, + 'is_rollback': is_rollback, + 'values': [] + } + if not is_rollback: + successes = dict(model.objects.values_list('pk').filter( + test__success=True).annotate(latest=Max('test__iso__id'))) + failures = dict(model.objects.values_list('pk').filter( + test__success=False).annotate(latest=Max('test__iso__id'))) + else: + successes = dict(model.objects.values_list('pk').filter( + rollback_test_set__success=True).annotate( + latest=Max('rollback_test_set__iso__id'))) + failures = dict(model.objects.values_list('pk').filter( + rollback_test_set__success=False).annotate( + latest=Max('rollback_test_set__iso__id'))) + + for value in model.objects.all(): + data = { + 'value': value, + 'success': successes.get(value.pk), + 'failure': failures.get(value.pk), + } + option['values'].append(data) + + return option + + +def options_fetch_iso(options): + '''Replaces the Iso PK with a full Iso model object in a list of options + used on the overview page. We do it this way to only have to query the Iso + table once rather than once per option.''' + # collect all necessary Iso PKs + all_pks = set() + for option in options: + all_pks.update(v['success'] for v in option['values']) + all_pks.update(v['failure'] for v in option['values']) + + all_pks.discard(None) + all_isos = Iso.objects.in_bulk(all_pks) + + for option in options: + for value in option['values']: + value['success'] = all_isos.get(value['success']) + value['failure'] = all_isos.get(value['failure']) + + return options + + +def test_results_overview(request): + # data structure produced: + # [ { + # option, name, is_rollback, + # values: [ { value, success, failure } ... ] + # } + # ... + # ] + all_options = [] + fields = ['architecture', 'iso_type', 'boot_type', 'hardware_type', + 'install_type', 'source', 'clock_choice', 'filesystem', 'modules', + 'bootloader', 'rollback_filesystem', 'rollback_modules'] + for field in fields: + all_options.append(calculate_option_overview(field)) + + all_options = options_fetch_iso(all_options) + + context = { + 'options': all_options, + 'iso_url': settings.ISO_LIST_URL, + } + return render(request, 'releng/results.html', context) + + +def test_results_iso(request, iso_id): + iso = get_object_or_404(Iso, pk=iso_id) + test_list = iso.test_set.select_related() + context = { + 'iso_name': iso.name, + 'test_list': test_list + } + return render(request, 'releng/result_list.html', context) + + +def test_results_for(request, option, value): + if option not in Test._meta.get_all_field_names(): + raise Http404 + option_model = getattr(Test, option).field.rel.to + option_model.verbose_name = option_model._meta.verbose_name + real_value = get_object_or_404(option_model, pk=value) + test_list = real_value.test_set.select_related().order_by( + '-iso__name', '-pk') + context = { + 'option': option_model, + 'value': real_value, + 'value_id': value, + 'test_list': test_list + } + return render(request, 'releng/result_list.html', context) + + +def submit_test_thanks(request): + return render(request, "releng/thanks.html", None) + + +def iso_overview(request): + isos = Iso.objects.all().order_by('-pk') + successes = dict(Iso.objects.values_list('pk').filter( + test__success=True).annotate(ct=Count('test'))) + failures = dict(Iso.objects.values_list('pk').filter( + test__success=False).annotate(ct=Count('test'))) + for iso in isos: + iso.successes = successes.get(iso.pk, 0) + iso.failures = failures.get(iso.pk, 0) + + # only show "useful" rows, currently active ISOs or those with results + isos = [iso for iso in isos if + iso.active is True or iso.successes > 0 or iso.failures > 0] + + context = { + 'isos': isos + } + return render(request, 'releng/iso_overview.html', context) + + +class ReleaseListView(ListView): + model = Release + + +class ReleaseDetailView(DetailView): + model = Release + slug_field = 'version' + slug_url_kwarg = 'version' + + +def release_torrent(request, version): + release = get_object_or_404(Release, version=version) + if not release.torrent_data: + raise Http404 + data = b64decode(release.torrent_data.encode('utf-8')) + response = HttpResponse(data, content_type='application/x-bittorrent') + # TODO: this is duplicated from Release.iso_url() + filename = '%s-%s-dual.iso.torrent' % (settings.BRANDING_SLUG, release.version) + response['Content-Disposition'] = 'attachment; filename=%s' % filename + return response + + +class ReleaseJSONEncoder(DjangoJSONEncoder): + release_attributes = ('release_date', 'version', 'kernel_version', + 'created', 'md5_sum', 'sha1_sum') + + def default(self, obj): + if isinstance(obj, Release): + data = {attr: getattr(obj, attr) or None + for attr in self.release_attributes} + data['available'] = obj.available + data['iso_url'] = '/' + obj.iso_url() + data['magnet_uri'] = obj.magnet_uri() + data['torrent_url'] = reverse('releng-release-torrent', args=[obj.version]) + data['info'] = obj.info_html() + torrent_data = obj.torrent() + if torrent_data: + torrent_data.pop('url_list', None) + data['torrent'] = torrent_data + return data + return super(ReleaseJSONEncoder, self).default(obj) + + +def releases_json(request): + releases = Release.objects.all() + try: + latest_version = Release.objects.filter(available=True).values_list( + 'version', flat=True).latest() + except Release.DoesNotExist: + latest_version = None + + data = { + 'version': 1, + 'releases': list(releases), + 'latest_version': latest_version, + } + to_json = json.dumps(data, ensure_ascii=False, cls=ReleaseJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + +# vim: set ts=4 sw=4 et: diff --git a/requirements.txt b/requirements.txt index 6d858a11..8128b451 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,12 @@ -Django==1.2.3 -Markdown==2.0.3 -South==0.7.2 +-e git+git://github.com/fredj/cssmin.git@master#egg=cssmin +Django==1.7.11 +IPy==0.83 +Jinja2==2.7.3 +Markdown==2.6.2 +MarkupSafe==0.23 +bencode==1.0 +django-countries==3.3 +django-jinja==1.3.3 +jsmin==2.1.1 +pgpdump==1.5 +pytz>=2015.4 diff --git a/requirements_prod.txt b/requirements_prod.txt index 7f5abb55..bcb30f3e 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,5 +1,15 @@ -Django==1.2.3 -Markdown==2.0.3 -MySQL-python==1.2.3c1 -South==0.7.2 -python-memcached==1.45 +-e git+git://github.com/fredj/cssmin.git@master#egg=cssmin +Django==1.7.8 +IPy==0.83 +Jinja2==2.7.3 +Markdown==2.6.2 +MarkupSafe==0.23 +bencode==1.0 +django-countries==3.3 +django-jinja==1.3.3 +jsmin==2.1.1 +pgpdump==1.5 +psycopg2==2.6.1 +pyinotify==0.9.6 +python-memcached==1.54 +pytz>=2015.4 diff --git a/retro/__init__.py b/retro/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/retro/__init__.py diff --git a/retro/static/2002/archlogo_black.gif b/retro/static/2002/archlogo_black.gif Binary files differnew file mode 100644 index 00000000..b4f979f4 --- /dev/null +++ b/retro/static/2002/archlogo_black.gif diff --git a/retro/static/2002/main.css b/retro/static/2002/main.css new file mode 100644 index 00000000..ea33cfae --- /dev/null +++ b/retro/static/2002/main.css @@ -0,0 +1,144 @@ +a:visited { + color: #dddddd; + text-decoration: none; + font-weight: bold; +} + +a:link { + color: #dddddd; + text-decoration: none; + font-weight: bold; +} + +a:hover { + color: #cccc00; + text-decoration: none; + font-weight: bold; +} + +a.menu { + text-decoration: none; + color: #ffffff; + font-family: Arial; + font-size: 12pt; +} + +body { + font-family: Arial; + background: #222222 none; +} + +b { + font-weight: bold; + font-family: Arial; + font-size: 13pt; +} + +b.normal { + font-weight: bold; + font-family: Arial; + font-size: 12pt; +} + +.text { + font-family: Arial; + font-size: 12pt; +} + +.quote { + font-family: Arial; + font-style: italic; + font-size: 11pt; +} + +.technical { + font-family: Courier; + color: #eeeeee; + font-size: 10pt; +} + +.fineprint { + font-family: Arial; + font-size: 10pt; +} + +.header { + color: #cccccc; + font-family: Arial; + font-size: 28pt; + font-weight: bolder; +} + +.subheader { + color: #eeeeee; + font-family: Arial; + font-size: 24pt; + font-weight: bold; +} + +ul.plain { + list-style: none; + font-family: Arial; + font-size: 12pt; +} + +ul.list { + list-style: square; + font-family: Arial; + font-size: 12pt; +} + +table.border { + background-repeat: no-repeat; + background-color: #000000; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + width: 93%; + padding: 5px; +} + +table.menu { + background-image: none; + background-color: none; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Arial; + font-size: 12pt; +} + +table.normal { + border-bottom: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Arial; + font-size: 12pt; +} + +table.technical { + border-bottom: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Courier; + font-size: 10pt; +} + +td { + color: #dddddd; + font-family: Arial; + font-size: 12pt; +} + +td.menu { + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + color: #dddddd; + text-align: center; + white-space: nowrap; + font-family: Arial; + font-size: 10pt; +} diff --git a/retro/static/2002/sflogo.png b/retro/static/2002/sflogo.png Binary files differnew file mode 100644 index 00000000..1b2870c0 --- /dev/null +++ b/retro/static/2002/sflogo.png diff --git a/retro/static/2003/dblue071.jpg b/retro/static/2003/dblue071.jpg Binary files differnew file mode 100644 index 00000000..d8c98954 --- /dev/null +++ b/retro/static/2003/dblue071.jpg diff --git a/retro/static/2003/favicon.ico b/retro/static/2003/favicon.ico Binary files differnew file mode 100644 index 00000000..8c129f24 --- /dev/null +++ b/retro/static/2003/favicon.ico diff --git a/media/logos/legacy/arch-legacy-ribbon5.png b/retro/static/2003/logo.png Binary files differindex abf7cce4..abf7cce4 100644 --- a/media/logos/legacy/arch-legacy-ribbon5.png +++ b/retro/static/2003/logo.png diff --git a/retro/static/2003/main.css b/retro/static/2003/main.css new file mode 100644 index 00000000..b9b2330d --- /dev/null +++ b/retro/static/2003/main.css @@ -0,0 +1,272 @@ +a:visited { + color: #dddddd; + text-decoration: none; + font-weight: bold; +} + +a:link { + color: #dddddd; + text-decoration: none; + font-weight: bold; +} + +a:hover { + color: #cccc00; + text-decoration: none; + font-weight: bold; +} + +a.menu { + text-decoration: none; + color: #ffffff; + font-family: Arial; + font-size: 10pt; +} + +a.menu:hover { + color: #cccc00; + text-decoration: none; + font-weight: bold; +} + +a.row { + text-decoration: none; + color: #dddd00; + font-weight: normal; +} + +a.row:hover { + color: #f2c011; + font-weight: bold; + text-decoration: none; +} + +body { + font-family: Arial; + font-size: 1.0em; + background: #222222 url('dblue071.jpg'); +} + +b { + font-weight: bold; + font-family: Arial; + font-size: 1.0em; +} + +b.normal { + font-weight: bold; + font-family: Arial; + font-size: 0.9em; +} + +.text { + font-family: Arial; + font-size: 0.9em; +} + +.quote { + font-family: Arial; + font-style: italic; + font-size: 1.2em; +} + +.technical { + font-family: Courier New; + color: #eeeeee; + font-size: 0.8em; +} + +.fineprint { + font-family: Arial; + font-size: 0.75em; +} + +.header { + color: #cccccc; + font-family: Arial; + font-size: 24pt; + font-weight: bolder; +} + +.subheader { + color: #eeeeee; + font-family: Arial; + font-size: 1.7em; + font-weight: bold; +} + +.headline { + color: #eeeeee; + font-family: Arial; + font-weight: bold; + font-size: 1.2em; +} + +ul.plain { + list-style: none; + font-family: Arial; + font-size: 1.0em; +} + +ul.list { + list-style: square; + font-family: Arial; + font-size: 1.0em; +} + +input.button { + background: #404040 none; + border: #cccccc 1px solid; + color: #cccc00; + font-family: Verdana, Arial; + font-size: 10px; + font-weight: bold; + padding: 0px; +} + +table.container { + width: 95%; + padding: 5px; +} + +table.box { + background: #222222 url('dblue071.jpg'); + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + width: 95%; + padding: 0px; +} + +table.header { + background: #000000; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + width: 100%; + padding: 5px; +} + +table.nav { + background-color: #000000; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + width: 100%; + padding: 5px; +} + +table.content { + background-color: #000000; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + width: 100%; + padding: 5px; +} + +table.menu { + background-image: none; + background-color: none; + border-bottom: #cccccc 1px solid; + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Arial; + font-size: 0.9em; +} + +table.normal { + border-bottom: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Arial; + font-size: 12pt; +} + +table.technical { + border-bottom: #cccccc 1px solid; + border-top: #cccccc 1px solid; + padding: none; + font-family: Courier; + font-size: 12pt; +} + +table.row { + border: none; + background: none transparent; + padding: none; + font-family: Lucida, Verdana, Arial; +} + +td.row1 { + background: #190866; + color: #dddd00; + border-top: #eeeeee 1px solid; + border-left: #eeeeee 1px solid; +} + +td.row2 { + background: #636268; + color: #dddd00; + border-top: #eeeeee 1px solid; + border-left: #eeeeee 1px solid; +} + +td { + color: #dddddd; + font-family: Arial; + font-size: 12px; +} + +th { + color: #dddddd; + font-family: Arial; + font-size: 16px; +} + +th.row { +} + +th.rowhdr { + color: #f2c011; + background: #302d49; + border-top: #eeeeee 1px solid; + border-left: #eeeeee 1px solid; +} + +td.box_headline { + color: #dddddd; + background: #000000; + border-bottom: #cccccc 1px solid; + padding: 0px; +} + +td.trans_text { + color: #dddddd; + background: none; +} + +td.box_content { + color: #dddddd; + background: #000000 none; + text-align: left; + border-top: #cccccc 1px solid; + padding: 2px; +} + +td.menu { + border-left: #cccccc 1px solid; + border-right: #cccccc 1px solid; + color: #dddddd; + text-align: center; + white-space: nowrap; + font-family: Arial; + font-size: 10pt; +} + diff --git a/retro/static/2003/sflogo.png b/retro/static/2003/sflogo.png Binary files differnew file mode 100644 index 00000000..a10050d7 --- /dev/null +++ b/retro/static/2003/sflogo.png diff --git a/retro/static/2004/containers.css b/retro/static/2004/containers.css new file mode 100644 index 00000000..7322b3f1 --- /dev/null +++ b/retro/static/2004/containers.css @@ -0,0 +1,199 @@ + body,table,td,img
+ {
+ border: 0px;
+ margin: 0px;
+ padding: 0px;
+ font-family: arial,verdana,tahoma;
+ }
+
+/* Main Wrapper Data Format */
+ td.preHeader
+ {
+ background-color: #000;
+ border-bottom: 1px solid rgb( 69, 84, 113 );
+ height: 16px;
+ text-align: right;
+ }
+ td.headerFill
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ }
+ td.headerDisplay
+ {
+ background-color: rgb( 108, 131, 176 );
+ padding-left: 16px;
+ }
+ td.mainLinks
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ height: 22px;
+ padding-left: 12px;
+ }
+ td.sideBar
+ {
+ background-color: #fff;
+ text-align: center;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarGrey
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: left;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarSmall
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ height: 16px;
+ text-align: right;
+ width: 150px;
+ }
+ td.sideBarSmallHeader
+ {
+ background-color: rgb(108,131,176);
+ vertical-align: top;
+ height: 16px;
+ padding-top: 1px;
+ padding-bottom: 2px;
+ text-align: right;
+ width: 150px;
+ }
+ td.subLinks
+ {
+ background-color: rgb( 225, 228, 232 );
+ border-right: 1px solid #000;
+ color: rgb( 120, 120, 120 );
+ padding-left: 12px;
+ height: 19px;
+ }
+ td.contentDisplay
+ {
+ background-color: #ffffff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ vertical-align: top;
+ padding: 10;
+ }
+
+ td.footerDisplay
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ }
+
+/* Containers Used Globally */
+ table.boxSoft
+ {
+ width: 90%;
+ background-color: #ddd;
+ }
+ td.boxSoft
+ {
+ background-color: #fff;
+ padding: 10;
+ }
+ td.boxSoftColumn
+ {
+ padding-left: 16;
+ padding-right: 16;
+ text-align: justify;
+ vertical-align: top;
+ text-indent: 20px;
+ }
+ td.div
+ {
+ background-color: #eee;
+ width: 3px;
+ }
+ td.boxSoftTitle
+ {
+ border-bottom: 1px solid #fff;
+ border-top: 1px solid #fff;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ padding-top: 1;
+ padding-bottom: 1;
+ }
+ table.boxSoftSmall
+ {
+ width: 94%;
+ background-color: #ddd;
+ }
+ td.boxSoftSmall
+ {
+ background-color: #fff;
+ text-align: center;
+ padding-top: 2;
+ padding-bottom: 2;
+ }
+ td.boxSoftSmallTitle
+ {
+ border-bottom: 1px solid #ccc;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ }
+ td.ss /* ss = small space */
+ {
+ padding-left: 6px;
+ vertical-align: top;
+ }
+ td.display
+ {
+ border-bottom: 1px solid #000;
+ padding-bottom: 6px;
+ }
+ td.features
+ {
+ padding: 4px;
+ text-align: justify;
+ vertical-align:top;
+ }
+ td.formLeft
+ {
+ padding: 6px;
+ text-align: left;
+ vertical-align: top;
+ }
+ td.data1
+ {
+ background-color: #eee;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ td.data2
+ {
+ background-color: #ddd;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ th
+ {
+ text-align: left;
+ }
+
+ input,textarea,select
+ {
+ background-color: rgb(108,131,176);
+ font-family: courier;
+ font-size: 12px;
+ background-color: #ccc;
+ border: #000000 1px solid;
+ color: #111111;
+ }
+
+ input.button
+ {
+ background-color: #fff;
+ color: rgb(108,131,176);
+ border: 1px dashed rgb(108,131,176);
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 12px;
+ }
diff --git a/retro/static/2004/favicon.ico b/retro/static/2004/favicon.ico Binary files differnew file mode 100644 index 00000000..a9f4e837 --- /dev/null +++ b/retro/static/2004/favicon.ico diff --git a/retro/static/2004/fonts.css b/retro/static/2004/fonts.css new file mode 100644 index 00000000..7def6210 --- /dev/null +++ b/retro/static/2004/fonts.css @@ -0,0 +1,96 @@ +/* Standard Fonts */
+ span /* Applicable by default in all fonts */
+ {
+ color: #666;
+ font-family: verdana, trebuchet ms, tahoma, luxi sans;
+ }
+ span.f1 /* Important */
+ {
+ font-family: verdana;
+ font-size: 20px;
+ letter-spacing: 1px;
+ }
+ span.f2 /* Title */
+ {
+ font-size: 14px;
+ color: rgb(108, 131, 176);
+ font-weight: bold;
+ }
+ span.f3 /* Sub Title */
+ {
+ color: #888;
+ font-size: 14px;
+ font-weight: bold;
+ }
+ span.f4 /* Content Text */
+ {
+ color: #444;
+ font-family: verdana;
+ font-size: 12px;
+ }
+ span.f5 /* Content Small */
+ {
+ color: #333;
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 11px;
+ }
+
+/* Font Attribute Change (#6c83b0)*/
+ span.blue
+ {
+ color: rgb( 108, 131, 176 );
+ }
+ span.white
+ {
+ color: white;
+ }
+ span.black
+ {
+ color: black;
+ }
+ span.link
+ {
+ color: rgb( 108, 131, 176 );
+ font-weight: bold;
+ }
+
+/* Misc (c9d1e2) */
+ span.preHeader
+ {
+ color: rgb( 201, 209, 226 );
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ word-spacing: 8px;
+ }
+ span.sideBarSmallHeader
+ {
+ color: #fff;
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ }
+
+a:visited {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:link {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:hover {
+ color: #990000;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+h1,h2,h3,h4 {
+ font-size: 16pt;
+}
diff --git a/retro/static/2004/frontComponents.gif b/retro/static/2004/frontComponents.gif Binary files differnew file mode 100644 index 00000000..0f20c0d4 --- /dev/null +++ b/retro/static/2004/frontComponents.gif diff --git a/retro/static/2004/frontNews.gif b/retro/static/2004/frontNews.gif Binary files differnew file mode 100644 index 00000000..6c2f35d0 --- /dev/null +++ b/retro/static/2004/frontNews.gif diff --git a/retro/static/2004/logoTop.gif b/retro/static/2004/logoTop.gif Binary files differnew file mode 100644 index 00000000..9233b177 --- /dev/null +++ b/retro/static/2004/logoTop.gif diff --git a/retro/static/2004/pad.gif b/retro/static/2004/pad.gif Binary files differnew file mode 100644 index 00000000..7761b868 --- /dev/null +++ b/retro/static/2004/pad.gif diff --git a/retro/static/2004/sflogo.png b/retro/static/2004/sflogo.png Binary files differnew file mode 100644 index 00000000..b49f6ccf --- /dev/null +++ b/retro/static/2004/sflogo.png diff --git a/retro/static/2004/x-click-butcc-donate.gif b/retro/static/2004/x-click-butcc-donate.gif Binary files differnew file mode 100644 index 00000000..046f3788 --- /dev/null +++ b/retro/static/2004/x-click-butcc-donate.gif diff --git a/retro/static/2005/button.png b/retro/static/2005/button.png Binary files differnew file mode 100644 index 00000000..670d69c6 --- /dev/null +++ b/retro/static/2005/button.png diff --git a/retro/static/2005/containers.css b/retro/static/2005/containers.css new file mode 100644 index 00000000..7322b3f1 --- /dev/null +++ b/retro/static/2005/containers.css @@ -0,0 +1,199 @@ + body,table,td,img
+ {
+ border: 0px;
+ margin: 0px;
+ padding: 0px;
+ font-family: arial,verdana,tahoma;
+ }
+
+/* Main Wrapper Data Format */
+ td.preHeader
+ {
+ background-color: #000;
+ border-bottom: 1px solid rgb( 69, 84, 113 );
+ height: 16px;
+ text-align: right;
+ }
+ td.headerFill
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ }
+ td.headerDisplay
+ {
+ background-color: rgb( 108, 131, 176 );
+ padding-left: 16px;
+ }
+ td.mainLinks
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ height: 22px;
+ padding-left: 12px;
+ }
+ td.sideBar
+ {
+ background-color: #fff;
+ text-align: center;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarGrey
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: left;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarSmall
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ height: 16px;
+ text-align: right;
+ width: 150px;
+ }
+ td.sideBarSmallHeader
+ {
+ background-color: rgb(108,131,176);
+ vertical-align: top;
+ height: 16px;
+ padding-top: 1px;
+ padding-bottom: 2px;
+ text-align: right;
+ width: 150px;
+ }
+ td.subLinks
+ {
+ background-color: rgb( 225, 228, 232 );
+ border-right: 1px solid #000;
+ color: rgb( 120, 120, 120 );
+ padding-left: 12px;
+ height: 19px;
+ }
+ td.contentDisplay
+ {
+ background-color: #ffffff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ vertical-align: top;
+ padding: 10;
+ }
+
+ td.footerDisplay
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ }
+
+/* Containers Used Globally */
+ table.boxSoft
+ {
+ width: 90%;
+ background-color: #ddd;
+ }
+ td.boxSoft
+ {
+ background-color: #fff;
+ padding: 10;
+ }
+ td.boxSoftColumn
+ {
+ padding-left: 16;
+ padding-right: 16;
+ text-align: justify;
+ vertical-align: top;
+ text-indent: 20px;
+ }
+ td.div
+ {
+ background-color: #eee;
+ width: 3px;
+ }
+ td.boxSoftTitle
+ {
+ border-bottom: 1px solid #fff;
+ border-top: 1px solid #fff;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ padding-top: 1;
+ padding-bottom: 1;
+ }
+ table.boxSoftSmall
+ {
+ width: 94%;
+ background-color: #ddd;
+ }
+ td.boxSoftSmall
+ {
+ background-color: #fff;
+ text-align: center;
+ padding-top: 2;
+ padding-bottom: 2;
+ }
+ td.boxSoftSmallTitle
+ {
+ border-bottom: 1px solid #ccc;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ }
+ td.ss /* ss = small space */
+ {
+ padding-left: 6px;
+ vertical-align: top;
+ }
+ td.display
+ {
+ border-bottom: 1px solid #000;
+ padding-bottom: 6px;
+ }
+ td.features
+ {
+ padding: 4px;
+ text-align: justify;
+ vertical-align:top;
+ }
+ td.formLeft
+ {
+ padding: 6px;
+ text-align: left;
+ vertical-align: top;
+ }
+ td.data1
+ {
+ background-color: #eee;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ td.data2
+ {
+ background-color: #ddd;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ th
+ {
+ text-align: left;
+ }
+
+ input,textarea,select
+ {
+ background-color: rgb(108,131,176);
+ font-family: courier;
+ font-size: 12px;
+ background-color: #ccc;
+ border: #000000 1px solid;
+ color: #111111;
+ }
+
+ input.button
+ {
+ background-color: #fff;
+ color: rgb(108,131,176);
+ border: 1px dashed rgb(108,131,176);
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 12px;
+ }
diff --git a/retro/static/2005/favicon.ico b/retro/static/2005/favicon.ico Binary files differnew file mode 100644 index 00000000..a9f4e837 --- /dev/null +++ b/retro/static/2005/favicon.ico diff --git a/retro/static/2005/fonts.css b/retro/static/2005/fonts.css new file mode 100644 index 00000000..7def6210 --- /dev/null +++ b/retro/static/2005/fonts.css @@ -0,0 +1,96 @@ +/* Standard Fonts */
+ span /* Applicable by default in all fonts */
+ {
+ color: #666;
+ font-family: verdana, trebuchet ms, tahoma, luxi sans;
+ }
+ span.f1 /* Important */
+ {
+ font-family: verdana;
+ font-size: 20px;
+ letter-spacing: 1px;
+ }
+ span.f2 /* Title */
+ {
+ font-size: 14px;
+ color: rgb(108, 131, 176);
+ font-weight: bold;
+ }
+ span.f3 /* Sub Title */
+ {
+ color: #888;
+ font-size: 14px;
+ font-weight: bold;
+ }
+ span.f4 /* Content Text */
+ {
+ color: #444;
+ font-family: verdana;
+ font-size: 12px;
+ }
+ span.f5 /* Content Small */
+ {
+ color: #333;
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 11px;
+ }
+
+/* Font Attribute Change (#6c83b0)*/
+ span.blue
+ {
+ color: rgb( 108, 131, 176 );
+ }
+ span.white
+ {
+ color: white;
+ }
+ span.black
+ {
+ color: black;
+ }
+ span.link
+ {
+ color: rgb( 108, 131, 176 );
+ font-weight: bold;
+ }
+
+/* Misc (c9d1e2) */
+ span.preHeader
+ {
+ color: rgb( 201, 209, 226 );
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ word-spacing: 8px;
+ }
+ span.sideBarSmallHeader
+ {
+ color: #fff;
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ }
+
+a:visited {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:link {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:hover {
+ color: #990000;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+h1,h2,h3,h4 {
+ font-size: 16pt;
+}
diff --git a/retro/static/2005/frontComponents.gif b/retro/static/2005/frontComponents.gif Binary files differnew file mode 100644 index 00000000..0f20c0d4 --- /dev/null +++ b/retro/static/2005/frontComponents.gif diff --git a/retro/static/2005/frontNews.gif b/retro/static/2005/frontNews.gif Binary files differnew file mode 100644 index 00000000..6c2f35d0 --- /dev/null +++ b/retro/static/2005/frontNews.gif diff --git a/retro/static/2005/logoTop.png b/retro/static/2005/logoTop.png Binary files differnew file mode 100644 index 00000000..e96cabc9 --- /dev/null +++ b/retro/static/2005/logoTop.png diff --git a/retro/static/2005/pad.gif b/retro/static/2005/pad.gif Binary files differnew file mode 100644 index 00000000..7761b868 --- /dev/null +++ b/retro/static/2005/pad.gif diff --git a/retro/static/2005/sflogo.png b/retro/static/2005/sflogo.png Binary files differnew file mode 100644 index 00000000..b65567f7 --- /dev/null +++ b/retro/static/2005/sflogo.png diff --git a/retro/static/2005/x-click-butcc-donate.gif b/retro/static/2005/x-click-butcc-donate.gif Binary files differnew file mode 100644 index 00000000..046f3788 --- /dev/null +++ b/retro/static/2005/x-click-butcc-donate.gif diff --git a/retro/static/2006/button.png b/retro/static/2006/button.png Binary files differnew file mode 100644 index 00000000..670d69c6 --- /dev/null +++ b/retro/static/2006/button.png diff --git a/retro/static/2006/containers.css b/retro/static/2006/containers.css new file mode 100644 index 00000000..7322b3f1 --- /dev/null +++ b/retro/static/2006/containers.css @@ -0,0 +1,199 @@ + body,table,td,img
+ {
+ border: 0px;
+ margin: 0px;
+ padding: 0px;
+ font-family: arial,verdana,tahoma;
+ }
+
+/* Main Wrapper Data Format */
+ td.preHeader
+ {
+ background-color: #000;
+ border-bottom: 1px solid rgb( 69, 84, 113 );
+ height: 16px;
+ text-align: right;
+ }
+ td.headerFill
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ }
+ td.headerDisplay
+ {
+ background-color: rgb( 108, 131, 176 );
+ padding-left: 16px;
+ }
+ td.mainLinks
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ height: 22px;
+ padding-left: 12px;
+ }
+ td.sideBar
+ {
+ background-color: #fff;
+ text-align: center;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarGrey
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: left;
+ vertical-align: top;
+ width: 150px;
+ }
+ td.sideBarSmall
+ {
+ background-color: rgb( 108, 131, 176 );
+ border-bottom: 1px solid #000;
+ height: 16px;
+ text-align: right;
+ width: 150px;
+ }
+ td.sideBarSmallHeader
+ {
+ background-color: rgb(108,131,176);
+ vertical-align: top;
+ height: 16px;
+ padding-top: 1px;
+ padding-bottom: 2px;
+ text-align: right;
+ width: 150px;
+ }
+ td.subLinks
+ {
+ background-color: rgb( 225, 228, 232 );
+ border-right: 1px solid #000;
+ color: rgb( 120, 120, 120 );
+ padding-left: 12px;
+ height: 19px;
+ }
+ td.contentDisplay
+ {
+ background-color: #ffffff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ vertical-align: top;
+ padding: 10;
+ }
+
+ td.footerDisplay
+ {
+ background-color: #eee;
+ border-bottom: 1px solid #000;
+ text-align: center;
+ }
+
+/* Containers Used Globally */
+ table.boxSoft
+ {
+ width: 90%;
+ background-color: #ddd;
+ }
+ td.boxSoft
+ {
+ background-color: #fff;
+ padding: 10;
+ }
+ td.boxSoftColumn
+ {
+ padding-left: 16;
+ padding-right: 16;
+ text-align: justify;
+ vertical-align: top;
+ text-indent: 20px;
+ }
+ td.div
+ {
+ background-color: #eee;
+ width: 3px;
+ }
+ td.boxSoftTitle
+ {
+ border-bottom: 1px solid #fff;
+ border-top: 1px solid #fff;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ padding-top: 1;
+ padding-bottom: 1;
+ }
+ table.boxSoftSmall
+ {
+ width: 94%;
+ background-color: #ddd;
+ }
+ td.boxSoftSmall
+ {
+ background-color: #fff;
+ text-align: center;
+ padding-top: 2;
+ padding-bottom: 2;
+ }
+ td.boxSoftSmallTitle
+ {
+ border-bottom: 1px solid #ccc;
+ background-color: rgb( 241, 242, 244 );
+ padding-left: 10;
+ }
+ td.ss /* ss = small space */
+ {
+ padding-left: 6px;
+ vertical-align: top;
+ }
+ td.display
+ {
+ border-bottom: 1px solid #000;
+ padding-bottom: 6px;
+ }
+ td.features
+ {
+ padding: 4px;
+ text-align: justify;
+ vertical-align:top;
+ }
+ td.formLeft
+ {
+ padding: 6px;
+ text-align: left;
+ vertical-align: top;
+ }
+ td.data1
+ {
+ background-color: #eee;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ td.data2
+ {
+ background-color: #ddd;
+ vertical-align: top;
+ padding-left: 5;
+ }
+ th
+ {
+ text-align: left;
+ }
+
+ input,textarea,select
+ {
+ background-color: rgb(108,131,176);
+ font-family: courier;
+ font-size: 12px;
+ background-color: #ccc;
+ border: #000000 1px solid;
+ color: #111111;
+ }
+
+ input.button
+ {
+ background-color: #fff;
+ color: rgb(108,131,176);
+ border: 1px dashed rgb(108,131,176);
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 12px;
+ }
diff --git a/retro/static/2006/favicon.ico b/retro/static/2006/favicon.ico Binary files differnew file mode 100644 index 00000000..a9f4e837 --- /dev/null +++ b/retro/static/2006/favicon.ico diff --git a/retro/static/2006/fonts.css b/retro/static/2006/fonts.css new file mode 100644 index 00000000..7def6210 --- /dev/null +++ b/retro/static/2006/fonts.css @@ -0,0 +1,96 @@ +/* Standard Fonts */
+ span /* Applicable by default in all fonts */
+ {
+ color: #666;
+ font-family: verdana, trebuchet ms, tahoma, luxi sans;
+ }
+ span.f1 /* Important */
+ {
+ font-family: verdana;
+ font-size: 20px;
+ letter-spacing: 1px;
+ }
+ span.f2 /* Title */
+ {
+ font-size: 14px;
+ color: rgb(108, 131, 176);
+ font-weight: bold;
+ }
+ span.f3 /* Sub Title */
+ {
+ color: #888;
+ font-size: 14px;
+ font-weight: bold;
+ }
+ span.f4 /* Content Text */
+ {
+ color: #444;
+ font-family: verdana;
+ font-size: 12px;
+ }
+ span.f5 /* Content Small */
+ {
+ color: #333;
+ font-family: trebuchet ms, tahoma, verdana;
+ font-size: 11px;
+ }
+
+/* Font Attribute Change (#6c83b0)*/
+ span.blue
+ {
+ color: rgb( 108, 131, 176 );
+ }
+ span.white
+ {
+ color: white;
+ }
+ span.black
+ {
+ color: black;
+ }
+ span.link
+ {
+ color: rgb( 108, 131, 176 );
+ font-weight: bold;
+ }
+
+/* Misc (c9d1e2) */
+ span.preHeader
+ {
+ color: rgb( 201, 209, 226 );
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ word-spacing: 8px;
+ }
+ span.sideBarSmallHeader
+ {
+ color: #fff;
+ font-weight: bold;
+ font-size: 11px;
+ font-family: tahoma, trebuchet ms, verdana;
+ padding-right: 8px;
+ }
+
+a:visited {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:link {
+ color: rgb(108,131,176);
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:hover {
+ color: #990000;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+h1,h2,h3,h4 {
+ font-size: 16pt;
+}
diff --git a/retro/static/2006/frontComponents.gif b/retro/static/2006/frontComponents.gif Binary files differnew file mode 100644 index 00000000..0f20c0d4 --- /dev/null +++ b/retro/static/2006/frontComponents.gif diff --git a/retro/static/2006/frontNews.gif b/retro/static/2006/frontNews.gif Binary files differnew file mode 100644 index 00000000..6c2f35d0 --- /dev/null +++ b/retro/static/2006/frontNews.gif diff --git a/retro/static/2006/logoTop.png b/retro/static/2006/logoTop.png Binary files differnew file mode 100644 index 00000000..e96cabc9 --- /dev/null +++ b/retro/static/2006/logoTop.png diff --git a/retro/static/2006/pad.gif b/retro/static/2006/pad.gif Binary files differnew file mode 100644 index 00000000..7761b868 --- /dev/null +++ b/retro/static/2006/pad.gif diff --git a/retro/static/2006/x-click-butcc-donate.gif b/retro/static/2006/x-click-butcc-donate.gif Binary files differnew file mode 100644 index 00000000..046f3788 --- /dev/null +++ b/retro/static/2006/x-click-butcc-donate.gif diff --git a/retro/static/2007/arch.css b/retro/static/2007/arch.css new file mode 100644 index 00000000..3aa504e2 --- /dev/null +++ b/retro/static/2007/arch.css @@ -0,0 +1,372 @@ +* { margin: 0; padding: 0; } +* ul { padding: 20px; } +body { + background: url("title_back.png") repeat-x top left #fbf8f1; + padding: 0 30px; + color: #46494d; + font-family: Bitstream Vera Sans, Lucinda Grande, Arial, sans-serif; +} +/* + * Divs + */ +#head_container { + height: 175px; +} +#main_nav ul { + list-style: none; + padding-right: 10px; + padding-top: 48px; +} +#main_nav ul li { + display: block; + float: right; + width: 67px; + height: 20px; + padding-top: 2px; + margin-left: 3px; + background: url("tab.png") repeat-x bottom left #fbf8f1; + text-align: center; + font-size: 13px; +} +#main_nav ul li[class~=selected] { + background: #fbf8f1; +} +#main_nav ul li a { + text-decoration: none; +} +#dev_nav ul { + list-style: none; + padding-right: 10px; + padding-top: 5px; +} +#dev_nav ul li { + display: block; + float: right; + width: 87px; + height: 20px; + padding-top: 2px; + margin-left: 3px; + background: url("tab.png") repeat-x bottom left #fbf8f1; + border: 1px solid #cccccc; + text-align: center; + font-size: 13px; +} +#dev_nav ul li[class~=selected] { + background: #fbf8f1; +} +#dev_nav ul li a { + text-decoration: none; +} +#title { + height: 140px; + float: left; +} +#updates { + font-size: small; + /*position: relative;*/ + top: 0px; + background: #f6efe0; + border: 1px solid #eee4cb; + padding: 10px; +} +#ads { + float: right; +} +#logo { + float: left; + width: 140px; + height: 140px; +} +#devlist { + width: 80%; + padding: 10px; + margin-left: auto; + margin-right: auto; + border-top: 1px dashed black; + border-bottom: 1px dashed black; + text-align: center; +} +.clear { + clear: both; + margin: 0; + padding: 0; +} +.right { + float: right; + width: 320px; + padding: 0 10px 10px 0; +} +.left { + padding: 10px; + margin: 0 360px 0 0; +} +.left p { + text-align: justify; + padding-bottom: 10px; +} +.box { + padding: 10px; + background: #e1e3e6; + border: 1px solid #8faecd; +} +.greybox { + padding: 10px; + background: #f6efe0; + border: 1px solid #eee4cb; +} +div.listing { + padding-right: 10px; + border-left: 1px solid #387cbf; +} +.error { + color: #dd0000; + font-size: small; +} +.foot { + clear: both; + text-align: center; + font-size: 0.8em; +} +#search { + float: right; + position: relative; + top: -2em; + font-size: 0.8em; +} +#search input { + background: #f6efe0; + border: 1px solid #eee4cb; +} +.smalltext { + text-align: right; + font-size: x-small; +} +/* + * Headers + */ +h2 { + margin: 20px 0 10px 0; +} +h2.title { + border-bottom: 1px solid #46494d; +} +h3 { + margin-bottom: 10px; +} +h3.title { + text-align: right; + border-bottom: 1px solid #46494d; +} +h4.title { + text-align: left; + border-bottom: 1px solid #46494d; +} +h4.news { + border-bottom: 1px dotted #8faecd; +} +div.listing h4 { + background: #d1d3d6; + border-top: 1px double #387cbf; + padding: 3px; +} +/* + * Paragraphs, Anchors, Images + */ +p { + padding-bottom: 20px; +} +p.news { + text-align: left; + font-size: small; +} +a { + color: #35526f; + font-weight: bold; + text-decoration: underline; +} +.news a { + text-decoration: none; +} +#about { + position: relative; + top: -9px; +} +#about a { + text-decoration: none; +} +.community a { + text-decoration: none; +} +ol { + padding-left: 45px; +} +ul.small { + list-style: none; + font-size: x-small; +} +ul.links { + list-style: none; + font-size: small; + padding: 0px 0px 20px 20px; +} +img { + border: none; +} +hr { + border: none; + border-top: 1px solid #46494d; +} +.greybox input, button, textarea, select { + background: #e1e3e6; + border: 1px solid #8faecd; +} +.box input, button { + padding: 2px; + background: #c1c3f6; + font-size: x-small; + border: 1px solid #8faecd; +} +button#f_trigger { + background: #e1e3e6; +} +/* + * Table stuff + */ +table.center { + margin-left: auto; + margin-right: auto; +} +table#releases { + font-size: small; + width: 100%; +} +table#releases td { + padding-right: 20px; +} +table#repolinks { + font-size: small; + width: 100%; +} +table#repolinks td { + text-align: right; +} +table#repolinks th { + text-align: left; +} +table#art { + text-align: center; + margin-left: auto; + margin-right: auto; +} +.devpic { + vertical-align: top; + padding-right: 15px; +} +table.deventry { + padding-bottom: 25px; +} +.deventry th { + text-align: left; + vertical-align: top; + white-space: nowrap; +} +.deventry td { + border-bottom: 1px solid black; + width: 100%; +} +table.results { + padding: 0px; + border-collapse: collapse; +} +.results th { + background: #e1e3e6; + border-bottom: 1px solid #46494d; + border-top: 1px solid #46494d; + text-align: left; + padding-top: 0px; + padding-bottom: 0px; + padding-right: 5px; +} +.results th>a { + text-decoration: none; + color: #46494d; +} +.results td { + padding-right: 5px; + vertical-align: top; + font-size: 0.8em; +} +.listing th { + background: #d1d3d6; + border-left: 1px solid #387cbf; + font-size: small; + vertical-align: top; + text-align: left; + padding: 2px; +} +.listing td { + font-size: small; + padding: 2px; +} +blockquote.code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: Courier, Courier New, Monospace; +} +/* + * Wiki Styles + */ +h1.wiki { + border-bottom: 1px solid #46494d; +} +div.wikifoot_l { + font-size: x-small; + text-align: left; + padding-top: 25px; +} +div.wikifoot_r { + font-size: x-small; + text-align: right; + float: right; + padding-top: 25px; +} +.wikibody { + padding-top: 15px; +} +.wikibody ol { + padding-left: 28px; + padding-top: 0px; +} +.wikibody ul { + padding-left: 25px; + padding-top: 0px; +} +.wikibody dd { + padding-left: 30px; +} +.wikibody pre code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: Courier, Courier New, Monospace; +} +.wikibody blockquote { + padding-left: 30px; +} +.wikibody td { + padding: 5px; + border: 1px solid black; +} + +/* Used by Django's FormWrappers */ +textarea.vLargeTextField { + width: 450px; + height: 250px; +} diff --git a/retro/static/2007/button.png b/retro/static/2007/button.png Binary files differnew file mode 100644 index 00000000..670d69c6 --- /dev/null +++ b/retro/static/2007/button.png diff --git a/retro/static/2007/favicon.ico b/retro/static/2007/favicon.ico Binary files differnew file mode 100644 index 00000000..e4d5d086 --- /dev/null +++ b/retro/static/2007/favicon.ico diff --git a/retro/static/2007/logo.png b/retro/static/2007/logo.png Binary files differnew file mode 100644 index 00000000..44968cd1 --- /dev/null +++ b/retro/static/2007/logo.png diff --git a/media/rss.png b/retro/static/2007/rss.png Binary files differindex c9164592..c9164592 100644 --- a/media/rss.png +++ b/retro/static/2007/rss.png diff --git a/retro/static/2007/tab.png b/retro/static/2007/tab.png Binary files differnew file mode 100644 index 00000000..56d2e617 --- /dev/null +++ b/retro/static/2007/tab.png diff --git a/retro/static/2007/title.png b/retro/static/2007/title.png Binary files differnew file mode 100644 index 00000000..e16971a1 --- /dev/null +++ b/retro/static/2007/title.png diff --git a/retro/static/2007/title_back.png b/retro/static/2007/title_back.png Binary files differnew file mode 100644 index 00000000..95c98d7a --- /dev/null +++ b/retro/static/2007/title_back.png diff --git a/retro/static/2008/arch.css b/retro/static/2008/arch.css new file mode 100644 index 00000000..0b6acafc --- /dev/null +++ b/retro/static/2008/arch.css @@ -0,0 +1,372 @@ +* { margin: 0; padding: 0; } +* ul { padding: 20px; } +body { + background: url("title_back.png") repeat-x top left #fbf8f1; + padding: 0 30px; + color: #46494d; + font-family: Bitstream Vera Sans, Lucida Grande, Arial, sans-serif; +} +/* + * Divs + */ +#head_container { + height: 175px; +} +#main_nav ul { + list-style: none; + padding-right: 10px; + padding-top: 48px; +} +#main_nav ul li { + display: block; + float: right; + width: 67px; + height: 20px; + padding-top: 2px; + margin-left: 3px; + background: url("tab.png") repeat-x bottom left #fbf8f1; + text-align: center; + font-size: 13px; +} +#main_nav ul li[class~=selected] { + background: #fbf8f1; +} +#main_nav ul li a { + text-decoration: none; +} +#dev_nav ul { + list-style: none; + padding-right: 10px; + padding-top: 5px; +} +#dev_nav ul li { + display: block; + float: right; + width: 87px; + height: 20px; + padding-top: 2px; + margin-left: 3px; + background: url("tab.png") repeat-x bottom left #fbf8f1; + border: 1px solid #cccccc; + text-align: center; + font-size: 13px; +} +#dev_nav ul li[class~=selected] { + background: #fbf8f1; +} +#dev_nav ul li a { + text-decoration: none; +} +#title { + height: 140px; + float: left; +} +#updates { + font-size: small; + /*position: relative;*/ + top: 0px; + background: #f6efe0; + border: 1px solid #eee4cb; + padding: 10px; +} +#ads { + float: right; +} +#logo { + float: left; + width: 140px; + height: 140px; +} +#devlist { + width: 80%; + padding: 10px; + margin-left: auto; + margin-right: auto; + border-top: 1px dashed black; + border-bottom: 1px dashed black; + text-align: center; +} +.clear { + clear: both; + margin: 0; + padding: 0; +} +.right { + float: right; + width: 320px; + padding: 0 10px 10px 0; +} +.left { + padding: 10px; + margin: 0 360px 0 0; +} +.left p { + text-align: justify; + padding-bottom: 10px; +} +.box { + padding: 10px; + background: #e1e3e6; + border: 1px solid #8faecd; +} +.greybox { + padding: 10px; + background: #f6efe0; + border: 1px solid #eee4cb; +} +div.listing { + padding-right: 10px; + border-left: 1px solid #387cbf; +} +.error { + color: #dd0000; + font-size: small; +} +.foot { + clear: both; + text-align: center; + font-size: 0.8em; +} +#search { + float: right; + position: relative; + top: -2em; + font-size: 0.8em; +} +#search input { + background: #f6efe0; + border: 1px solid #eee4cb; +} +.smalltext { + text-align: right; + font-size: x-small; +} +/* + * Headers + */ +h2 { + margin: 20px 0 10px 0; +} +h2.title { + border-bottom: 1px solid #46494d; +} +h3 { + margin-bottom: 10px; +} +h3.title { + text-align: right; + border-bottom: 1px solid #46494d; +} +h4.title { + text-align: left; + border-bottom: 1px solid #46494d; +} +h4.news { + border-bottom: 1px dotted #8faecd; +} +div.listing h4 { + background: #d1d3d6; + border-top: 1px double #387cbf; + padding: 3px; +} +/* + * Paragraphs, Anchors, Images + */ +p { + padding-bottom: 20px; +} +p.news { + text-align: left; + font-size: small; +} +a { + color: #35526f; + font-weight: bold; + text-decoration: underline; +} +.news a { + text-decoration: none; +} +#about { + position: relative; + top: -9px; +} +#about a { + text-decoration: none; +} +.community a { + text-decoration: none; +} +ol { + padding-left: 45px; +} +ul.small { + list-style: none; + font-size: x-small; +} +ul.links { + list-style: none; + font-size: small; + padding: 0px 0px 20px 20px; +} +img { + border: none; +} +hr { + border: none; + border-top: 1px solid #46494d; +} +.greybox input, button, textarea, select { + background: #e1e3e6; + border: 1px solid #8faecd; +} +.box input, button { + padding: 2px; + background: #c1c3f6; + font-size: x-small; + border: 1px solid #8faecd; +} +button#f_trigger { + background: #e1e3e6; +} +/* + * Table stuff + */ +table.center { + margin-left: auto; + margin-right: auto; +} +table#releases { + font-size: small; + width: 100%; +} +table#releases td { + padding-right: 20px; +} +table#repolinks { + font-size: small; + width: 100%; +} +table#repolinks td { + text-align: right; +} +table#repolinks th { + text-align: left; +} +table#art { + text-align: center; + margin-left: auto; + margin-right: auto; +} +.devpic { + vertical-align: top; + padding-right: 15px; +} +table.deventry { + padding-bottom: 25px; +} +.deventry th { + text-align: left; + vertical-align: top; + white-space: nowrap; +} +.deventry td { + border-bottom: 1px solid black; + width: 100%; +} +table.results { + padding: 0px; + border-collapse: collapse; +} +.results th { + background: #e1e3e6; + border-bottom: 1px solid #46494d; + border-top: 1px solid #46494d; + text-align: left; + padding-top: 0px; + padding-bottom: 0px; + padding-right: 5px; +} +.results th>a { + text-decoration: none; + color: #46494d; +} +.results td { + padding-right: 5px; + vertical-align: top; + font-size: 0.8em; +} +.listing th { + background: #d1d3d6; + border-left: 1px solid #387cbf; + font-size: small; + vertical-align: top; + text-align: left; + padding: 2px; +} +.listing td { + font-size: small; + padding: 2px; +} +blockquote.code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: Courier, Courier New, Monospace; +} +/* + * Wiki Styles + */ +h1.wiki { + border-bottom: 1px solid #46494d; +} +div.wikifoot_l { + font-size: x-small; + text-align: left; + padding-top: 25px; +} +div.wikifoot_r { + font-size: x-small; + text-align: right; + float: right; + padding-top: 25px; +} +.wikibody { + padding-top: 15px; +} +.wikibody ol { + padding-left: 28px; + padding-top: 0px; +} +.wikibody ul { + padding-left: 25px; + padding-top: 0px; +} +.wikibody dd { + padding-left: 30px; +} +.wikibody pre code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: Courier, Courier New, Monospace; +} +.wikibody blockquote { + padding-left: 30px; +} +.wikibody td { + padding: 5px; + border: 1px solid black; +} + +/* Used by Django's FormWrappers */ +textarea.vLargeTextField { + width: 450px; + height: 250px; +} diff --git a/retro/static/2008/favicon.ico b/retro/static/2008/favicon.ico Binary files differnew file mode 100644 index 00000000..3a6d2ab9 --- /dev/null +++ b/retro/static/2008/favicon.ico diff --git a/retro/static/2008/logo.png b/retro/static/2008/logo.png Binary files differnew file mode 100644 index 00000000..44968cd1 --- /dev/null +++ b/retro/static/2008/logo.png diff --git a/retro/static/2008/rss.png b/retro/static/2008/rss.png Binary files differnew file mode 100644 index 00000000..c9164592 --- /dev/null +++ b/retro/static/2008/rss.png diff --git a/retro/static/2008/tab.png b/retro/static/2008/tab.png Binary files differnew file mode 100644 index 00000000..56d2e617 --- /dev/null +++ b/retro/static/2008/tab.png diff --git a/retro/static/2008/title.png b/retro/static/2008/title.png Binary files differnew file mode 100644 index 00000000..e16971a1 --- /dev/null +++ b/retro/static/2008/title.png diff --git a/retro/static/2008/title_back.png b/retro/static/2008/title_back.png Binary files differnew file mode 100644 index 00000000..95c98d7a --- /dev/null +++ b/retro/static/2008/title_back.png diff --git a/retro/static/2009/arch.css b/retro/static/2009/arch.css new file mode 100644 index 00000000..8d1cd301 --- /dev/null +++ b/retro/static/2009/arch.css @@ -0,0 +1,412 @@ +* { margin: 0; padding: 0; } +* ul { padding: 10px 20px; } +body { + min-width: 600px; + background: url("titlebar.png") repeat-x top left #fff; + padding: 0 30px; + color: #46494d; + font-size: 14px; + font-family: "DejaVu Sans", "Bitstream Vera Sans", "Lucida Grande", Arial, sans-serif; +} +/* + * Divs + */ +#head_container { + height: 220px; +} +#main_nav { + position: absolute; + top: 123px; + right: 30px; + width: 600px; + background: #333; +} +#dev_nav { + position: absolute; + top: 149px; + right: 30px; + width: 600px; + background: #1793d1; +} +#main_nav ul, #dev_nav ul { + list-style: none; + margin: 0; + padding: 0; +} +#main_nav ul li, #dev_nav ul li { + display: block; + float: right; + margin: 0 3px; + padding: 0; + text-align: center; + font-size: 13px; + line-height: 26px; +} +#main_nav ul li.selected { + background: #1793d1; +} +#dev_nav ul li.selected { + background: #333; +} +#main_nav ul li a, #dev_nav ul li a { + display: block; + padding: 0 8px; + color: #fff; + font-weight: bold; + text-decoration: none; +} +#main_nav ul li a:hover { + background: #1793d1; +} +#updates { + font-size: small; + /*position: relative;*/ + top: 0px; + background: #f6efe0; + border: 1px solid #eee4cb; + padding: 10px; +} +#updates a.testing { + font-style: italic; +} +#ads { + z-index: 0; + position: absolute; + top: 40px; + right: 10px; +} +#logo { + z-index: 1; + position: absolute; + top: 10px; + left: 25px; + width: 350px; +} +#logo h1#archtitle { + text-indent: -9999px; + margin: 0; + padding: 0; +} +#logo h1#archtitle a { + display: block; + background: transparent url("titlelogo.png") top left no-repeat; + width: 350px; + height: 103px; +} +#devlist { + width: 80%; + padding: 10px; + margin-left: auto; + margin-right: auto; + border-top: 1px dashed black; + border-bottom: 1px dashed black; + text-align: center; +} +.clear { + clear: both; + margin: 0; + padding: 0; +} +.right { + float: right; + width: 320px; + padding: 0 10px 10px 0; +} +.left { + padding: 10px; + margin: 0 360px 0 0; +} +.left p { + padding-bottom: 10px; +} +.box { + padding: 10px; + background: #f0f0f0; + border: 1px solid #d9d9d9; +} +.greybox { + padding: 10px; + background: #f6efe0; + border: 1px solid #eee4cb; +} +div.listing { + padding-right: 10px; +} +.error, .errorlist { + color: #dd0000; + font-size: small; +} +.foot { + clear: both; + padding: 2em 0; + text-align: center; + font-size: 0.75em; + line-height: 1.5em; +} +#search { + float: right; + position: relative; + top: -2em; + font-size: 0.8em; +} +#search input { + background: #f6efe0; + border: 1px solid #eee4cb; +} +.smalltext { + text-align: right; + font-size: x-small; +} +/* + * Headers + */ +h2 { + margin: 20px 0 10px 0; +} +h2.title { + border-bottom: 1px solid #46494d; +} +h3 { + margin-bottom: 10px; +} +h3.title { + text-align: right; + border-bottom: 1px solid #46494d; +} +h4.title { + text-align: left; + border-bottom: 1px solid #46494d; +} +h4.news { + border-bottom: 1px dotted #0771a6; + margin-bottom: .25em; + padding-bottom: .2em; +} +div.listing h4 { + color: #fff; + background: #0771a6; + padding: 3px; +} +/* + * Paragraphs, Anchors, Images + */ +p { + padding-bottom: 20px; +} +p.news { + font-size: small; +} +a { + color: #0771a6; + text-decoration: none; +} +a:hover { + color: #333; + text-decoration: underline; +} +#about { + position: relative; + top: -9px; +} +ol { + padding-left: 45px; +} +ul.small { + list-style: none; + font-size: x-small; +} +ul.links { + list-style: none; + font-size: small; + padding: 0px 0px 20px 20px; +} +img { + border: none; +} +hr { + border: none; + border-top: 1px solid #46494d; +} +.greybox input, button, textarea, select { + background: #e1e3e6; + border: 1px solid #8faecd; +} +.box input, button { + padding: 2px; + background: #c1c3f6; + font-size: x-small; + border: 1px solid #8faecd; +} +button#f_trigger { + background: #e1e3e6; +} +/* + * Table stuff + */ +table.center { + margin-left: auto; + margin-right: auto; +} +table#releases { + font-size: small; + width: 100%; +} +table#releases td { + padding-right: 20px; +} +table#repolinks { + font-size: small; + width: 100%; +} +table#repolinks td { + text-align: right; +} +table#repolinks th { + text-align: left; +} +table#art { + text-align: center; + margin-left: auto; + margin-right: auto; +} +.devpic { + vertical-align: top; + padding-top: 10px; + padding-right: 15px; +} +table.deventry { + padding-bottom: 25px; +} +.deventry th { + text-align: left; + vertical-align: top; + white-space: nowrap; +} +.deventry td { + width: 100%; +} +table.results { + padding: 0px; + border-collapse: collapse; +} +.results th { + background: #e1e3e6; + border-bottom: 1px solid #46494d; + border-top: 1px solid #46494d; + text-align: left; + padding-top: 0px; + padding-bottom: 0px; + padding-right: 5px; +} +.results th>a { + text-decoration: none; + color: #46494d; +} +.results td { + padding-right: 5px; + vertical-align: top; + font-size: 0.8em; +} +.listing th { + font-size: small; + vertical-align: top; + text-align: left; + padding: 2px; +} +.listing td { + font-size: small; + padding: 2px; +} +blockquote.code { + background: #d0d0d0; + border: 1px solid #bbb; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, "Courier New", Monospace; +} +/* + * Wiki Styles + */ +h1.wiki { + border-bottom: 1px solid #46494d; +} +div.wikifoot_l { + font-size: x-small; + text-align: left; + padding-top: 25px; +} +div.wikifoot_r { + font-size: x-small; + text-align: right; + float: right; + padding-top: 25px; +} +.wikibody { + padding-top: 15px; +} +.wikibody ol { + padding-left: 28px; + padding-top: 0px; +} +.wikibody ul { + padding-left: 25px; + padding-top: 0px; +} +.wikibody dd { + padding-left: 30px; +} +.wikibody pre code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, "Courier New", Monospace; +} +.wikibody blockquote { + padding-left: 30px; +} +.wikibody td { + padding: 5px; + border: 1px solid black; +} + +/* Used by Django's FormWrappers */ +textarea.vLargeTextField { + width: 450px; + height: 250px; +} +.pkgr2 { + background-color: #eee4cb; +} + +/* override some calendar attributes copied from admin */ +/* CALENDARS & CLOCKS */ +.calendarbox, .clockbox { margin:5px auto; font-size:11px; width:16em; text-align:center; background:white; position:relative; } +.clockbox { width:9em; } +.calendar { margin:0; padding: 0; } +.calendar table { margin:0; padding:0; border-collapse:collapse; background:white; width:99%; } +.calendar caption, .calendarbox h2 { margin: 0; font-size:11px; text-align:center; border-top:none; } +.calendar th { font-size:10px; color:#666; padding:2px 3px; text-align:center; background:#e1e1e1 url(nav-bg.gif) 0 50% repeat-x; border-bottom:1px solid #ddd; } +.calendar td { font-size:11px; text-align: center; padding: 0; border-top:1px solid #eee; border-bottom:none; } +.calendar td.selected a { background: #C9DBED; } +.calendar td.nonday { background:#efefef; } +.calendar td.today a { background:#ffc; } +.calendar td a, .timelist a { display: block; font-weight:bold; padding:4px; text-decoration: none; color:#444; } +.calendar td a:hover, .timelist a:hover { background: #5b80b2; color:white; } +.calendar td a:active, .timelist a:active { background: #036; color:white; } +.calendarnav { font-size:10px; text-align: center; color:#ccc; margin:0; padding:1px 3px; } +.calendarnav a:link, #calendarnav a:visited, #calendarnav a:hover { color: #999; } +.calendar-shortcuts { background:white; font-size:10px; line-height:11px; border-top:1px solid #eee; padding:3px 0 4px; color:#ccc; } +.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { display:block; position:absolute; font-weight:bold; font-size:12px; background:#C9DBED url(default-bg.gif) bottom left repeat-x; padding:1px 4px 2px 4px; color:white; } +.calendarnav-previous:hover, .calendarnav-next:hover { background:#036; } +.calendarnav-previous { top:0; left:0; } +.calendarnav-next { top:0; right:0; } +.calendar-cancel { margin:0 !important; padding:0; font-size:10px; background:#e1e1e1 url(nav-bg.gif) 0 50% repeat-x; border-top:1px solid #ddd; } +.calendar-cancel a { padding:2px; color:#999; } +ul.timelist, .timelist li { list-style-type:none; margin:0; padding:0; } +.timelist a { padding:2px; } + diff --git a/retro/static/2009/default-bg.gif b/retro/static/2009/default-bg.gif Binary files differnew file mode 100644 index 00000000..003aeca5 --- /dev/null +++ b/retro/static/2009/default-bg.gif diff --git a/media/favicon.ico b/retro/static/2009/favicon.ico Binary files differindex 55497b85..55497b85 100644 --- a/media/favicon.ico +++ b/retro/static/2009/favicon.ico diff --git a/retro/static/2009/nav-bg.gif b/retro/static/2009/nav-bg.gif Binary files differnew file mode 100644 index 00000000..f8402b80 --- /dev/null +++ b/retro/static/2009/nav-bg.gif diff --git a/retro/static/2009/rss.png b/retro/static/2009/rss.png Binary files differnew file mode 100644 index 00000000..c9164592 --- /dev/null +++ b/retro/static/2009/rss.png diff --git a/media/sevenl_button.png b/retro/static/2009/sevenl_button.png Binary files differindex 93adcdf0..93adcdf0 100644 --- a/media/sevenl_button.png +++ b/retro/static/2009/sevenl_button.png diff --git a/retro/static/2009/titlebar.png b/retro/static/2009/titlebar.png Binary files differnew file mode 100644 index 00000000..4e17b609 --- /dev/null +++ b/retro/static/2009/titlebar.png diff --git a/retro/static/2009/titlelogo.png b/retro/static/2009/titlelogo.png Binary files differnew file mode 100644 index 00000000..b3da627c --- /dev/null +++ b/retro/static/2009/titlelogo.png diff --git a/retro/static/2010/arch.css b/retro/static/2010/arch.css new file mode 100644 index 00000000..8d1cd301 --- /dev/null +++ b/retro/static/2010/arch.css @@ -0,0 +1,412 @@ +* { margin: 0; padding: 0; } +* ul { padding: 10px 20px; } +body { + min-width: 600px; + background: url("titlebar.png") repeat-x top left #fff; + padding: 0 30px; + color: #46494d; + font-size: 14px; + font-family: "DejaVu Sans", "Bitstream Vera Sans", "Lucida Grande", Arial, sans-serif; +} +/* + * Divs + */ +#head_container { + height: 220px; +} +#main_nav { + position: absolute; + top: 123px; + right: 30px; + width: 600px; + background: #333; +} +#dev_nav { + position: absolute; + top: 149px; + right: 30px; + width: 600px; + background: #1793d1; +} +#main_nav ul, #dev_nav ul { + list-style: none; + margin: 0; + padding: 0; +} +#main_nav ul li, #dev_nav ul li { + display: block; + float: right; + margin: 0 3px; + padding: 0; + text-align: center; + font-size: 13px; + line-height: 26px; +} +#main_nav ul li.selected { + background: #1793d1; +} +#dev_nav ul li.selected { + background: #333; +} +#main_nav ul li a, #dev_nav ul li a { + display: block; + padding: 0 8px; + color: #fff; + font-weight: bold; + text-decoration: none; +} +#main_nav ul li a:hover { + background: #1793d1; +} +#updates { + font-size: small; + /*position: relative;*/ + top: 0px; + background: #f6efe0; + border: 1px solid #eee4cb; + padding: 10px; +} +#updates a.testing { + font-style: italic; +} +#ads { + z-index: 0; + position: absolute; + top: 40px; + right: 10px; +} +#logo { + z-index: 1; + position: absolute; + top: 10px; + left: 25px; + width: 350px; +} +#logo h1#archtitle { + text-indent: -9999px; + margin: 0; + padding: 0; +} +#logo h1#archtitle a { + display: block; + background: transparent url("titlelogo.png") top left no-repeat; + width: 350px; + height: 103px; +} +#devlist { + width: 80%; + padding: 10px; + margin-left: auto; + margin-right: auto; + border-top: 1px dashed black; + border-bottom: 1px dashed black; + text-align: center; +} +.clear { + clear: both; + margin: 0; + padding: 0; +} +.right { + float: right; + width: 320px; + padding: 0 10px 10px 0; +} +.left { + padding: 10px; + margin: 0 360px 0 0; +} +.left p { + padding-bottom: 10px; +} +.box { + padding: 10px; + background: #f0f0f0; + border: 1px solid #d9d9d9; +} +.greybox { + padding: 10px; + background: #f6efe0; + border: 1px solid #eee4cb; +} +div.listing { + padding-right: 10px; +} +.error, .errorlist { + color: #dd0000; + font-size: small; +} +.foot { + clear: both; + padding: 2em 0; + text-align: center; + font-size: 0.75em; + line-height: 1.5em; +} +#search { + float: right; + position: relative; + top: -2em; + font-size: 0.8em; +} +#search input { + background: #f6efe0; + border: 1px solid #eee4cb; +} +.smalltext { + text-align: right; + font-size: x-small; +} +/* + * Headers + */ +h2 { + margin: 20px 0 10px 0; +} +h2.title { + border-bottom: 1px solid #46494d; +} +h3 { + margin-bottom: 10px; +} +h3.title { + text-align: right; + border-bottom: 1px solid #46494d; +} +h4.title { + text-align: left; + border-bottom: 1px solid #46494d; +} +h4.news { + border-bottom: 1px dotted #0771a6; + margin-bottom: .25em; + padding-bottom: .2em; +} +div.listing h4 { + color: #fff; + background: #0771a6; + padding: 3px; +} +/* + * Paragraphs, Anchors, Images + */ +p { + padding-bottom: 20px; +} +p.news { + font-size: small; +} +a { + color: #0771a6; + text-decoration: none; +} +a:hover { + color: #333; + text-decoration: underline; +} +#about { + position: relative; + top: -9px; +} +ol { + padding-left: 45px; +} +ul.small { + list-style: none; + font-size: x-small; +} +ul.links { + list-style: none; + font-size: small; + padding: 0px 0px 20px 20px; +} +img { + border: none; +} +hr { + border: none; + border-top: 1px solid #46494d; +} +.greybox input, button, textarea, select { + background: #e1e3e6; + border: 1px solid #8faecd; +} +.box input, button { + padding: 2px; + background: #c1c3f6; + font-size: x-small; + border: 1px solid #8faecd; +} +button#f_trigger { + background: #e1e3e6; +} +/* + * Table stuff + */ +table.center { + margin-left: auto; + margin-right: auto; +} +table#releases { + font-size: small; + width: 100%; +} +table#releases td { + padding-right: 20px; +} +table#repolinks { + font-size: small; + width: 100%; +} +table#repolinks td { + text-align: right; +} +table#repolinks th { + text-align: left; +} +table#art { + text-align: center; + margin-left: auto; + margin-right: auto; +} +.devpic { + vertical-align: top; + padding-top: 10px; + padding-right: 15px; +} +table.deventry { + padding-bottom: 25px; +} +.deventry th { + text-align: left; + vertical-align: top; + white-space: nowrap; +} +.deventry td { + width: 100%; +} +table.results { + padding: 0px; + border-collapse: collapse; +} +.results th { + background: #e1e3e6; + border-bottom: 1px solid #46494d; + border-top: 1px solid #46494d; + text-align: left; + padding-top: 0px; + padding-bottom: 0px; + padding-right: 5px; +} +.results th>a { + text-decoration: none; + color: #46494d; +} +.results td { + padding-right: 5px; + vertical-align: top; + font-size: 0.8em; +} +.listing th { + font-size: small; + vertical-align: top; + text-align: left; + padding: 2px; +} +.listing td { + font-size: small; + padding: 2px; +} +blockquote.code { + background: #d0d0d0; + border: 1px solid #bbb; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, "Courier New", Monospace; +} +/* + * Wiki Styles + */ +h1.wiki { + border-bottom: 1px solid #46494d; +} +div.wikifoot_l { + font-size: x-small; + text-align: left; + padding-top: 25px; +} +div.wikifoot_r { + font-size: x-small; + text-align: right; + float: right; + padding-top: 25px; +} +.wikibody { + padding-top: 15px; +} +.wikibody ol { + padding-left: 28px; + padding-top: 0px; +} +.wikibody ul { + padding-left: 25px; + padding-top: 0px; +} +.wikibody dd { + padding-left: 30px; +} +.wikibody pre code { + background: #c1c3f6; + border: 1px solid #8faecd; + margin-left: auto; + margin-right: auto; + white-space: nowrap; + padding: 5px; + font-family: "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, "Courier New", Monospace; +} +.wikibody blockquote { + padding-left: 30px; +} +.wikibody td { + padding: 5px; + border: 1px solid black; +} + +/* Used by Django's FormWrappers */ +textarea.vLargeTextField { + width: 450px; + height: 250px; +} +.pkgr2 { + background-color: #eee4cb; +} + +/* override some calendar attributes copied from admin */ +/* CALENDARS & CLOCKS */ +.calendarbox, .clockbox { margin:5px auto; font-size:11px; width:16em; text-align:center; background:white; position:relative; } +.clockbox { width:9em; } +.calendar { margin:0; padding: 0; } +.calendar table { margin:0; padding:0; border-collapse:collapse; background:white; width:99%; } +.calendar caption, .calendarbox h2 { margin: 0; font-size:11px; text-align:center; border-top:none; } +.calendar th { font-size:10px; color:#666; padding:2px 3px; text-align:center; background:#e1e1e1 url(nav-bg.gif) 0 50% repeat-x; border-bottom:1px solid #ddd; } +.calendar td { font-size:11px; text-align: center; padding: 0; border-top:1px solid #eee; border-bottom:none; } +.calendar td.selected a { background: #C9DBED; } +.calendar td.nonday { background:#efefef; } +.calendar td.today a { background:#ffc; } +.calendar td a, .timelist a { display: block; font-weight:bold; padding:4px; text-decoration: none; color:#444; } +.calendar td a:hover, .timelist a:hover { background: #5b80b2; color:white; } +.calendar td a:active, .timelist a:active { background: #036; color:white; } +.calendarnav { font-size:10px; text-align: center; color:#ccc; margin:0; padding:1px 3px; } +.calendarnav a:link, #calendarnav a:visited, #calendarnav a:hover { color: #999; } +.calendar-shortcuts { background:white; font-size:10px; line-height:11px; border-top:1px solid #eee; padding:3px 0 4px; color:#ccc; } +.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { display:block; position:absolute; font-weight:bold; font-size:12px; background:#C9DBED url(default-bg.gif) bottom left repeat-x; padding:1px 4px 2px 4px; color:white; } +.calendarnav-previous:hover, .calendarnav-next:hover { background:#036; } +.calendarnav-previous { top:0; left:0; } +.calendarnav-next { top:0; right:0; } +.calendar-cancel { margin:0 !important; padding:0; font-size:10px; background:#e1e1e1 url(nav-bg.gif) 0 50% repeat-x; border-top:1px solid #ddd; } +.calendar-cancel a { padding:2px; color:#999; } +ul.timelist, .timelist li { list-style-type:none; margin:0; padding:0; } +.timelist a { padding:2px; } + diff --git a/retro/static/2010/default-bg.gif b/retro/static/2010/default-bg.gif Binary files differnew file mode 100644 index 00000000..003aeca5 --- /dev/null +++ b/retro/static/2010/default-bg.gif diff --git a/retro/static/2010/favicon.ico b/retro/static/2010/favicon.ico Binary files differnew file mode 100644 index 00000000..55497b85 --- /dev/null +++ b/retro/static/2010/favicon.ico diff --git a/retro/static/2010/nav-bg.gif b/retro/static/2010/nav-bg.gif Binary files differnew file mode 100644 index 00000000..f8402b80 --- /dev/null +++ b/retro/static/2010/nav-bg.gif diff --git a/retro/static/2010/rss.png b/retro/static/2010/rss.png Binary files differnew file mode 100644 index 00000000..c9164592 --- /dev/null +++ b/retro/static/2010/rss.png diff --git a/retro/static/2010/sevenl_button.png b/retro/static/2010/sevenl_button.png Binary files differnew file mode 100644 index 00000000..93adcdf0 --- /dev/null +++ b/retro/static/2010/sevenl_button.png diff --git a/retro/static/2010/titlebar.png b/retro/static/2010/titlebar.png Binary files differnew file mode 100644 index 00000000..4e17b609 --- /dev/null +++ b/retro/static/2010/titlebar.png diff --git a/retro/static/2010/titlelogo.png b/retro/static/2010/titlelogo.png Binary files differnew file mode 100644 index 00000000..b3da627c --- /dev/null +++ b/retro/static/2010/titlelogo.png diff --git a/media/vnet_button.png b/retro/static/2010/vnet_button.png Binary files differindex 22cfa9e4..22cfa9e4 100644 --- a/media/vnet_button.png +++ b/retro/static/2010/vnet_button.png diff --git a/retro/static/2011/airvm_button.png b/retro/static/2011/airvm_button.png Binary files differnew file mode 100644 index 00000000..0acadc9c --- /dev/null +++ b/retro/static/2011/airvm_button.png diff --git a/media/archnavbar/archlogo.gif b/retro/static/2011/archlogo.gif Binary files differindex e1852a06..e1852a06 100644 --- a/media/archnavbar/archlogo.gif +++ b/retro/static/2011/archlogo.gif diff --git a/media/archnavbar/archlogo.png b/retro/static/2011/archlogo.png Binary files differindex e873e94b..e873e94b 100644 --- a/media/archnavbar/archlogo.png +++ b/retro/static/2011/archlogo.png diff --git a/media/archnavbar/archnavbar.css b/retro/static/2011/archnavbar.css index d95832bc..d95832bc 100644 --- a/media/archnavbar/archnavbar.css +++ b/retro/static/2011/archnavbar.css diff --git a/retro/static/2011/archweb-print.css b/retro/static/2011/archweb-print.css new file mode 100644 index 00000000..079dfd2e --- /dev/null +++ b/retro/static/2011/archweb-print.css @@ -0,0 +1,24 @@ + + + + + +/* + FILE ARCHIVED ON 3:57:32 Feb 12, 2011 AND RETRIEVED FROM THE + INTERNET ARCHIVE ON 20:20:44 Feb 2, 2012. + JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE. + + ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C. + SECTION 108(a)(3)). +*/ +/* + * ARCH LINUX DJANGO (MAIN SITE) + * + * Stylesheet for printing + */ + +/* general styling */ +body { font: normal 100% sans-serif; } +#content { font-size: 0.812em; } +#archnavbarmenu, #archdev-navbar, .admin-actions { display: none; } + diff --git a/media/archweb.css b/retro/static/2011/archweb.css index 040746bd..d82f416b 100644 --- a/media/archweb.css +++ b/retro/static/2011/archweb.css @@ -1,16 +1,5 @@ -/* - * ARCH LINUX DJANGO (MAIN SITE) - * - * Font sizing based on 16px browser defaults (use em): - * 14px = 0.875em - * 13px = 0.812em - * 12px = 0.75em - * 11px = 0.6875em - * - */ - /* import the global navbar stylesheet */ -@import url('archnavbar/archnavbar.css'); +@import url('archnavbar.css'); /* simple reset */ * { margin: 0; padding: 0; line-height: 1.4; } @@ -124,7 +113,7 @@ ul.errorlist { color: red; } #pkg-updates table { margin: 0; } #pkg-updates td.pkg-name { white-space: normal; } #pkg-updates td.pkg-arch { text-align: right; } -#pkg-updates span.testing, #pkg-updates span.community-testing { font-style: italic; } +#pkg-updates span.testing, #pkg-updates span.community-testing, span.multilib-testing { font-style: italic; } /* home: sidebar navigation */ div#nav-sidebar ul { list-style: none; margin: 0.5em 0 0.5em 1em; padding: 0; } @@ -212,6 +201,8 @@ form#flag-pkg-form textarea, form#flag-pkg-form input[type=text] { width: 45%; } #pkgdetails #metadata h3 { background: #555; color: #fff; font-size: 1em; margin-bottom: 0.5em; padding: 0.2em 0.35em; } #pkgdetails #metadata ul { list-style: none; margin: 0; padding: 0; } #pkgdetails #metadata li { padding-left: 0.5em; } +#pkgdetails #metadata p { padding-left: 0.5em; } +#pkgdetails #metadata .message { font-style: italic; } #pkgdetails #metadata br { clear: both; } #pkgdetails #pkgdeps { float: left; width: 48%; margin-right: 2%; } #pkgdetails #pkgreqs { float: left; width: 50%; } diff --git a/media/asc.gif b/retro/static/2011/asc.gif Binary files differindex 74157867..74157867 100644 --- a/media/asc.gif +++ b/retro/static/2011/asc.gif diff --git a/media/desc.gif b/retro/static/2011/desc.gif Binary files differindex 3b30b3c5..3b30b3c5 100644 --- a/media/desc.gif +++ b/retro/static/2011/desc.gif diff --git a/retro/static/2011/favicon.ico b/retro/static/2011/favicon.ico Binary files differnew file mode 100644 index 00000000..55497b85 --- /dev/null +++ b/retro/static/2011/favicon.ico diff --git a/media/nosort.gif b/retro/static/2011/nosort.gif Binary files differindex fac668fc..fac668fc 100644 --- a/media/nosort.gif +++ b/retro/static/2011/nosort.gif diff --git a/retro/static/2011/rss.png b/retro/static/2011/rss.png Binary files differnew file mode 100644 index 00000000..c9164592 --- /dev/null +++ b/retro/static/2011/rss.png diff --git a/retro/static/2011/sevenl_button.png b/retro/static/2011/sevenl_button.png Binary files differnew file mode 100644 index 00000000..93adcdf0 --- /dev/null +++ b/retro/static/2011/sevenl_button.png diff --git a/retro/static/2011/vnet_button.png b/retro/static/2011/vnet_button.png Binary files differnew file mode 100644 index 00000000..22cfa9e4 --- /dev/null +++ b/retro/static/2011/vnet_button.png diff --git a/retro/static/2012/CP_EN_BK_S_001.gif b/retro/static/2012/CP_EN_BK_S_001.gif Binary files differnew file mode 100644 index 00000000..41cf0885 --- /dev/null +++ b/retro/static/2012/CP_EN_BK_S_001.gif diff --git a/retro/static/2012/airvm_button.png b/retro/static/2012/airvm_button.png Binary files differnew file mode 100644 index 00000000..0acadc9c --- /dev/null +++ b/retro/static/2012/airvm_button.png diff --git a/retro/static/2012/archlogo.gif b/retro/static/2012/archlogo.gif Binary files differnew file mode 100644 index 00000000..e1852a06 --- /dev/null +++ b/retro/static/2012/archlogo.gif diff --git a/retro/static/2012/archlogo.png b/retro/static/2012/archlogo.png Binary files differnew file mode 100644 index 00000000..e873e94b --- /dev/null +++ b/retro/static/2012/archlogo.png diff --git a/retro/static/2012/archnavbar.css b/retro/static/2012/archnavbar.css new file mode 100644 index 00000000..d95832bc --- /dev/null +++ b/retro/static/2012/archnavbar.css @@ -0,0 +1,33 @@ +/* + * ARCH GLOBAL NAVBAR + * + * We're forcing all generic selectors with !important + * to help prevent other stylesheets from interfering. + * + */ + +/* container for the entire bar */ +#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } + +/* logo trickery -- GIF for IE6 and PNG for the rest */ +#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; } +/* IE6 doesn't support alpha PNGs so we serve it a GIF */ +#archnavbarlogo { background: url('archlogo.gif') no-repeat !important; } +/* and use a proper PNG for all other modern browsers */ +html > body #archnavbarlogo { background: url('archlogo.png') no-repeat !important; } + +/* move the heading/paragraph text offscreen */ +#archnavbarlogo p { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } +#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } + +/* make the link the same size as the logo */ +#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } + +/* display the list inline, float it to the right and style it */ +#archnavbar ul { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } +#archnavbar ul li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } + +/* style the links */ +#archnavbar ul#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } +#archnavbar ul li a:hover { color: white !important; text-decoration: underline !important; } + diff --git a/retro/static/2012/archweb-print.css b/retro/static/2012/archweb-print.css new file mode 100644 index 00000000..95c2a532 --- /dev/null +++ b/retro/static/2012/archweb-print.css @@ -0,0 +1,24 @@ + + + + + +/* + FILE ARCHIVED ON 16:45:26 Mar 12, 2012 AND RETRIEVED FROM THE + INTERNET ARCHIVE ON 22:32:15 Nov 11, 2013. + JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE. + + ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C. + SECTION 108(a)(3)). +*/ +/* + * ARCH LINUX DJANGO (MAIN SITE) + * + * Stylesheet for printing + */ + +/* general styling */ +body { font: normal 100% sans-serif; } +#content { font-size: 0.812em; } +#archnavbarmenu, #archdev-navbar, .admin-actions { display: none; } + diff --git a/retro/static/2012/archweb.css b/retro/static/2012/archweb.css new file mode 100644 index 00000000..b96927b6 --- /dev/null +++ b/retro/static/2012/archweb.css @@ -0,0 +1,1005 @@ +/* + * ARCH LINUX DJANGO (MAIN SITE) + * + * Font sizing based on 16px browser defaults (use em): + * 14px = 0.875em + * 13px = 0.812em + * 12px = 0.75em + * 11px = 0.6875em + * + */ + +/* import the global navbar stylesheet */ +@import url('archnavbar.css'); + +/* simple reset */ +* { + margin: 0; + padding: 0; + line-height: 1.4; +} + +/* general styling */ +body { + min-width: 650px; + background: #f6f9fc; + color: #222; + font: normal 100% sans-serif; + text-align: center; +} + +p { + margin: .33em 0 1em; +} + +ol, +ul { + margin-bottom: 1em; + padding-left: 2em; +} + + ul { + list-style: square; + } + +code { + font: 1.2em monospace; + background: #ffd; + padding: 0.15em 0.25em; +} + +pre { + font: 1.2em monospace; + border: 1px solid #bdb; + background: #dfd; + padding: 0.5em; + margin: 1em; +} + + pre code { + display: block; + background: none; + } + +blockquote { + margin: 1.5em 2em; +} + +input { + vertical-align: middle; +} + +select[multiple] { + padding: 1px 0; +} + + select[multiple] option { + padding: 0 0.5em 0 0.3em; + } + +input[type=submit] { + padding: 0 0.6em; +} + +.clear { + clear: both; +} + +hr { + border: none; + border-top: 1px solid #888; +} + +img { + border: 0; +} + +/* scale fonts down to a sane default (16 * .812 = 13px) */ +#content { + font-size: 0.812em; +} + +/* link style */ +a { + text-decoration: none; +} + + a:link, + th a:visited { + color: #07b; + } + + a:visited { + color: #666; + } + + a:hover { + text-decoration: underline; + color: #666; + } + + a:active { + color: #e90; + } + +/* headings */ +h2 { + font-size: 1.5em; + margin-bottom: 0.5em; + border-bottom: 1px solid #888; +} + +h3 { + font-size: 1.25em; + margin-top: .5em; +} + +h4 { + font-size: 1.15em; + margin-top: 1em; +} + +h5 { + font-size: 1em; + margin-top: 1em; +} + +/* general layout */ +div#content { + width: 95%; + margin: 0 auto; + text-align: left; +} + +div#content-left-wrapper { + float: left; + width: 100%; /* req to keep content above sidebar in source code */ +} + +div#content-left { + margin: 0 340px 0 0; +} + +div#content-right { + float: left; + width: 300px; + margin-left: -300px; +} + +div.box { + margin-bottom: 1.5em; + padding: 0.65em; + background: #ecf2f5; + border: 1px solid #bcd; +} + +div#footer { + clear: both; + margin: 2em 0 1em; +} + + div#footer p { + margin: 0; + text-align: center; + font-size: 0.85em; + } + +/* alignment */ +div.center, +table.center, +img.center { + width: auto; + margin-left: auto; + margin-right: auto; +} + +p.center, +td.center, +th.center { + text-align: center; +} + +/* table generics */ +table { + width: 100%; + border-collapse: collapse; +} + + table .wrap { + white-space: normal; + } + +th, +td { + white-space: nowrap; + text-align: left; +} + + th { + vertical-align: middle; + font-weight: bold; + } + + td { + vertical-align: top; + } + +/* table pretty styles */ +table.pretty1 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bcd; +} + + table.pretty1 th { + padding: 0.35em; + background: #e4eeff; + border: 1px solid #bcd; + } + + table.pretty1 td { + padding: 0.35em; + border: 1px dotted #bcd; + } + +table.pretty2 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bbb; +} + + table.pretty2 th { + padding: 0.35em; + background: #eee; + border: 1px solid #bbb; + } + + table.pretty2 td { + padding: 0.35em; + border: 1px dotted #bbb; + } + +/* definition lists */ +dl { + clear: both; +} + + dl dt, + dl dd { + margin-bottom: 4px; + padding: 8px 0px 4px; + font-weight: bold; + border-top: 1px dotted #bbb; + } + + dl dt { + color: #333; + float:left; + padding-right:15px; + } + +/* forms and input styling */ +form p { + margin: 0.5em 0; +} + +fieldset { + border: 0; +} + +label { + width: 12em; + vertical-align: top; + display: inline-block; + font-weight: bold; +} + +input[type=text], +input[type=password], +textarea { + padding: 0.10em; +} + +form.general-form label, +form.general-form .form-help { + width: 10em; + vertical-align: top; + display: inline-block; +} + +form.general-form input[type=text], +form.general-form textarea { + width: 45%; +} + +/* archdev navbar */ +div#archdev-navbar { + margin: 1.5em 0; +} + + div#archdev-navbar ul { + list-style: none; + margin: -0.5em 0; + padding: 0; + } + + div#archdev-navbar li { + display: inline; + margin: 0; + padding: 0; + font-size: 0.9em; + } + + div#archdev-navbar li a { + padding: 0 0.5em; + color: #07b; + } + +/* error/info messages (x pkg is already flagged out-of-date, etc) */ +#sys-message { + width: 35em; + text-align: center; + margin: 1em auto; + padding: 0.5em; + background: #fff; + border: 1px solid #f00; +} + + #sys-message p { + margin: 0; + } + +ul.errorlist { + color: red; +} + +/** + * PAGE SPECIFIC STYLES + */ + +/* home: introduction */ +#intro p.readmore { + margin: -0.5em 0 0 0; + font-size: .9em; + text-align: right; +} + +/* home: news */ +#news { + margin-top: 1.5em; +} + + #news h3 { + float: left; + padding-bottom: .5em + } + + #news div { + margin-bottom: 1em; + } + + #news div p { + margin-bottom: 0.5em; + } + + #news .more { + font-weight: normal; + } + + #news .rss-icon { + float: right; + margin-top: 1em; + } + + #news h4 { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; + } + + #news .timestamp { + float: right; + font-size: 0.85em; + margin: -1.8em 0.5em 0 0; + } + +/* home: arrowed headings */ +#news h3 a { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + + #news a:active { + color: white; + } + +h3 span.arrow { + display: block; + width: 0px; + height: 0px; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #1794D1; + margin: 0 auto; + font-size: 0px; + line-height: 0px; +} + +/* home: pkgsearch box */ +#pkgsearch { + padding: 1em 0.75em; + background: #3ad; + color: #fff; + border: 1px solid #08b; +} + + #pkgsearch label { + width: auto; + padding: 0.1em 0; + } + + #pkgsearch input { + width: 10em; + float: right; + font-size: 1em; + color: #000; + background: #fff; + border: 1px solid #09c; + } + +/* home: recent pkg updates */ +#pkg-updates h3 { + margin: 0 0 0.3em; +} + + #pkg-updates .more { + font-weight: normal; + } + + #pkg-updates .rss-icon { + float: right; + margin: -2em 0 0 0; + } + + #pkg-updates table { + margin: 0; + } + + #pkg-updates td.pkg-name { + white-space: normal; + } + + #pkg-updates td.pkg-arch { + text-align: right; + } + + #pkg-updates span.testing { + font-style: italic; + } + + #pkg-updates span.staging { + font-style: italic; + color: #ff8040; + } + +/* home: sidebar navigation */ +div#nav-sidebar ul { + list-style: none; + margin: 0.5em 0 0.5em 1em; + padding: 0; +} + +/* home: sponsor banners */ +div#arch-sponsors img { + padding: 0.3em 0; +} + +/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ +div.widget { + margin-bottom: 1.5em; +} + +/* feeds page */ +#rss-feeds .rss { + padding-right: 20px; + background: url(rss.png) top right no-repeat; +} + +/* artwork: logo images */ +#artwork img.inverted { + background: #333; + padding: 0; +} + +#artwork div.imagelist img { + display: inline; + margin: 0.75em; +} + +/* news: article list */ +.news-nav { + float: right; + margin-top: -2.2em; +} + + .news-nav .prev, + .news-nav .next { + margin: 0 1em; + } + +/* news: article pages */ +div.news-article .article-info { + margin: 0; + color: #999; +} + +/* news: add/edit article */ +form#newsform { + width: 60em; +} + + form#newsform input[type=text], + form#newsform textarea { + width: 75%; + } + +/* donate: donor list */ +div#donor-list ul { + width: 100%; +} + /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ + div#donor-list li { + float: left; + width: 25%; + min-width: 20em; + } + +/* download page */ +#arch-downloads h3 { + border-bottom: 1px dotted #bbb; +} + +table#download-torrents .cpu-arch { + text-align: center; +} + +table#download-mirrors { + width: auto; + margin-bottom: 1em; +} + + table#download-mirrors td.mirror-country { + padding-top: 1em; + } + + table#download-mirrors td.mirror-server { + padding-right: 1em; + } + + table#download-mirrors a { + display: block; + float: right; + width: 4em; + } + +/* pkglists/devlists */ +table.results { + font-size: 0.846em; + border-top: 1px dotted #999; + border-bottom: 1px dotted #999; +} + + table.results th { + padding: 0.5em 1em 0.25em 0.25em; + border-bottom: 1px solid #999; + white-space: nowrap; + background-color:#fff; + } + + /* additional styles for JS sorting */ + table.results th.header { + padding-right: 20px; + background-image: url(nosort.gif); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; + } + + table.results th.headerSortDown { + background-color: #e4eeff; + background-image: url(desc.gif); + } + + table.results th.headerSortUp { + background-color: #e4eeff; + background-image: url(asc.gif); + } + + table.results td { + padding: .3em 1em .3em 3px; + } + + table.results tr.odd { + background: #fff; + } + + table.results tr.even { + background: #e4eeff; + } + + table.results .flagged { + color: red; + } + +/* pkglist: layout */ +div#pkglist-about { + margin-top: 1.5em; +} + +/* pkglist: results navigation */ +#pkglist-stats-top, +#pkglist-stats-bottom { + font-size: 0.85em; +} + +#pkglist-results .pkglist-nav { + float: right; + margin-top: -2.2em; +} + +.pkglist-nav .prev { + margin-right: 1em; +} + +.pkglist-nav .next { + margin-right: 1em; +} + +/* search fields and other filter selections */ +.filter-criteria { + margin-bottom: 1em; +} + +.filter-criteria h3 { + font-size: 1em; + margin-top: 0; +} + +.filter-criteria div { + float: left; + margin-right: 1.65em; + font-size: 0.85em; +} + +.filter-criteria legend { + display: none; +} + +.filter-criteria label { + width: auto; + display: block; + font-weight: normal; +} + +/* pkgdetails: details links that float on the right */ +#pkgdetails #detailslinks { + float: right; +} + + #pkgdetails #detailslinks h4 { + margin-top: 0; + margin-bottom: 0.25em; + } + + #pkgdetails #detailslinks ul { + list-style: none; + padding: 0; + margin-bottom: 0; + font-size: 0.846em; + } + + #pkgdetails #detailslinks > div { + padding: 0.5em; + margin-bottom: 1em; + background: #eee; + border: 1px solid #bbb; + } + +#pkgdetails #actionlist .flagged { + color: red; + font-size: 0.9em; + font-style: italic; +} + +/* pkgdetails: pkg info */ +#pkgdetails #pkginfo { + width: auto; +} + + #pkgdetails #pkginfo td { + padding: 0.25em 0 0.25em 1.5em; + } + + #pkgdetails #pkginfo .userdata { + font-size: 0.85em; + padding: 0.5em; + } + +/* pkgdetails: flag package */ +form#flag-pkg-form label { + width: 10em; +} + +form#flag-pkg-form textarea, +form#flag-pkg-form input[type=text] { + width: 45%; +} + +/* pkgdetails: deps, required by and file lists */ +#pkgdetails #metadata { + clear: both; +} + +#pkgdetails #metadata h3 { + background: #555; + color: #fff; + font-size: 1em; + margin-bottom: 0.5em; + padding: 0.2em 0.35em; +} + +#pkgdetails #metadata ul { + list-style: none; + margin: 0; + padding: 0; +} + +#pkgdetails #metadata li { + padding-left: 0.5em; +} + +#pkgdetails #metadata p { + padding-left: 0.5em; +} + +#pkgdetails #metadata .message { + font-style: italic; +} + +#pkgdetails #metadata br { + clear: both; +} + +#pkgdetails #pkgdeps { + float: left; + width: 48%; + margin-right: 2%; +} + +#pkgdetails #metadata .virtual-dep, +#pkgdetails #metadata .testing-dep, +#pkgdetails #metadata .opt-dep, +#pkgdetails #metadata .dep-desc { + font-style: italic; +} +#pkgdetails #pkgreqs { + float: left; + width: 50%; +} + +#pkgdetails #pkgfiles { + clear: left; + padding-top: 1em; +} + +/* dev/TU biographies */ +div#arch-bio-toc { + width: 75%; + margin: 0 auto; + text-align: center; +} + + div#arch-bio-toc a { + white-space: nowrap; + } + +table.arch-bio-entry td.pic { + vertical-align: top; + padding-right: 15px; + padding-top: 10px; +} + + table.arch-bio-entry td.pic img { + padding: 4px; + border: 1px solid #ccc; + } + +table.arch-bio-entry table.bio { + margin-bottom: 2em; +} + + table.arch-bio-entry table.bio th { + text-align: left; + padding-right: 0.5em; + vertical-align: top; + white-space: nowrap; + } + + table.arch-bio-entry table.bio td { + width: 100%; + padding-bottom: 0.25em; + } + +/* dev: login/out */ +table#dev-login { + width: auto; +} + +/* dev dashboard: flagged packages */ +form#dash-pkg-notify { + text-align: right; + padding: 1em 0 0; + margin-top: 1em; + font-size: 0.85em; + border-top: 1px dotted #bbb; +} + + form#dash-pkg-notify label { + width: auto; + font-weight: normal; + } + + form#dash-pkg-notify input { + vertical-align: middle; + margin: 0 0.25em; + } + + form#dash-pkg-notify input[type=submit] { + margin-top: -0.25em; + } + + form#dash-pkg-notify p { + margin: 0; + } + +table.dash-stats .key { + width: 50%; +} + +/* dev dashboard: admin actions (add news items, todo list, etc) */ +ul.admin-actions { + float: right; + list-style: none; + margin-top: -2.5em; +} + + ul.admin-actions li { + display: inline; + padding-left: 1.5em; + } + +/* todo lists (public and private) */ +.todo-table .complete { + color: green; +} + +.todo-table .incomplete { + color: red; +} +.todo-info { + margin: 0; color: #999; +} + +.todo-list h4 { + margin-top: 0; + margin-bottom: 0.4em; +} + +/* dev: signoff page */ +#dev-signoffs tr:hover { + background: #ffd; +} + +ul.signoff-list { + list-style: none; + margin: 0; + padding: 0; +} + +.signoff-yes { + color: green; + font-weight: bold; +} + +.signoff-no { + color: red; +} + +.signoff-bad { + color: darkorange; +} + +.signoff-disabled { + color: gray; +} + +/* iso testing feedback form */ +#releng-feedback label { + width: auto; + display: inline; + font-weight: normal; +} + +#releng-feedback ul { + padding-left: 1em; +} + +#releng-feedback li { + list-style: none; +} + +#releng-feedback ul+.helptext { + position: relative; top: -0.9em; +} + +#releng-result .success-yes { + color: green; +} + +#releng-result .success-no { + color: red; +} + +/* highlight current website in the navbar */ +#archnavbar.anb-home ul li#anb-home a, +#archnavbar.anb-packages ul li#anb-packages a, +#archnavbar.anb-download ul li#anb-download a { + color: white !important; +} + +/* visualizations page */ +.visualize-buttons { + margin: 0.5em 0.33em; +} + + .visualize-buttons button.active { + depressed: true; + } + +.visualize-chart { + position: relative; + height: 500px; + margin: 0.33em; +} + +#visualize-archrepo .treemap-cell { + border: solid 1px white; + overflow: hidden; + position: absolute; +} + + #visualize-archrepo .treemap-cell span { + padding: 3px; + font-size: 0.85em; + line-height: 1em; + } + +#visualize-keys svg { + width: 100%; +} + + #visualize-keys circle { + stroke-width: 1.5px; + } + + #visualize-keys line { + stroke: #888; + } diff --git a/retro/static/2012/asc.gif b/retro/static/2012/asc.gif Binary files differnew file mode 100644 index 00000000..74157867 --- /dev/null +++ b/retro/static/2012/asc.gif diff --git a/retro/static/2012/desc.gif b/retro/static/2012/desc.gif Binary files differnew file mode 100644 index 00000000..3b30b3c5 --- /dev/null +++ b/retro/static/2012/desc.gif diff --git a/media/new.png b/retro/static/2012/new.png Binary files differindex 6a9bf037..6a9bf037 100755..100644 --- a/media/new.png +++ b/retro/static/2012/new.png diff --git a/retro/static/2012/nosort.gif b/retro/static/2012/nosort.gif Binary files differnew file mode 100644 index 00000000..fac668fc --- /dev/null +++ b/retro/static/2012/nosort.gif diff --git a/retro/static/2012/rss.png b/retro/static/2012/rss.png Binary files differnew file mode 100644 index 00000000..c9164592 --- /dev/null +++ b/retro/static/2012/rss.png diff --git a/retro/static/2012/sevenl_button.png b/retro/static/2012/sevenl_button.png Binary files differnew file mode 100644 index 00000000..93adcdf0 --- /dev/null +++ b/retro/static/2012/sevenl_button.png diff --git a/retro/static/2012/vnet_button.png b/retro/static/2012/vnet_button.png Binary files differnew file mode 100644 index 00000000..22cfa9e4 --- /dev/null +++ b/retro/static/2012/vnet_button.png diff --git a/retro/static/2013/airvm_button.png b/retro/static/2013/airvm_button.png Binary files differnew file mode 100644 index 00000000..0acadc9c --- /dev/null +++ b/retro/static/2013/airvm_button.png diff --git a/retro/static/2013/apple-touch-icon-114x114.343cca8f850e.png b/retro/static/2013/apple-touch-icon-114x114.343cca8f850e.png Binary files differnew file mode 100644 index 00000000..a5b4282a --- /dev/null +++ b/retro/static/2013/apple-touch-icon-114x114.343cca8f850e.png diff --git a/retro/static/2013/apple-touch-icon-144x144.38cf584757c3.png b/retro/static/2013/apple-touch-icon-144x144.38cf584757c3.png Binary files differnew file mode 100644 index 00000000..cd177f2c --- /dev/null +++ b/retro/static/2013/apple-touch-icon-144x144.38cf584757c3.png diff --git a/retro/static/2013/apple-touch-icon-57x57.0cd0ab3349e2.png b/retro/static/2013/apple-touch-icon-57x57.0cd0ab3349e2.png Binary files differnew file mode 100644 index 00000000..d7d592c7 --- /dev/null +++ b/retro/static/2013/apple-touch-icon-57x57.0cd0ab3349e2.png diff --git a/retro/static/2013/apple-touch-icon-72x72.e502bac6368f.png b/retro/static/2013/apple-touch-icon-72x72.e502bac6368f.png Binary files differnew file mode 100644 index 00000000..5983885f --- /dev/null +++ b/retro/static/2013/apple-touch-icon-72x72.e502bac6368f.png diff --git a/retro/static/2013/archlogo.4fefb38dc270.png b/retro/static/2013/archlogo.4fefb38dc270.png Binary files differnew file mode 100644 index 00000000..e873e94b --- /dev/null +++ b/retro/static/2013/archlogo.4fefb38dc270.png diff --git a/retro/static/2013/archweb.css b/retro/static/2013/archweb.css new file mode 100644 index 00000000..22c30e76 --- /dev/null +++ b/retro/static/2013/archweb.css @@ -0,0 +1 @@ +#archnavbar{height:40px!important;padding:10px 15px!important;background:#333!important;border-bottom:5px #08c solid!important}#archnavbarlogo{float:left!important;margin:0!important;padding:0!important;height:40px!important;width:190px!important;background:url(archlogo.4fefb38dc270.png) no-repeat!important}#archnavbarlogo h1{margin:0!important;padding:0!important;text-indent:-9999px!important}#archnavbarlogo a{display:block!important;height:40px!important;width:190px!important}#archnavbarlist{display:inline!important;float:right!important;list-style:none!important;margin:0!important;padding:0!important}#archnavbarlist li{float:left!important;font-size:14px!important;font-family:sans-serif!important;line-height:45px!important;padding-right:15px!important;padding-left:15px!important}#archnavbarlist li a{color:#999;font-weight:bold!important;text-decoration:none!important}#archnavbarlist li a:hover{color:white!important;text-decoration:underline!important}*{margin:0;padding:0;line-height:1.4}body{min-width:650px;background:#f6f9fc;color:#222;font:normal 100% sans-serif;text-align:center}p{margin:.33em 0 1em}ol,ul{margin-bottom:1em;padding-left:2em}ul{list-style:square}code{font:1.2em monospace;background:#ffd;padding:.15em .25em}pre{font:1.2em monospace;border:1px solid #bdb;background:#dfd;padding:.5em;margin:1em}pre code{display:block;background:none}blockquote{margin:1.5em 2em}input{vertical-align:middle}select[multiple]{padding:1px 0}select[multiple] option{padding:0 .5em 0 .3em}input[type=submit]{padding:0 .6em}.clear{clear:both}.hide{display:none}hr{border:none;border-top:1px solid #888}img{border:0}#content{font-size:.812em}a{text-decoration:none}a:link,th a:visited{color:#07b}a:visited{color:#666}a:hover{text-decoration:underline;color:#666}a:active{color:#e90}a.headerlink{visibility:hidden;padding-left:.5em}h3:hover>a.headerlink{visibility:visible}h2{font-size:1.5em;margin-bottom:.5em;border-bottom:1px solid #888}h3{font-size:1.25em;margin-top:.5em}h4{font-size:1.15em;margin-top:1em}h5{font-size:1em;margin-top:1em}#content{width:95%;margin:0 auto;text-align:left}#content-left-wrapper{float:left;width:100%}#content-left{margin:0 340px 0 0}#content-right{float:left;width:300px;margin-left:-300px}div.box{margin-bottom:1.5em;padding:.65em;background:#ecf2f5;border:1px solid #bcd}#footer{clear:both;margin:2em 0 1em}#footer p{margin:0;text-align:center;font-size:.85em}div.center,table.center,img.center{width:auto;margin-left:auto;margin-right:auto}p.center,td.center,th.center{text-align:center}table{width:100%;border-collapse:collapse}table .wrap{white-space:normal}th,td{white-space:nowrap;text-align:left}th{vertical-align:middle;font-weight:bold}td{vertical-align:top}table.pretty1{width:auto;margin-top:.25em;margin-bottom:.5em;border-collapse:collapse;border:1px solid #bcd}.pretty1 th{padding:.35em;background:#e4eeff;border:1px solid #bcd}.pretty1 td{padding:.35em;border:1px dotted #bcd}table.pretty2{width:auto;margin-top:.25em;margin-bottom:.5em;border-collapse:collapse;border:1px solid #bbb}.pretty2 th{padding:.35em;background:#eee;border:1px solid #bbb}.pretty2 td{padding:.35em;border:1px dotted #bbb}table.compact{width:auto}.compact td{padding:.25em 0 .25em 1.5em}dl{clear:both}dl dt,dl dd{margin-bottom:4px;padding:8px 0 4px;font-weight:bold;border-top:1px dotted #bbb}dl dt{color:#333;float:left;padding-right:15px}form p{margin:.5em 0}fieldset{border:0}label{width:12em;vertical-align:top;display:inline-block;font-weight:bold}input[type=text],input[type=password],textarea{padding:.10em}form.general-form label,form.general-form .form-help{width:10em;vertical-align:top;display:inline-block}form.general-form input[type=text],form.general-form textarea{width:45%}#archdev-navbar{margin:1.5em 0}#archdev-navbar ul{list-style:none;margin:-0.5em 0;padding:0}#archdev-navbar li{display:inline;margin:0;padding:0;font-size:.9em}#archdev-navbar li a{padding:0 .5em;color:#07b}#sys-message{width:35em;text-align:center;margin:1em auto;padding:.5em;background:#fff;border:1px solid #f00}#sys-message p{margin:0}ul.errorlist{color:red}table th.tablesorter-header{padding-right:20px;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-repeat:no-repeat;background-position:center right;cursor:pointer}table thead th.tablesorter-headerAsc{background-color:#e4eeff;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7)}table thead th.tablesorter-headerDesc{background-color:#e4eeff;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}table thead th.sorter-false{background-image:url("");cursor:default}#intro p.readmore{margin:-0.5em 0 0 0;font-size:.9em;text-align:right}#news{margin-top:1.5em}#news h3{float:left;padding-bottom:.5em}#news div{margin-bottom:1em}#news div p{margin-bottom:.5em}#news .more{font-weight:normal}#news .rss-icon{float:right;margin-top:1em}#news h4{clear:both;font-size:1em;margin-top:1.5em;border-bottom:1px dotted #bbb}#news .timestamp{float:right;font-size:.85em;margin:-1.8em .5em 0 0}#news h3 a{display:block;background:#1794D1;font-size:15px;padding:2px 10px;color:white}#news a:active{color:white}h3 span.arrow{display:block;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #1794D1;margin:0 auto;font-size:0;line-height:0}#pkgsearch{padding:1em .75em;background:#3ad;color:#fff;border:1px solid #08b}#pkgsearch label{width:auto;padding:.1em 0}#pkgsearch input{width:10em;float:right;font-size:1em;color:#000;background:#fff;border:1px solid #09c}.pkgsearch-typeahead{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;padding:.15em .1em;margin:0;min-width:10em;font-size:.812em;text-align:left;list-style:none;background-color:#f6f9fc;border:1px solid #09c}.pkgsearch-typeahead li a{color:#000}.pkgsearch-typeahead li.active a{color:#07b}#pkg-updates h3{margin:0 0 .3em}#pkg-updates .more{font-weight:normal}#pkg-updates .rss-icon{float:right;margin:-2em 0 0 0}#pkg-updates table{margin:0}#pkg-updates td.pkg-name{white-space:normal}#pkg-updates td.pkg-arch{text-align:right}#pkg-updates span.testing{font-style:italic}#pkg-updates span.staging{font-style:italic;color:#ff8040}#nav-sidebar ul{list-style:none;margin:.5em 0 .5em 1em;padding:0}#arch-sponsors img{padding:.3em 0}div.widget{margin-bottom:1.5em}#konami{position:fixed;top:0;left:0;width:100%;height:100%;text-align:center;opacity:.6}#rss-feeds .rss{padding-right:20px;background:url(rss.c5ebdc5318d6.png) top right no-repeat}#artwork img.inverted{background:#333;padding:0}#artwork div.imagelist img{display:inline;margin:.75em}.news-nav{float:right;margin-top:-2.2em}.news-nav .prev,.news-nav .next{margin:0 1em}div.news-article .article-info{margin:0;color:#999}#newsform{width:60em}#newsform input[type=text],#newsform textarea{width:75%}#donor-list ul{width:100%}#donor-list li{float:left;width:25%;min-width:20em}#arch-downloads h3{border-bottom:1px dotted #bbb}table.results{font-size:.846em;border-top:1px dotted #999;border-bottom:1px dotted #999}.results th{padding:.5em 1em .25em .25em;border-bottom:1px solid #999;white-space:nowrap;background-color:#fff}.results td{padding:.3em 1em .3em 3px}.results tr.odd{background:#fff}.results tr.even{background:#e4eeff}.results .flagged{color:red}#pkglist-about{margin-top:1.5em}.pkglist-stats{font-size:.85em}#pkglist-results .pkglist-nav{float:right;margin-top:-2.2em}.pkglist-nav .prev{margin-right:1em}.pkglist-nav .next{margin-right:1em}.filter-criteria{margin-bottom:1em}.filter-criteria h3{font-size:1em;margin-top:0}.filter-criteria div{float:left;margin-right:1.65em;font-size:.85em}.filter-criteria legend{display:none}.filter-criteria label{width:auto;display:block;font-weight:normal}#pkgdetails #detailslinks{float:right}#pkgdetails #detailslinks h4{margin-top:0;margin-bottom:.25em}#pkgdetails #detailslinks ul{list-style:none;padding:0;margin-bottom:0;font-size:.846em}#pkgdetails #detailslinks>div{padding:.5em;margin-bottom:1em;background:#eee;border:1px solid #bbb}#pkgdetails #actionlist .flagged{color:red;font-size:.9em;font-style:italic}#pkgdetails #pkginfo{width:auto}#pkgdetails #pkginfo td{padding:.25em 0 .25em 1.5em}#pkgdetails #pkginfo .userdata{font-size:.85em;padding:.5em}#flag-pkg-form label{width:10em}#flag-pkg-form textarea,#flag-pkg-form input[type=text]{width:45%}#pkgdetails #metadata{clear:both}#pkgdetails #metadata h3{background:#555;color:#fff;font-size:1em;margin-bottom:.5em;padding:.2em .35em}#pkgdetails #metadata ul{list-style:none;margin:0;padding:0}#pkgdetails #metadata li{padding-left:.5em}#pkgdetails #metadata p{padding-left:.5em}#pkgdetails #metadata .message{font-style:italic}#pkgdetails #metadata br{clear:both}#pkgdetails #pkgdeps{float:left;width:48%;margin-right:2%}#pkgdetails #metadata .virtual-dep,#pkgdetails #metadata .testing-dep,#pkgdetails #metadata .staging-dep,#pkgdetails #metadata .opt-dep,#pkgdetails #metadata .make-dep,#pkgdetails #metadata .check-dep,#pkgdetails #metadata .dep-desc{font-style:italic}#pkgdetails #pkgreqs{float:left;width:50%}#pkgdetails #pkgfiles{clear:left;padding-top:1em}#pkgfilelist li.d{color:#666}#pkgfilelist li.f{}table td.country{white-space:normal}#list-generator div ul{list-style:none;display:inline;padding-left:0}#list-generator div ul li{display:inline}#visualize-mirror .axis path,#visualize-mirror .axis line{fill:none;stroke:#000;stroke-width:3px;shape-rendering:crispEdges}#visualize-mirror .url-dot{stroke:#000}#visualize-mirror .url-line{fill:none;stroke-width:1.5px}#arch-bio-toc{width:75%;margin:0 auto;text-align:center}#arch-bio-toc a{white-space:nowrap}.arch-bio-entry{width:75%;min-width:640px;margin:0 auto}.arch-bio-entry td.pic{vertical-align:top;padding-right:15px;padding-top:2.25em}.arch-bio-entry td.pic img{padding:4px;border:1px solid #ccc}.arch-bio-entry td h3{border-bottom:1px dotted #ccc;margin-bottom:.5em}.arch-bio-entry table.bio{margin-bottom:2em}.arch-bio-entry table.bio th{color:#666;font-weight:normal;text-align:right;padding-right:.5em;vertical-align:top;white-space:nowrap}.arch-bio-entry table.bio td{width:100%;padding-bottom:.25em;white-space:normal}#dev-login{width:auto}#dash-pkg-notify{text-align:right;padding:1em 0 0;margin-top:1em;font-size:.85em;border-top:1px dotted #bbb}#dash-pkg-notify label{width:auto;font-weight:normal}#dash-pkg-notify input{vertical-align:middle;margin:0 .25em}#dash-pkg-notify input[type=submit]{margin-top:-0.25em}#dash-pkg-notify p{margin:0}table.dash-stats .key{width:50%}ul.admin-actions{float:right;list-style:none;margin-top:-2.5em}ul.admin-actions li{display:inline;padding-left:1.5em}.todo-table .complete,.signoff-yes,#key-status .signed-yes,#releng-result .success-yes,#release-list .available-yes{color:green}.todo-table .incomplete,.signoff-no,#key-status .signed-no,#releng-result .success-no,#release-list .available-no{color:red}.todo-table .inprogress,.signoff-bad{color:darkorange}.todo-info{margin:0;color:#999}.todo-list h4{margin-top:0;margin-bottom:.4em}#dev-signoffs tr:hover{background:#ffd}ul.signoff-list{list-style:none;margin:0;padding:0}.signoff-yes{font-weight:bold}.signoff-disabled{color:gray}#releng-feedback label{width:auto;display:inline;font-weight:normal}#releng-feedback ul{padding-left:1em}#releng-feedback li{list-style:none}#releng-feedback ul+.helptext{position:relative;top:-0.9em}#archnavbar.anb-home ul li#anb-home a,#archnavbar.anb-packages ul li#anb-packages a,#archnavbar.anb-download ul li#anb-download a{color:white!important}.visualize-buttons{margin:.5em .33em}.visualize-buttons button.active{depressed:true}.visualize-chart{position:relative;height:500px;margin:.33em}#visualize-archrepo .treemap-cell{border:solid 1px white;overflow:hidden;position:absolute}#visualize-archrepo .treemap-cell span{padding:3px;font-size:.85em;line-height:1em}#visualize-keys svg{width:100%;height:100%} diff --git a/retro/static/2013/bootstrap-typeahead.min.1aacd3d7f4db.js b/retro/static/2013/bootstrap-typeahead.min.1aacd3d7f4db.js new file mode 100644 index 00000000..7d555ed9 --- /dev/null +++ b/retro/static/2013/bootstrap-typeahead.min.1aacd3d7f4db.js @@ -0,0 +1 @@ +!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery)
\ No newline at end of file diff --git a/retro/static/2013/click_and_pledge.png b/retro/static/2013/click_and_pledge.png Binary files differnew file mode 100644 index 00000000..078bf88e --- /dev/null +++ b/retro/static/2013/click_and_pledge.png diff --git a/retro/static/2013/favicon.29302f683ff8.ico b/retro/static/2013/favicon.29302f683ff8.ico Binary files differnew file mode 100644 index 00000000..55497b85 --- /dev/null +++ b/retro/static/2013/favicon.29302f683ff8.ico diff --git a/retro/static/2013/jquery.js b/retro/static/2013/jquery.js new file mode 100644 index 00000000..83589daa --- /dev/null +++ b/retro/static/2013/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */
+(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);
\ No newline at end of file diff --git a/retro/static/2013/konami.min.e165c814457d.js b/retro/static/2013/konami.min.e165c814457d.js new file mode 100644 index 00000000..f69ca4ff --- /dev/null +++ b/retro/static/2013/konami.min.e165c814457d.js @@ -0,0 +1,4 @@ +var Konami=function(t){var e={addEvent:function(t,e,n,i){t.addEventListener?t.addEventListener(e,n,!1):t.attachEvent&&(t["e"+e+n]=n,t[e+n]=function(){t["e"+e+n](window.event,i)},t.attachEvent("on"+e,t[e+n]))},input:"",pattern:"3838404037393739666513",load:function(t){this.addEvent(document,"keydown",function(n,i){return i&&(e=i),e.input+=n?n.keyCode:event.keyCode,e.input.length>e.pattern.length&&(e.input=e.input.substr(e.input.length-e.pattern.length)),e.input==e.pattern?(e.code(t),e.input="",void 0):void 0},this),this.iphone.load(t)},code:function(t){window.location=t},iphone:{start_x:0,start_y:0,stop_x:0,stop_y:0,tap:!1,capture:!1,orig_keys:"",keys:["UP","UP","DOWN","DOWN","LEFT","RIGHT","LEFT","RIGHT","TAP","TAP","TAP"],code:function(t){e.code(t)},load:function(t){this.orig_keys=this.keys,e.addEvent(document,"touchmove",function(t){if(1==t.touches.length&&e.iphone.capture===!0){var n=t.touches[0] + e.iphone.stop_x=n.pageX,e.iphone.stop_y=n.pageY,e.iphone.tap=!1,e.iphone.capture=!1,e.iphone.check_direction()}}),e.addEvent(document,"touchend",function(){e.iphone.tap===!0&&e.iphone.check_direction(t)},!1),e.addEvent(document,"touchstart",function(t){e.iphone.start_x=t.changedTouches[0].pageX,e.iphone.start_y=t.changedTouches[0].pageY,e.iphone.tap=!0,e.iphone.capture=!0})},check_direction:function(t){var e=Math.abs(this.start_x-this.stop_x),n=Math.abs(this.start_y-this.stop_y),i=0>this.start_x-this.stop_x?"RIGHT":"LEFT",o=0>this.start_y-this.stop_y?"DOWN":"UP",s=e>n?i:o + s=this.tap===!0?"TAP":s,s==this.keys[0]&&(this.keys=this.keys.slice(1,this.keys.length)),0==this.keys.length&&(this.keys=this.orig_keys,this.code(t))}}} +return"string"==typeof t&&e.load(t),"function"==typeof t&&(e.code=t,e.load()),e} diff --git a/retro/static/2013/rss.c5ebdc5318d6.png b/retro/static/2013/rss.c5ebdc5318d6.png new file mode 120000 index 00000000..094d5953 --- /dev/null +++ b/retro/static/2013/rss.c5ebdc5318d6.png @@ -0,0 +1 @@ +rss.png
\ No newline at end of file diff --git a/retro/static/2013/rss.png b/retro/static/2013/rss.png Binary files differnew file mode 100644 index 00000000..a6f114cd --- /dev/null +++ b/retro/static/2013/rss.png diff --git a/retro/static/2013/vector_tux.864e6cdcc23e.png b/retro/static/2013/vector_tux.864e6cdcc23e.png Binary files differnew file mode 100644 index 00000000..ab4be6d0 --- /dev/null +++ b/retro/static/2013/vector_tux.864e6cdcc23e.png diff --git a/retro/static/2013/vnet_button.png b/retro/static/2013/vnet_button.png Binary files differnew file mode 100644 index 00000000..22cfa9e4 --- /dev/null +++ b/retro/static/2013/vnet_button.png diff --git a/retro/templates/retro/index-20020328.html b/retro/templates/retro/index-20020328.html new file mode 100644 index 00000000..8c8f9d62 --- /dev/null +++ b/retro/templates/retro/index-20020328.html @@ -0,0 +1,137 @@ +{% load retro_static from retro %}<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Arch Linux</title> +<link rel="stylesheet" type="text/css" href="{% retro_static year "main.css" %}"> +</head> + +<body bgcolor="#000000" link="cccc00" text="#cccccc"> +<table class="border" align="center"> +<tbody><tr><td> + +<table width="100%"> +<tbody><tr><td valign="bottom"> +<table class="technical"><tbody><tr><td> +Release: 0.1 (Homer)<br> +Devel: 0.2 +</td></tr></tbody></table><br> +<table> + <tbody><tr> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/install.php"> installation </a></td> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/download.php"> download </a></td> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/packages.php"> package list </a></td> + </tr><tr> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/index.php"> news </a></td> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/faq.php"> faq </a></td> + <td class="menu"><a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/changelog.php"> changelog </a></td> + </tr> +</tbody></table> +</td><td align="right"> +<img src="{% retro_static year "archlogo_black.gif" %}" alt="Arch Logo"><br> +<span class="quote"> +</span> +</td></tr></tbody></table> +<hr> + +<p><span class="subheader">News</span><br><br> +<b>Mar 18 - pacman 1.2 released</b> +</p><ul class="plain"><li>I've put a pacman-1.2 package up on the ftp site. This version + comes with the pacsync utility, which lets you automatically download and install + packages and otherwise keep your system up to date.</li></ul> +<b>Mar 13 - rsync server in place</b> +<ul class="plain"><li>I've set up an rsync server on archlinux.org. This will let + everybody keep their /usr/abs tree up to date, and it will also let you easily + mirror the ftp site. I'm in need of download mirrors, so please, if anybody would + like to volunteer, email me and I'll put you on the mirror page.<br><br> + If you don't already have it, create the directory /usr/abs. Then to + update your /usr/abs tree, you can do the following:<br> + <blockquote><pre># cd /usr/abs && rsync -av archlinux.org::abs .</pre></blockquote> + </li></ul> +<b>Mar 11 - Arch Linux 0.1 (Homer) released</b> +<ul class="plain"><li>I've finally got a bootable iso image on the ftp site. + The bad news is that you don't get a pretty interactive installer. But if + you wanted one of those, you would have gone with RedHat, right? ;)<br><br> + Here's a short list of some future plans for 0.2:<ul class="list"> + <li>Document ABS (Arch Build System) and provide a cvs-like update method so people + can start building their own packages. + </li><li>Finish the contrib area and start posting third-party packages. + </li><li>Finish pacman 1.2 -- this will allow you to update your entire system with + the latest stable version of all packages, all with one command. + </li><li>Add a pretty interactive installer. ;) + </li><li>Add more documentation -- our docs really suck right now. Please! If you have + questions, just <a href="mailto:jvinet@zeroflux.org">ask</a>! Also, if you + want to help out in any way, please <a href="mailto:jvinet@zeroflux.org">let me know</a>. + I'm a student so my free time comes and goes at the will of my evil profs. + </li></ul><br> + I'll try to get the docs up for ABS (Arch Build System) which, IMHO, is one + of the best advantages of Arch. With ABS, you can easily create new packages, + and it's trivial to rebuild existing packages with your own customizations.<br><br> + And on that note, if you start to use the ABS and build your own packages, I welcome + your submissions. My "development team" is working on a contrib area as we speak. ;) + </li></ul> +<p></p> +<br> + +<p><span class="subheader">About</span><br><br> +<span class="text">Arch Linux is an i686-optimized linux distribution based on ideas from + <a href="http://web.archive.org/web/20020328043401/http://www.crux.nu/">CRUX</a>, a great distribution developed by Per Lidén. It is lightweight and + contains the latest stable versions of software. Packages are in .tar.gz format and are tracked + by a package manager that is designed to allow easy package upgrades. Arch is quite streamlined + compared to some other distributions. Things that are relatively unused (by me, anyway) are not + kept (info-pages, for example). A default Arch install leaves you with a solid base; from there, + you can add packages to create the custom installation you're looking for. Arch has a package + build system that allows you to easily create your own packages, which makes it very easy to + rebuild a package with your own custom configuration. Arch also aims to use the newer features + available to linux users, such as reiserfs/ext3 and devfs. +</span></p> +<br> + +<p><span class="subheader">Components</span><br><br> +<span class="text">All components are optional, of course. It's your system -- build it however you want.</span><br> +</p><ul class="list"> + <li>Linux Kernel 2.4.18</li> + <li>XFree86 4.2.0</li> + <li>glibc 2.2.5</li> + <li>gcc 2.95.3</li> + <li>OpenSSH 3.1p1</li> + <li>Mozilla 0.9.9</li> + <li>WindowMaker 0.80.0</li> + <li>Vim 6.1</li> + <li>Reiserfsprogs 3.x.1b</li> + <li>devfsd 1.3.22</li> + <li>... and more ...</li> +</ul> +<p></p> +<br> + +<p><span class="subheader">Mailing List</span><br><br> +<span class="text">There is a mailing list in place for general discussion about +Arch Linux. Here, you can post questions, problems, solutions, ideas, etc. To +subscribe to the list, send an email to <b>arch-request@archlinux.org</b> with +<b>subscribe</b> as the subject.<br><br> +Alternatively, you can click <a href="http://web.archive.org/web/20020328043401/http://www.archlinux.org/mailman/listinfo/arch"> +here</a> to use the web interface. +</span> +</p> +<br> + +<p><span class="subheader">IRC</span><br><br> +<span class="text">The project is still in its early stages of development. If you are one + of those brave souls who has installed it and you're seeking help, you can usually find me + on #archlinux at <a href="http://web.archive.org/web/20020328043401/http://www.openprojects.net/">irc.openprojects.net</a>. My nick is + apeiro.</span> +</p> + +</td></tr> +</tbody></table> +<center> +<span class="fineprint">Questions? Comments? <a href="mailto:jvinet@zeroflux.org">Mail em here!</a></span> +<p> +<span class="fineprint">Copyright ©2002, Judd Vinet +<<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>> +</span> +<a href="http://web.archive.org/web/20020328043401/http://sourceforge.net/"> + <img src="{% retro_static year "sflogo.png" %}" alt="SourceForge Logo" align="right" border="0" height="31" width="105"></a> +</p></center> + +</body></html> diff --git a/retro/templates/retro/index-20030330.html b/retro/templates/retro/index-20030330.html new file mode 100644 index 00000000..51cc8ba3 --- /dev/null +++ b/retro/templates/retro/index-20030330.html @@ -0,0 +1,249 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Arch Linux</title> +<link rel="stylesheet" type="text/css" href="{% retro_static year "main.css" %}"> +<link rel="SHORTCUT ICON" href="{% retro_static year "favicon.ico" %}"> +</head> + +<body background="{% retro_static year "dblue071.jpg" %}" bgcolor="#222222" link="cccc00" text="#cccccc"> +<!--BANNER--> + +<table class="container" align="center" cellpadding="5" height="100%"> +<tbody><tr><td colspan="2"> + <!-- START Header Table --> + <table class="header" align="center" width="100%"><tbody><tr><td> + <table width="100%"><tbody><tr><td valign="top"> + <table class="technical"><tbody><tr><td> + <span class="technical"> + Release: 0.4 (Dragon)<br> + Devel: 0.5 + </span> + </td></tr></tbody></table><br> + </td><td rowspan="2" align="right"> + <img src="{% retro_static year "logo.png" %}"> + </td></tr><tr><td valign="bottom"> + <span class="quote">An i686-optimized Linux distribution.</span> + </td></tr></tbody></table> + </td></tr></tbody></table> + <!-- END Header Table --> +</td></tr><tr><td align="left" height="100%" valign="top"> + <!-- START Nav Table --> + <table class="nav" height="100%"><tbody><tr><td height="100%" nowrap="nowrap" valign="top"> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/index.php"> news </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/about.php"> about </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/people.php"> people </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/donation.php"> donate! </a><br> + <br> + <a class="menu" href="javascript:void(0);"> package lists</a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/packages.php?r=arch"> arch </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/packages.php?r=unofficial"> unofficial </a><br> + <br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/download.php"> download </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/docs.php"> documentation </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/support.php"> support </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://bbs.archlinux.org/"> user forum </a><br> + <br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/logos.php"> logos </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/changelog.php"> changelog </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/phpbt/"> bugs </a><br> + <a class="menu" href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/cvs.php"> cvs </a><br> + </td></tr></tbody></table> + <!-- END Nav Table --> +</td><td height="100%" valign="top" width="100%"> + <!-- Start Content Table --> + <table class="content" height="100%" width="100%"><tbody><tr><td height="100%" valign="top"> + +<p><span class="subheader">News</span><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">XFree86 4.3.0 is out</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">February 27, 2003<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> +XFree86 4.3.0 was released today and the Arch package is ready to go.<pr> +The new version of Xfree86 now has xft2 and fontconfig built in, so if you've +already got these packages installed on your system, you will get a package +conflict error when you try to <b>--sysupgrade</b> with pacman. +<p> +You can fix this by removing the xft2 and fontconfig (ignoring dependencies) +and then re-running --sysupgrade.</p><p> +You might get a couple file conflicts as well, but these are just leftover +cache files from the fontconfig package. If they're +<code>fonts.cache-1</code> files, you can safely <b>--force</b> them. +</p><blockquote><code> +# pacman -Rd xft2 fontconfig<br> +# pacman -Syu +</code></blockquote> + </pr></td></tr> + </tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Pacman 2.3 Released</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">February 23, 2003<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> +Pacman 2.3 went out today. It has a few key bugfixes, a cleaner --search +output, and the first stage of source-side auto-resolving dependencies. +<p> +We've also opened a third package repository called +<a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/packages.php?r=unstable">unstable</a>. This repo +will contain packages that are deemed unstable by the software author(s) and/or +the Arch Linux package maintainers. + </p></td></tr> +</tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Arch 0.4 (Dragon) Released</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">December 18, 2002<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> +We are pleased to present Arch 0.4 to the public for general consumption. +The <a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/changelog.php">ChangeLog</a> and <a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/dragon.pkglist">package +list</a> are at their usual locations. +<p> +This release comes with KDE 3.1rc5 and GNOME 2.0.2 as well as the latest +versions of all our usual packges: OpenSSL 0.9.6h, OpenSSH 3.5p1, +XFree86 4.2.1, Linux 2.4.20, GCC 3.2.1, and Glibc 2.3.1. +</p><p> +Dragon still provides a streamlined package set (323 packages) but if you want +more you can always access our unofficial package repository, which has about +350 more packages and is growing fast. Docs can be found +<a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/archdoc.html">here</a> and live help can usually be found in the +#archlinux channel on <a href="http://web.archive.org/web/20030330090147/http://www.freenode.net/">irc.freenode.net</a>. +We also have a <a href="http://web.archive.org/web/20030330090147/http://bbs.archlinux.org/">user forum</a> where you +can post your problems and suggestions. +</p><p> +Happy holidays! + </p></td></tr> +</tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Arch moves to GCC 3.2</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">October 2, 2002<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> + After a few weeks of testing, we are ready to move to gcc 3.2. We have + rebuilt every package with the gcc3 compiler, so this means that you will + see a very large update the next time you run <code>pacman -Syu</code>. + It is advisable to reboot your machine after this upgrade. Remember to + run 'lilo' before rebooting.<p> + Note that packages from the unofficial repository may not work for a few + days. We are in the process of rebuilding them now.</p><p> + With gcc3 out of the way, we are focusing our efforts on the 0.4 release. + Stay tuned. + </p></td></tr> +</tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Pacman 2.1 Released</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">August 22, 2002<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> + Pacman 2.1 has new functionality to allow the use + of multiple package repositories and multiple servers. This was brought about + so we could open a new 'unofficial' package repository that will hold all the + unsupported packages that never made it into the official Arch package area. + <p> + To start using the unofficial repository, just upgrade to pacman 2.1 and + edit your /etc/pacman.conf. Find the block that starts with '[unofficial]' + and uncomment it and the servers listed underneath. Then just run pacman + as usual and it will check both repositories for packages.</p><p> + This also opens up a new opportunity for the more adventurous: You can + now create and use your own local package repositories. I often keep + my own PKGBUILD files in /usr/abs/local and install them on to my box. Now + I can turn that into a functional repository that can be used with the + 'pacman --sync' operation. The new 'gensync' script will do the dirty work + for you. See the pacman manpage for a crude explanation. + </p></td></tr> +</tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Arch 0.3 (Firefly) Released</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">August 7, 2002<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> + At long last, Arch Linux 0.3 is released! Firefly sports the new pacman 2.0, + many new/updated packages and a (hopefully) smoother installation process. + There is also some user documentation available which will get you started + with the nuances of pacman and makepkg. All packages now have meta-info + and dependencies, and the improved ABS system will allow you to follow + different package trees. See the <a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/changelog.php">changelog</a> + for a list of new packages.<br><br> + The 0.3 iso is about 543 MB with all the new packages. If there is enough + demand, I will release a second, smaller iso that only contains the base + packages. From there it is easy to install any additional packages with + pacman's new --sync feature. + </td></tr> +</tbody></table><br><br> + +<table class="box" align="center"> + <tbody><tr><td class="box_headline"> + <table width="100%"><tbody><tr><td class="trans_text"> + <span class="headline">Pacman 2.0 Released</span> + </td><td class="trans_text" align="right"> + <span class="fineprint">July 23, 2002<br>posted by judd</span> + </td></tr></tbody></table> + </td></tr> + <tr><td class="box_content" colspan="2"><br> + Pacman 2.0 was released yesterday and should be on the mirrors soon.<br><br> + Some new pacman features:<br> + <ul> + <li>Package-level dependency functionality</li> + <li>Built-in FTP support</li> + <li>New database structure</li> + <li>md5-based backup file control (a la rpm)</li> + <li>Ability to upgrade packages from a remote server</li> + <li>Auto-resolving dependencies with --sync</li> + <li>A search option for finding new packages</li> + <li>The 'abs' sync script for updating your ABS tree</li> + <li>Dependency checking at the source level with makepkg</li> + <li>More package meta-info available with the --info option</li> + <li>Easy conversion from a pacman 1.x database</li> + </ul><br> + I expect to release Firefly in the next week or so. + </td></tr> +</tbody></table><br><br> + + +<table width="100%"><tbody><tr><td align="right"> + [ <a href="http://web.archive.org/web/20030330090147/http://www.archlinux.org/oldnews.php">Older News</a> ] +</td></tr></tbody></table><br> +<br> + + + </td></tr></tbody></table> + <!-- End Content Table --> +</td></tr> +</tbody></table> +<p align="center"> +Copyright ©2002, Judd Vinet +<<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>> +</p> +<a href="http://web.archive.org/web/20030330090147/http://sourceforge.net/"> + <img src="{% retro_static year "sflogo.png" %}" alt="SourceForge Logo" align="right" border="0" height="31" width="105"></a> + +</body></html> diff --git a/retro/templates/retro/index-20040327.html b/retro/templates/retro/index-20040327.html new file mode 100644 index 00000000..9c8ea0dd --- /dev/null +++ b/retro/templates/retro/index-20040327.html @@ -0,0 +1,477 @@ +{% load retro_static from retro %}<html><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title>Arch Linux</title> +<meta name="keywords" content="linux, linux distribution, arch, pacman, i686-optimized, distribution, open source, free, packages, server, daemon, network, systems"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "fonts.css" %}"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "containers.css" %}"> +<link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}"> +</head> +<body> +<table style="background-color: rgb(0, 0, 0); width: 100%;" cellspacing="0"> + <tbody><tr> + <td colspan="2" class="preHeader"><span class="preHeader">An i686-optimized Linux distribution</span></td> + </tr> + <tr> + <td class="headerFill" colspan="2"> + <table width="100%"> + <tbody><tr> + <td class="headerDisplay"><img src="{% retro_static year "logoTop.gif" %}"></td> + <td class="headerDisplay" align="right"> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="mainLinks" align="center"><span class="f2"><span class="black">.:</span> <a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/index.php">Home</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/news.php">News</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/about.php">About</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/packages.php">Packages</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/download.php">Download</a> <span class="black">:.</span></span></td> + <td rowspan="2" class="sideBar" height="100%" valign="top"> + <table cellspacing="0" height="100%"> + <tbody><tr> + <td class="sideBarGrey"><center><br><br></center> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader" valign="top"><span class="sideBarSmallHeader">Get Arch Linux</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/download.php">Download</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.osdisc.com/cgi-bin/view.cgi/products/linux/arch">Get a CD</a><!-- a href="http://www.linuxcd.org/view_distro.php?id_distro=48">Get a CD</a--></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/changelog.php">ChangeLog</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/logos.php">Logos/Wallpaper</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Support / Community</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://bbs.archlinux.org/">User Forums</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/mailman/listinfo/arch/">Mailing List</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/pipermail/arch/">Archives</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://wiki.archlinux.org/">Wiki</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://archlinux.org/donations.php">Donations</a></span></span> + </td> + </tr> + <tr> + <td> + <table> + <tbody><tr><td valign="top"><span class="f4"><span class="blue"><b>·IRC:</b></span></span></td> + <td><span class="f4"><span class="blue">irc.freenode.net<br>#archlinux<br>#archlinuxfr</span></span></td></tr> + </tbody></table> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Documentation</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/docs/en/">English</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/docs/de/">Deutsch</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/docs/es/">Español</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/docs/fr/">Français</a></span> (old)</span><br> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">User Contributions</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://tur.archlinux.org/">TURs</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://archstats.coding-zone.com/">ArchStats</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://amlug.net/new-projects/live-cd/al-amlug-live-cd.html">Arch Live CD</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://amlug.net/new-projects/hwd/hwd.html">Hardware Detection</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Press</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.linuxlookup.com/modules.php?op=modload&name=Reviews&file=index&req=showcontent&id=58">Review at LinuxLookup</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.osnews.com/story.php?news_id=5971">Review at OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.osnews.com/story.php?news_id=4827">Review at OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://lwn.net/Articles/40952/">Review at LWN</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.distrowatch.com/dwres.php?resource=interview-arch">Interview at DW</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://home.nyc.rr.com/computertaijutsu/arch.html">Scott Robbins</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Development</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/people.php">Developers</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://bugs.archlinux.org/">Bug Tracker</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20040327023505/http://www.archlinux.org/cvs.php">CVS Repository</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<a href="http://web.archive.org/web/20040327023505/http://sourceforge.net/"><img src="{% retro_static year "sflogo.png" %}" alt="SourceForge Logo" border="0" height="31" width="105"></a> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<!-- paypal code --> +<img src="{% retro_static year "x-click-butcc-donate.gif" %}" alt="Make payments with PayPal - it's fast, free and secure!" style="background: none repeat scroll 0% 0% transparent; border: medium none;" border="0"> +<br> +<span class="f4">All money goes directly to server costs</span> + </td> + </tr> + <tr> + <td class="sideBarGrey" style="border: medium none;" height="100%"> </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="contentDisplay"> + +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Package Directory</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontComponents.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 100%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table style="width: 100%;" cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Search: </span> + <input name="s_keyword" size="20" value="enter keywords" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td colspan="2"> + <table class="boxSoft" cellspacing="2"> + <tbody><tr> + <td class="boxSoftTitle" align="right"> + <span class="f3">Recent Updates</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;"> + <tbody><tr> + <td><span class="f4"><span class="blue"> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=250">ethereal 0.10.3-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=768">zsh 4.2.0-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=3590">fbset 2.1-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=559">oxine 0.2-2</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=3589">xfce4-xmms-plugin 0.1.1-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=3588">xfce4-fsguard-plugin 0.2.0-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=885">galculator 1.2.1-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=2037">mutt-devel 1.5.6i-2</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=3587">xpenguins_themes 1.0-1</a><br> +· <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?id=3586">loudmouth 0.16-1</a><br> + </span> + </span></td> + <td align="right"><span class="f4"> +network<br> +system<br> +system<br> +multimedia<br> +xfce4<br> +xfce4<br> +x11<br> +network<br> +games<br> +network<br> + </span></td> + </tr> + </tbody></table> + <table style="width: 100%;"><tbody><tr><td align="right"> + <span class="f5"><br><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?os=lastupdate&s=lastupdate">More...</a></span> + </td></tr></tbody></table> + </td> + </tr> + </tbody></table> + </td> + <td class="ss"> + <table style="width: 100%;"><tbody><tr><td> + <span class="f3">Current Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?s_repo=1">Current</a></span></td> + <td align="right"><span class="f4"> +March 26 20:54 </span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?s_repo=2">Extra</a></span></td> + <td align="right"><span class="f4">March 26 16:35</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?s_repo=3">Unstable</a></span></td> + <td align="right"><span class="f4">March 25 06:44</span></td> + </tr> + </tbody></table> + </td></tr><tr><td> + <img src="{% retro_static year "pad.gif" %}" height="30"><br> + <span class="f3">Release Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/packages.php?s_repo=1">0.7 ______</a></span></td> + <td align="right"><span class="f4"><i>pending</i></span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.6">0.6 Widget</a></span></td> + <td align="right"><span class="f4">March 1, 2004</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.5">0.5 Nova</a></span></td> + <td align="right"><span class="f4">July 21, 2003</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.4">0.4 Dragon</a></span></td> + <td align="right"><span class="f4">December 18, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.3">0.3 Firefly</a></span></td> + <td align="right"><span class="f4">August 7, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.2">0.2 Vega</a></span></td> + <td align="right"><span class="f4">April 17, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20040327023505/http://archlinux.org/pkglist.php?r=0.1">0.1 Homer</a></span></td> + <td align="right"><span class="f4">March 11, 2002</span></td> + </tr> + </tbody></table> + </td></tr></tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Current News</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontNews.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 50%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20040327023505/http://archlinux.org/subscribe.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Subscribe: </span> + <input name="email" size="20" value="enter email" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td class="ss" colspan="4" align="center"> + <table> + <tbody><tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/news.php#56">Arch Review at LinuxLookup</a><br> <div style="padding-left: 20"><span class="f5">There's a favorable review of Arch Linux at LinuxLookup.com....</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 23, 2004</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/news.php#55">Arch Linux Newsletter for March 21, 2004</a><br> <div style="padding-left: 20"><span class="f5">New newsletter for this week: http://www.archlinux.org/~jason/newsletters/newsle...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 22, 2004</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/news.php#54">OpenSSL Upgrade</a><br> <div style="padding-left: 20"><span class="f5">We've started the not-so-fun upgrade from openssl 0.9.6 to openssl 0.9.7. We've...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 20, 2004</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/news.php#53">Arch Linux Newsletter for March 14, 2004</a><br> <div style="padding-left: 20"><span class="f5">New newsletter for this week: http://www.archlinux.org/~jason/newsletters/newsle...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 14, 2004</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20040327023505/http://archlinux.org/news.php#52">Arch Linux Newsletter for March 07, 2004</a><br> <div style="padding-left: 20"><span class="f5">New newsletter for this week: http://www.archlinux.org/~jason/newsletters/newsle...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 07, 2004</span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> + + </td> + </tr> + <tr> + <td colspan="2" class="footerDisplay"><span class="f5"> +Copyright ©2002-2004, Judd Vinet <<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>> + </span> + </td> + </tr> +</tbody></table> + +</body></html> diff --git a/retro/templates/retro/index-20050328.html b/retro/templates/retro/index-20050328.html new file mode 100644 index 00000000..8b4f9e75 --- /dev/null +++ b/retro/templates/retro/index-20050328.html @@ -0,0 +1,609 @@ +{% load retro_static from retro %}<html><head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Arch Linux</title> +<meta name="keywords" content="linux, linux distribution, arch, pacman, i686-optimized, distribution, open source, free, packages, server, daemon, network, systems"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "fonts.css" %}"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "containers.css" %}"> +<link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}"> +</head> +<body> +<table style="background-color: rgb(0, 0, 0); width: 100%;" cellspacing="0"> + <tbody><tr> + <td colspan="2" class="preHeader"><span class="preHeader">An i686-optimized Linux distribution</span></td> + </tr> + <tr> + <td class="headerFill" colspan="2"> + <table width="100%"> + <tbody><tr> + <td class="headerDisplay"><img src="{% retro_static year "logoTop.png" %}"></td> + <td class="headerDisplay" align="right"> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="mainLinks" align="center"><span class="f2"><span class="black">.:</span> <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/index.php">Home</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php">News</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/about.php">About</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php">Packages</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/download.php">Download</a> <span class="black">:.</span></span></td> + <td rowspan="2" class="sideBar" height="100%" valign="top"> + <table cellspacing="0" height="100%"> + <tbody><tr> + <td class="sideBarGrey"><center><br><br></center> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader" valign="top"><span class="sideBarSmallHeader">Get Arch Linux</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/download.php">Download</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.osdisc.com/cgi-bin/view.cgi/products/linux/arch">Get a CD</a><!-- a href="http://www.linuxcd.org/view_distro.php?id_distro=48">Get a CD</a--></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/changelog.php">ChangeLog</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/logos.php">Logos/Wallpaper</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.cafeshops.com/archlinux/">Schwag</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Support / Community</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://bbs.archlinux.org/">User Forums</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.nl/forum/">Dutch</a></span></span> + </td> + </tr><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://forums.archlinuxfr.org/">French</a></span></span> + </td> + </tr><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.it/">Italian</a></span></span> + </td> + </tr><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://archlinux.laber-land.de/">German</a></span></span> + </td> + </tr><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://archlinux.fc.pl/forum/">Polish</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/mailman/listinfo/arch/">Mailing List</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pipermail/arch/">Archives</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://news.gmane.org/gmane.linux.arch.general">Gmane</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://wiki.archlinux.org/">Wiki</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/%7Ejason/newsletters/">Newsletters</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/donations.php">Donations</a></span></span> + </td> + </tr> + <tr> + <td> + <table> + <tbody><tr><td valign="top"><span class="f4"><span class="blue"><b>·IRC:</b></span></span></td> + <td><span class="f4"><span class="blue">irc.freenode.net<br>#archlinux<br>#archlinuxfr<br>#archlinux.de<br>#archlinux-es</span></span></td></tr> + </tbody></table> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Documentation</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/docs/en/">English</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/docs/de/">Deutsch</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/docs/es/">Español</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/docs/fr/">Français</a></span> (old)</span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/docs/it/guide/install/arch-install-guide.html">Italian</a></span></span><br> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">User Contributions</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://tur.archlinux.org/">TURs</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/mailman/listinfo/tur-users/">Mailing List</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://archstats.coding-zone.com/">ArchStats</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://amlug.net/new-projects/live-cd/al-amlug-live-cd.html">Arch Live CD</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://amlug.net/new-projects/hwd/hwd.html">Hardware Detection</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://arch-i18n.berlios.de/">Translation Project</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Press</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://osnews.com/story.php?news_id=10047">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://os.newsforge.com/os/05/02/14/1722211.shtml?tid=2">NewsForge</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.linuxtimes.net/modules.php?name=News&file=article&sid=774">LinuxTimes</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://osnews.com/story.php?news_id=9540">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://discuss.extremetech.com/n/mb/display.asp?webtag=extremetech&msg=53648.1">Robert Burns</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.linuxlookup.com/modules.php?op=modload&name=Reviews&file=index&req=showcontent&id=58">LinuxLookup</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.osnews.com/story.php?news_id=5971">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.osnews.com/story.php?news_id=4827">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://lwn.net/Articles/40952/">LWN</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.distrowatch.com/dwres.php?resource=interview-arch">DistroWatch</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://home.nyc.rr.com/computertaijutsu/arch.html">Scott Robbins</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Development</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/people.php">Developers</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://bugs.archlinux.org/">Bug Tracker</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/cvs.php">CVS Repository</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/"><img src="{% retro_static year "button.png" %}" alt="Arch Linux" border="0"></a> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<a href="http://web.archive.org/web/20050328032247/http://sourceforge.net/"><img src="{% retro_static year "sflogo.png" %}" alt="SourceForge Logo" border="0" height="31" width="105"></a> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<!-- paypal code --> +<img src="{% retro_static year "x-click-butcc-donate.gif" %}" alt="Make payments with PayPal - it's fast, free and secure!" style="background: none repeat scroll 0% 0% transparent; border: medium none;" border="0"> +<br> +<span class="f4">All money goes directly to server costs</span> + </td> + </tr> + <tr> + <td class="sideBarGrey" style="border: medium none;" height="100%"> </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="contentDisplay"> + +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Package Directory</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontComponents.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 100%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table style="width: 100%;" cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Search: </span> + <input name="s_keyword" size="20" value="enter keywords" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td colspan="2"> + <table class="boxSoft" cellspacing="2"> + <tbody><tr> + <td class="boxSoftTitle" align="right"> + <span class="f3">Recent Updates</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellpadding="0" cellspacing="0"> +<tbody><tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=6469">snapscreenshot 1.0.14.2-1</a></span></span></td><td align="right"><span class="f4">system</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=364">guile 1.6.7-1</a></span></span></td><td align="right"><span class="f4">devel</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=361">glade 2.10.0-1</a></span></span></td><td align="right"><span class="f4">devel</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=6067">libgnomeprint-cups 2.10.2-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3163">libgnomeprintui 2.10.2-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3162">libgnomeprint 2.10.2-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3697">gok 1.0.3-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3696">gnopernicus 0.10.5-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=6435">gnome-menus 2.10.1-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3890">genius 0.7.3-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=1991">gedit 2.10.1-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3134">control-center 2.10.0-2</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=1976">mplayer-plugin 2.80-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3578">abcm2ps-devel 4.9.2-1</a></span></span></td><td align="right"><span class="f4">office</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?id=3145">gnome-icon-theme 2.10.1-1</a></span></span></td><td align="right"><span class="f4">gnome</span></td></tr> + </tbody></table> + <table style="width: 100%;"><tbody><tr> + <td> + <span class="f5"><br><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/rdf_feed.php">RDF</a></span> + </td><td align="right"> + <span class="f5"><br><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?os=lastupdate&s=lastupdate">More...</a></span> + </td></tr></tbody></table> + </td> + </tr> + </tbody></table> + </td> + <td class="ss"> + <table style="width: 100%;"><tbody><tr><td> + <span class="f3">Current Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?s_repo=1">Current</a></span></td> + <td align="right"><span class="f4"> +March 24 05:13 </span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?s_repo=2">Extra</a></span></td> + <td align="right"><span class="f4">March 27 12:06</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?s_repo=3">Unstable</a></span></td> + <td align="right"><span class="f4">March 27 09:49</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?s_repo=4">Testing</a></span></td> + <td align="right"><span class="f4">March 17 18:52</span></td> + </tr> + </tbody></table> + </td></tr><tr><td> + <img src="{% retro_static year "pad.gif" %}" height="30"><br> + <span class="f3">Release Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/packages.php?s_repo=1">0.8 ______</a></span></td> + <td align="right"><span class="f4"><i>pending</i></span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.7">0.7 Wombat</a></span></td> + <td align="right"><span class="f4">January 24, 2005</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.6">0.6 Widget</a></span></td> + <td align="right"><span class="f4">March 1, 2004</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.5">0.5 Nova</a></span></td> + <td align="right"><span class="f4">July 21, 2003</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.4">0.4 Dragon</a></span></td> + <td align="right"><span class="f4">December 18, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.3">0.3 Firefly</a></span></td> + <td align="right"><span class="f4">August 7, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.2">0.2 Vega</a></span></td> + <td align="right"><span class="f4">April 17, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/pkglist.php?r=0.1">0.1 Homer</a></span></td> + <td align="right"><span class="f4">March 11, 2002</span></td> + </tr> + </tbody></table> + </td></tr></tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Current News</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontNews.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 50%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20050328032247/http://www.archlinux.org/subscribe.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Subscribe: </span> + <input name="email" size="20" value="enter email" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td class="ss" colspan="4" align="center"> + <table> + <tbody><tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#145">Arch Linux Newsletter for March 20, 2005</a><br> <div style="padding-left: 20"><span class="f5">New newsletter for this week: http://www.archlinux.org/~jason/newsletters/newsle...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 22, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#144">celestia 1.3.2-2 - switching from KDE to GTK2 UI</a><br> <div style="padding-left: 20"><span class="f5">Because of the bug 2422 i had to rebuild the celestia pkg. Considering that i di...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 21, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#143">KDE 3.4.0 in [extra] UPGRADERS PLEASE READ THIS!</a><br> <div style="padding-left: 20"><span class="f5">Greetings to all kde users out there. +kde 3.4.0 packages are now in extra repos...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 16, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#142">Arch Linux Newsletter for February 27, 2005</a><br> <div style="padding-left: 20"><span class="f5">New newsletter for this week: http://www.archlinux.org/~jason/newsletters/newsle...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 27, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#141">mono 1.2 beta series is in testing</a><br> <div style="padding-left: 20"><span class="f5">Actually this should go to unstable. But as written on a couple of websites, ann...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 21, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#140">The inevitable courier-smashing starts in testing</a><br> <div style="padding-left: 20"><span class="f5">The layout of courier sources has changed. So we have a courier-authlib now, pro...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 20, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#139">webmin in [testing]</a><br> <div style="padding-left: 20"><span class="f5">hi +for all who waited for webmin now it's available. Please use the bugtracker ...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 15, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#138">Udev-053 Changes</a><br> <div style="padding-left: 20"><span class="f5">The latest version of udev has some upstream changes in the configuration layout...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 14, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#137">Xorg 6.8.2 Released</a><br> <div style="padding-left: 20"><span class="f5">The new xorg package is now available in the Testing repository. + +You can enab...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 10, 2005</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php#136">testing: fox 1.2.11 -> 1.4.y</a><br> <div style="padding-left: 20"><span class="f5">The fox toolkit released their first 1.4.y versions some days ago. As this is a ...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 10, 2005</span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr><tr> + <td> + <table style="width: 100%; background: none repeat scroll 0% 0% rgb(255, 255, 255);"><tbody><tr> + <td> + <span class="f5"><br><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/rdf_news.php">RDF</a></span> + </td><td align="right"> + <span class="f5"><br><a href="http://web.archive.org/web/20050328032247/http://www.archlinux.org/news.php">More...</a></span> + </td></tr></tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> + + </td> + </tr> + <tr> + <td colspan="2" class="footerDisplay"><span class="f5"> +Copyright ©2002-2005, Judd Vinet <<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>> + </span> + </td> + </tr> +</tbody></table> + +</body></html> diff --git a/retro/templates/retro/index-20060328.html b/retro/templates/retro/index-20060328.html new file mode 100644 index 00000000..f45024df --- /dev/null +++ b/retro/templates/retro/index-20060328.html @@ -0,0 +1,653 @@ +{% load retro_static from retro %}<html><head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Arch Linux</title> +<meta name="keywords" content="linux, linux distribution, arch, pacman, i686-optimized, distribution, open source, free, packages, server, daemon, network, systems"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "fonts.css" %}"> +<link rel="stylesheet" type="text/css" href="{% retro_static year "containers.css" %}"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Feed" href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/rdf_news.php"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/rdf_feed.php"> +<link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}"> +</head> +<body> +<table style="background-color: rgb(0, 0, 0); width: 100%;" cellspacing="0"> + <tbody><tr> + <td colspan="2" class="preHeader"><span class="preHeader">An i686-optimized Linux distribution</span></td> + </tr> + <tr> + <td class="headerFill" colspan="2"> + <table width="100%"> + <tbody><tr> + <td class="headerDisplay"><img src="{% retro_static year "logoTop.png" %}"></td> + <td class="headerDisplay" align="right"> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="mainLinks" align="center"><span class="f2"><span class="black">.:</span> <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/index.php">Home</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/news.php">News</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/about.php">About</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/packages.php">Packages</a> <span class="black"> - </span> <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/download.php">Download</a> <span class="black">:.</span></span></td> + <td rowspan="2" class="sideBar" height="100%" valign="top"> + <table cellspacing="0" height="100%"> + <tbody><tr> + <td class="sideBarGrey"><center><br><br></center> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader" valign="top"><span class="sideBarSmallHeader">Get Arch Linux</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/download.php">Download</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.osdisc.com/cgi-bin/view.cgi/products/linux/arch">Get a CD</a><!-- a href="http://www.linuxcd.org/view_distro.php?id_distro=48">Get a CD</a--></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/changelog.php">ChangeLog</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/logos.php">Logos/Artwork</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.cafeshops.com/archlinux/">Schwag</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Support / Community</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://wiki.archlinux.org/">Wiki / Docs</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://bbs.archlinux.org/">Forums</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> · + <a href="http://web.archive.org/web/20060328003102/http://archlinux.laber-land.de/">de</a>, + <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.com.ar/">es</a>, + <a href="http://web.archive.org/web/20060328003102/http://forums.archlinuxfr.org/">fr</a>, + <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.it/">it</a>, + <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.nl/forum/">nl</a>, + <a href="http://web.archive.org/web/20060328003102/http://archlinux.fc.pl/forum/">pl</a> + </span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/mailman/listinfo/arch/">Mailing List</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/pipermail/arch/">Archives</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://news.gmane.org/gmane.linux.arch.general">Gmane</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://aur.archlinux.org/">AUR</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/mailman/listinfo/tur-users/">Mailing List</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://planet.archlinux.org/">Planet Arch</a></span></span> + </td> + </tr><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/blog/">Blog</a></span></span> + </td> + </tr> + + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/%7Ejason/newsletters/">Newsletters</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/donations.php">Donations</a></span></span> + </td> + </tr> + <tr> + <td> + <table> + <tbody><tr><td valign="top"><span class="f4"><span class="blue"><b>·IRC:</b></span></span></td> + <td><span class="f4"><span class="blue">irc.freenode.net<br>#archlinux<br>#archlinuxfr<br>#archlinux.de<br>#archlinux.se<br>#archlinux-es</span></span></td></tr> + </tbody></table> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Documentation</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/docs/en/">English</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/docs/de/">Deutsch</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/docs/es/">Español</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/docs/fr/">Français</a></span></span><br> + <span class="f4"><span class="blue"> ·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/docs/it/guide/install/arch-install-guide.html">Italian</a></span></span><br> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">User Contributions</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://user-contributions.org/home/index.php">user-contributions.org</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/%7Esimo/archstats/">ArchStats</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://archie.dotsrc.org/">Archie Live CD</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.arch64.org/">Arch64</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://amlug.net/new-projects/hwd/hwd.html">Hardware Detection</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://arch-i18n.berlios.de/">Translation Project</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://arch-egis.berlios.de/">AEGIS</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Press</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.linux-magazine.com/issue/64/Arch_Linux_Review.pdf">Linux Magazine (pdf)</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://michael-and-mary.net/intro/?q=node/260">Michael & Mary</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://osnews.com/story.php?news_id=10142">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://osnews.com/story.php?news_id=10047">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://os.newsforge.com/os/05/02/14/1722211.shtml?tid=2">NewsForge</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.linuxtimes.net/modules.php?name=News&file=article&sid=774">LinuxTimes</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://osnews.com/story.php?news_id=9540">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://discuss.extremetech.com/n/mb/display.asp?webtag=extremetech&msg=53648.1">Robert Burns</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.linuxlookup.com/modules.php?op=modload&name=Reviews&file=index&req=showcontent&id=58">LinuxLookup</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.osnews.com/story.php?news_id=5971">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.osnews.com/story.php?news_id=4827">OSNews</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://lwn.net/Articles/40952/">LWN</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.distrowatch.com/dwres.php?resource=interview-arch">DistroWatch</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://home.nyc.rr.com/computertaijutsu/arch.html">Scott Robbins</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="sideBarSmallHeader"><span class="sideBarSmallHeader">Development</span></td> + </tr> + <tr> + <td class="sideBarGrey"> + <table cellspacing="6"> + <tbody><tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/devs.php">Developers</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://bugs.archlinux.org/">Bug Tracker</a></span></span> + </td> + </tr> + <tr> + <td> + <span class="f4"><span class="blue">·<a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/cvs.php">CVS Repository</a></span></span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> + <a href="http://web.archive.org/web/20060328003102/http://www.archlinux.org/"><img src="{% retro_static year "button.png" %}" alt="Arch Linux" border="0"></a> + </td> + </tr> + <tr> + <td style="background-color: rgb(238, 238, 238);" align="center"><br> +<!-- paypal code --> +<img src="{% retro_static year "x-click-butcc-donate.gif" %}" alt="Make payments with PayPal - it's fast, free and secure!" style="background: none repeat scroll 0% 0% transparent; border: medium none;" border="0"> + </td> + </tr> + <tr> + <td class="sideBarGrey" style="border: medium none;" height="100%"> </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td class="contentDisplay"> + +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Package Directory</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontComponents.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 100%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table style="width: 100%;" cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Search: </span> + <input name="s_keyword" size="20" value="enter keywords" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td colspan="2"> + <table class="boxSoft" cellspacing="2"> + <tbody><tr> + <td class="boxSoftTitle" align="right"> + <span class="f3">Recent Updates</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellpadding="0" cellspacing="0"> +<tbody><tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=6741">amarok-engine-xine 1.3.9-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=6740">amarok-engine-gst 1.3.9-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=6739">amarok-engine-arts 1.3.9-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=6738">amarok-base-mysqlfree 1.3.9-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=6737">amarok-base 1.3.9-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=2134">bincimap 1.2.13-2</a></span></span></td><td align="right"><span class="f4">network</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=10718">bmp-musepack 1.2-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=3280">bmp 0.9.7.1-4</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=4340">tunepimp 0.4.1-1</a></span></span></td><td align="right"><span class="f4">multimedia</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=4297">mc 4.6.1-4</a></span></span></td><td align="right"><span class="f4">system</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=4140">pcre 6.6-2</a></span></span></td><td align="right"><span class="f4">base</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=855">bash-completion 20060301-5</a></span></span></td><td align="right"><span class="f4">system</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=4162">mysql 5.0.19-2</a></span></span></td><td align="right"><span class="f4">daemons</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=4174">vsftpd 2.0.4-3</a></span></span></td><td align="right"><span class="f4">daemons</span></td></tr> +<tr><td><span class="f4"><span class="blue">· <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?id=5755">mod_python 3.2.8-1</a></span></span></td><td align="right"><span class="f4">devel</span></td></tr> + </tbody></table> + <table style="width: 100%;"><tbody><tr> + <td> + <span class="f5"><br><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/rdf_feed.php">RDF</a></span> + </td><td align="right"> + <span class="f5"><br><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?os=lastupdate&s=lastupdate">More...</a></span> + </td></tr></tbody></table> + </td> + </tr> + </tbody></table> + </td> + <td class="ss"> + <table style="width: 100%;"><tbody><tr><td> + <span class="f3">Current Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=1">Current</a></span></td> + <td align="right"><span class="f4"> +March 27 13:34 </span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=2">Extra</a></span></td> + <td align="right"><span class="f4">March 27 17:35</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=3">Unstable</a></span></td> + <td align="right"><span class="f4">March 18 20:43</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=4">Testing</a></span></td> + <td align="right"><span class="f4">March 27 13:14</span></td> + </tr> + </tbody></table> + </td></tr><tr><td> + <img src="{% retro_static year "pad.gif" %}" height="30"><br> + <span class="f3">Release Package Lists</span> + <table style="width: 90%;" align="right"> + <tbody><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=1">0.7.2 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/packages.php?s_repo=1">______</a></span></td> + <td align="right"><span class="f4"><i>pending</i></span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.7.1">0.7.1 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.7.1">Noodle</a></span></td> + <td align="right"><span class="f4">January 5, 2006</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.7">0.7 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.7">Wombat</a></span></td> + <td align="right"><span class="f4">January 24, 2005</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.6">0.6 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.6">Widget</a></span></td> + <td align="right"><span class="f4">March 1, 2004</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.5">0.5 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.5">Nova</a></span></td> + <td align="right"><span class="f4">July 21, 2003</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.4">0.4 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.4">Dragon</a></span></td> + <td align="right"><span class="f4">December 18, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.3">0.3 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.3">Firefly</a></span></td> + <td align="right"><span class="f4">August 7, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.2">0.2 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.2">Vega</a></span></td> + <td align="right"><span class="f4">April 17, 2002</span></td> + </tr><tr> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.1">0.1 </a></span></td> + <td><span class="f4"><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/pkglist.php?r=0.1">Homer</a></span></td> + <td align="right"><span class="f4">March 11, 2002</span></td> + </tr> + </tbody></table> + </td></tr></tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> +<center> +<table class="boxSoft" cellspacing="3"> + <tbody><tr> + <td class="boxSoftTitle" align="right" nowrap="nowrap"> + <span class="f3">Current News</span> + </td> + </tr><tr> + <td class="boxSoft"> + <table style="width: 100%;" cellspacing="4"> + <tbody><tr> + <td colspan="2" style="text-align: center; width: 50%;"><img src="{% retro_static year "frontNews.gif" %}" height="30" width="179"><br><img src="{% retro_static year "pad.gif" %}" height="50"></td> + <td colspan="2" style="text-align: center; width: 50%;" align="right" valign="top"> + <table class="boxSoftSmall" style="width: 250px;" align="right" cellspacing="3"> + <tbody><tr> + <td class="boxSoftSmall"> + <table cellspacing="0"> + <tbody><tr> + <td style="text-align: center; padding-left: 10px;"> + <form action="http://web.archive.org/web/20060328003102/http://archlinux.org/subscribe.php" method="POST"> + <center> + <table cellspacing="0"><tbody><tr><td><span class="f3">Subscribe: </span> + <input name="email" size="20" value="enter email" onfocus="this.value='';" type="text"> + </td><td style="width: 100%; text-align: center; vertical-align: bottom;"> + <span class="f3"><input class="button" value="Go" type="submit"></span> + </td></tr></tbody></table> + </center> + </form> + </td></tr> + + </tbody></table> + </td> + </tr> + </tbody></table><br> + </td> + </tr> + <tr> + <td class="ss" colspan="4" align="center"> + <table> + <tbody><tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#212">Kernel 2.6.16 - modularized capability</a><br> <div style="padding-left: 20"><span class="f5">Hey all, + +Some people have requested that we move the default linux capability...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 20, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#211">Server Migration Complete!</a><br> <div style="padding-left: 20"><span class="f5">Thanks to everyone's generous donations, Dale was able to purchase a nice shiny ...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 20, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#210">New Newsletter for March 19th</a><br> <div style="padding-left: 20"><span class="f5">Today marks the day of a new newsletter. Read it and rejoice! + +Current: http:...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 19, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#209">Important glibc change</a><br> <div style="padding-left: 20"><span class="f5">glibc will no longer contain pre-generated locales. This means users who use som...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 11, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#208">ArchCK in Extra, madwifi-ng in [unstable], ATI drivers renamed.</a><br> <div style="padding-left: 20"><span class="f5">I have had to rename the ATI drivers a second time. Soon there will be driver pa...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 10, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#207">New Newsletter for March 05, 2006</a><br> <div style="padding-left: 20"><span class="f5">Latest newsletter: http://archlinux.org/~jason/newsletters/newsletter-2006-Mar-0...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">March 05, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#206">Donation Drive: We won!</a><br> <div style="padding-left: 20"><span class="f5">Just in case you weren't around for the last few days, we had a donation drive a...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 28, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#205">Important glibc locale change in testing</a><br> <div style="padding-left: 20"><span class="f5">Starting with glibc 2.3.6-1, locales will no longer be included as a pre-generat...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 28, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#204">Server Donation Drive</a><br> <div style="padding-left: 20"><span class="f5">On the Archlinux Mailing List, Judd posted the following: + +Hey all, + +I'm sur...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 22, 2006</span> + </td> + </tr> + <tr> + <td nowrap="nowrap"> + <span class="f3"><span class="blue"> + <a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php#203">Xorg7 Moves to Current</a><br> <div style="padding-left: 20"><span class="f5">Hey everyone, + +Xorg7 has finally moved into Current. The upgrade is pretty sm...</span></div> </span> + </span></td><td style="width: 50px;"> </td> + <td align="right" nowrap="nowrap" valign="top"> + <span class="f5">February 20, 2006</span> + </td> + </tr> + </tbody></table> + </td> + </tr> + <tr> + <td colspan="4"><img src="{% retro_static year "pad.gif" %}" height="10" width="1"></td> + </tr> + </tbody></table> + </td> + </tr><tr> + <td> + <table style="width: 100%; background: none repeat scroll 0% 0% rgb(255, 255, 255);"><tbody><tr> + <td> + <span class="f5"><br><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/rdf_news.php">RDF</a></span> + </td><td align="right"> + <span class="f5"><br><a href="http://web.archive.org/web/20060328003102/http://archlinux.org/news.php">More...</a></span> + </td></tr></tbody></table> + </td> + </tr> +</tbody></table> +</center> +<br> + + </td> + </tr> + <tr> + <td colspan="2" class="footerDisplay"><span class="f5"> +Copyright ©2002-2006, Judd Vinet <<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>> + </span> + </td> + </tr> +</tbody></table> + +</body></html> diff --git a/retro/templates/retro/index-20070324.html b/retro/templates/retro/index-20070324.html new file mode 100644 index 00000000..14453726 --- /dev/null +++ b/retro/templates/retro/index-20070324.html @@ -0,0 +1,382 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1-strict.dtd "> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" href="{% retro_static year "arch.css" %}"> + <link rel="icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + <link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20070324064759/http://archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20070324064759/http://archlinux.org/feeds/packages/"> + + </head> + <body> + + <div id="head_container"> + <div id="title"> + <div id="logo"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/"><img src="{% retro_static year "logo.png" %}" alt="Arch Logo"></a></div> + <a href="http://web.archive.org/web/20070324064759/http://archlinux.org/"><img src="{% retro_static year "title.png" %}" alt="Arch Linux"></a> + </div> + <div style="float: right; color: #eeeeee; font-size: small"> + + </div> + <div id="main_nav"> + + <ul> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/download/">Get Arch</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://aur.archlinux.org/">AUR</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://bugs.archlinux.org/">Bugs</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://wiki.archlinux.org/">Wiki</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://bbs.archlinux.org/">Forums</a></li> + <li class="selected"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/">Home</a></li> + </ul> + + </div> + + + <div id="ads"> + </div> + + </div> + <div id="content"> + + <div class="right"> + + <div id="search"> + <form method="get" action="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/search/"> + <p>Package Search: <input name="q" size="20" maxlength="200" type="text"></p> + </form> + </div> + <div id="updates"> + <table width="100%"> + <tbody><tr> + <td><h3>Recent Updates</h3></td> + <td style="vertical-align: top; text-align: right;"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/feeds/packages/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a></td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/4208/">gimp 2.2.13-3</a></td> + <td style="text-align: right;">multimedia</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/8704/">netcdf 3.6.2-1</a></td> + <td style="text-align: right;">lib</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/12748/">syslinux 3.36-1</a></td> + <td style="text-align: right;">system</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/8605/">cairo 1.4.2-1</a></td> + <td style="text-align: right;">lib</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/3874/">libgda 1.2.4-1</a></td> + <td style="text-align: right;">lib</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/3873/">libgnomedb 1.2.2-4</a></td> + <td style="text-align: right;">gnome</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/3333/">inkscape 0.45.1-1</a></td> + <td style="text-align: right;">multimedia</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/4197/">kernel26 2.6.20.3-3</a></td> + <td style="text-align: right;">kernels</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/12500/">mercurial 0.9.3-2</a></td> + <td style="text-align: right;">devel</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/662/">squid 2.6.STABLE10-1</a></td> + <td style="text-align: right;">network</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/361/">glade 3.2.0-1</a></td> + <td style="text-align: right;">devel</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/3705/">wlan-ng26 0.2.7-4</a></td> + <td style="text-align: right;">network</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/11314/">archboot 0.4.11-1</a></td> + <td style="text-align: right;">system</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/12552/">kernel26mm 2.6.21.rc4.mm1-1</a></td> + <td style="text-align: right;">kernels</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/12284/">hwdetect 0.8-5</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td colspan="2" style="text-align: right; font-size: x-small;"><br><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/search?sort=-last_update">More...</a></td> + </tr> + </tbody></table> + </div> + <br> + <div class="greybox"> + <h3>Package Repositories</h3> + <table id="repolinks"> + + <tbody><tr> + <th><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Current">Current</a></th> + <td>2007-03-23 20:38:03</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Extra">Extra</a></th> + <td>2007-03-23 18:12:31</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Unstable">Unstable</a></th> + <td>2007-03-21 19:01:19</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Testing">Testing</a></th> + <td>2007-03-23 15:36:36</td> + </tr> + + </tbody></table> + </div> + <br> + <div class="greybox"> + <h3>Releases</h3> + <table id="releases"> + <tbody><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Current">0.8</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/packages/?repo=Current">Voodoo</a></td> + <td style="text-align: right;"><em>pending</em></td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.2.txt">0.7.2</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.2.txt">Gimmick</a></td> + <td style="text-align: right;">2006-05-23</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.1.txt">0.7.1</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.1.txt">Noodle</a></td> + <td style="text-align: right;">2006-01-05</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.txt">0.7</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.7.txt">Wombat</a></td> + <td style="text-align: right;">2005-01-24</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.6.txt">0.6</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.6.txt">Widget</a></td> + <td style="text-align: right;">2004-03-01</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.5.txt">0.5</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.5.txt">Nova</a></td> + <td style="text-align: right;">2003-07-21</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.4.txt">0.4</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.4.txt">Dragon</a></td> + <td style="text-align: right;">2002-12-18</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.3.txt">0.3</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.3.txt">Firefly</a></td> + <td style="text-align: right;">2002-08-07</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.2.txt">0.2</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.2.txt">Vega</a></td> + <td style="text-align: right;">2002-04-17</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.1.txt">0.1</a></td> + <td><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/pkglists/list-0.1.txt">Homer</a></td> + <td style="text-align: right;">2002-03-11</td> + </tr> + </tbody></table> + </div> + <br> + <h3>Documentation:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/docs/arch-install-guide.html">Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://wiki.archlinux.org/">Wiki</a></li> + </ul> + <h3>Support Arch:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/donate/">Donate</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://www.cafeshops.com/archlinux/">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/art/">Logos & Artwork</a></li> + </ul> + <h3>Community Links:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20070324064759/http://www.archlinux.org/mailman/listinfo/">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/irc/">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://planet.archlinux.org/">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://blog.archlinux.org/">Development Blog</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/static/newsletters/">Newsletters</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/projects/">Arch-Based Projects</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/moreforums/">Non-English Forums</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/press/">Press</a></li> + </ul> + <h3>Development:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/developers/">Developers</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://bugs.archlinux.org/">Bug Tracker</a></li> + <li><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/cvs/">CVS</a></li> + </ul> + + </div> + <div class="left"> + + <div id="about" class="box"> + <h2>Welcome to Arch!</h2> + <p> + You've reached the website for <strong>Arch Linux</strong>, a lightweight + and flexible linux distribution that tries to Keep It Simple. + </p><p> + Currently we have official packages optimized for the i686 and x86-64 + architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20070324064759/http://aur.archlinux.org/">community-operated package repository</a> + that grows in size and quality each and every day. + </p><p> + Our strong community is diverse and helpful, and we pride ourselves on + the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20070324064759/http://bbs.archlinux.org/">forums</a> and + <a href="http://web.archive.org/web/20070324064759/http://www.archlinux.org/mailman/listinfo/">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20070324064759/http://wiki.archlinux.org/">wiki</a> + if you want to learn more about Arch. + </p><p style="text-align: right"> + <a href="http://web.archive.org/web/20070324064759/http://archlinux.org/about/"><span style="font-size:x-small">Learn more...</span></a> + </p> + </div> + <br><br> + <div style="float:right;position:relative;bottom:-25px"> + <a href="http://web.archive.org/web/20070324064759/http://archlinux.org/feeds/news/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + </div> + <h2 class="title">Latest News</h2> + <div> + + <br> + <span style="float:right; font-size:x-small">2007-03-23</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/301/">GNOME 2.18 is in testing</a></h4> + <p class="news">GNOME 2.18 has been packaged and is placed into +testing. Some packages are still missing, these are left at the 2.16 +version we have in extra. These packages will be added later this +weekend. Please test this release very careful. I don't expect major +issues with this release, as the changes are not as big as the previous +version when ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-03-18</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/299/">Testing moved to current/extra</a></h4> + <p class="news">The contents of Testing have been moved to the current + and extra repositories today. This means python 2.5, DB 4.5, wxGTK 2.8, + PostgreSQL 8.2 and all the packages that have to be updated for these +updates have been merged into current and extra. As this move involves +many packages which take many megabytes, some mirrors can have problems +catching up ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-03-18</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/300/">Newsletter for March 18, 2007</a></h4> + <p class="news">A bunch new devland stuff in this newsletter. +Hopefully things are looking up. Current: +http://archlinux.org/static/newsletters/newsletter-2007-Mar-18.html +Archive:</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-03-07</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/298/">Newsletter for March 04, 2007</a></h4> + <p class="news">Sorry about not updating sooner. Current: +http://archlinux.org/static/newsletters/newsletter-2007-Mar-04.html +Archive: http://archlinux.org/static/newsletters/</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-03-05</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/297/">kernel26mm returns</a></h4> + <p class="news">The mm kernel is now reinstated, and has been moved to + the [unstable] repo, which is more appropriate to its bleeding edge +nature. A limited selection of compatible external modules is provided, +namely nvidia-mm ati-fglrx-mm ipw3945-mm wlan-ng26-mm If there is +sufficient demand for other modules, I will try to provide them, subject + of course to successful compilation against mm. Contact ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-02-24</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/296/">Voodoo Beta2 ISO release</a></h4> + <p class="news">Hi folks, after one month heavy hacking during the +evenings/weekends on archboot. 0.8 Beta2 Isos are available for i686 and + x86_64. This time only isolinux is used to avoid non booting cd media. - + switched to kernel 2.6.20.1 - to boot the ISO 96 MB RAM are +recommended, it breaks somewhere between 80 - 90 MB RAM. +(calculated like ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-02-18</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/295/">Arch64 Unstable Repo</a></h4> + <p class="news">The 'unstable' repository for Arch64 is now live. You +can enable unstable in pacman.conf. Currently only xfce-svn is in the +repo, but this will be updated soon to include beryl,gaim-svn and other +unstable stuff. As always, use unstable at your own risk. Enjoy! - +(ganja_guru)</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-02-15</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/294/">kernel 2.6.20 series went to current</a></h4> + <p class="news">Hi kernel 2.6.20 series entered current repository, +thanks to the people who tested it. Latest Changes: - reverted +additional framebuffer support - Recent Changes: Upstream Changes Nvidia + Users consider this New_Nvidia_Drivers have fun and report bugs thanks +greetings tpowa</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-02-12</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/293/">Newsletter for February 11, 2007</a></h4> + <p class="news">Current: http://archlinux.org/static/newsletters/newsletter-2007-Feb-11.html Archive: http://archlinux.org/static/newsletters/</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-02-06</span> + <h4 class="news"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/290/">kernel 2.6.20 hits testing</a></h4> + <p class="news">Hi kernel 2.6.20 series is now in testing, it will be +the kernel series for 0.8 release so please test this stuff well before +it can go into current repository. Changes: Console framebuffers added: +--------- - to use the other framebuffers, disable vesa first in boot +manager video=vesa:off - load the correct framebuffer module from +MODULES= in rc.conf - Recent ...</p> + <br> + + <span style="float:right;font-size:x-small"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/news/">More News...</a></span> + <br><br> + </div> + + </div> + + </div> + <div class="foot"> + Copyright © 2002-2006, Judd Vinet <<a href="mailto:jvinet@zeroflux.org">jvinet@zeroflux.org</a>><br><br> + <img src="{% retro_static year "button.png" %}" alt="Arch Linux"> + </div> + +</body></html> diff --git a/retro/templates/retro/index-20080311.html b/retro/templates/retro/index-20080311.html new file mode 100644 index 00000000..89a7de95 --- /dev/null +++ b/retro/templates/retro/index-20080311.html @@ -0,0 +1,392 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1-strict.dtd "> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" href="{% retro_static year "arch.css" %}"> + <link rel="icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + <link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/feeds/packages/"> + + </head> + <body> + + <div id="head_container"> + <div id="title"> + <div id="logo"><a href="http://web.archive.org/web/20070324064759/http://archlinux.org/"><img src="{% retro_static year "logo.png" %}" alt="Arch Logo"></a></div> + <a href="http://web.archive.org/web/20070324064759/http://archlinux.org/"><img src="{% retro_static year "title.png" %}" alt="Arch Linux"></a> + </div> + <div id="main_nav"> + <ul> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/download/">Get Arch</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://aur.archlinux.org/">AUR</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://bugs.archlinux.org/">Bugs</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://wiki.archlinux.org/">Wiki</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://bbs.archlinux.org/">Forums</a></li> + <li class="selected"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/">Home</a></li> + </ul> + </div> + <div id="ads"> + </div> + </div> + <div id="content"> + + <div class="right"> + + <div id="search"> + <form method="get" action="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/search/"> + <p>Package Search: <input name="q" size="20" maxlength="200" type="text"></p> + </form> + </div> + <div id="updates"> + <table width="100%"> + <tbody><tr> + <td><h3>Recent Updates</h3></td> + <td style="vertical-align: top; text-align: right;"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/feeds/packages/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a></td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13284/">filesystem 2008.03-2</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13565/">libpng 1.2.24-3</a></td> + <td style="text-align: right;">lib</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/14687/">opera 9.26-1</a></td> + <td style="text-align: right;">network</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/14812/">firefox3 3.0b4-1</a></td> + <td style="text-align: right;">network</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/837/">drscheme 372-1</a></td> + <td style="text-align: right;">devel</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/3582/">fvwm-devel 2.5.25-1</a></td> + <td style="text-align: right;">x11</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/14751/">mpg123 1.3.1-1</a></td> + <td style="text-align: right;">multimedia</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/2032/">dvd+rw-tools 7.1-1</a></td> + <td style="text-align: right;">system</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/12004/">audacious-plugins 1.4.5-2</a></td> + <td style="text-align: right;">multimedia</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13318/">kernel26 2.6.24.3-3</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13299/">hdparm 8.6-1</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13401/">xfsprogs 2.9.7-1</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13285/">findutils 4.2.33-1</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13651/">php 5.2.5-7</a></td> + <td style="text-align: right;">devel</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/13362/">pacman 3.1.3-1</a></td> + <td style="text-align: right;">base</td> + </tr> + + <tr> + <td colspan="2" style="text-align: right; font-size: x-small;"><br><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/search?sort=-last_update">More...</a></td> + </tr> + </tbody></table> + </div> + <br> + <div class="greybox"> + <h3>Package Repositories</h3> + <table id="repolinks"> + + <tbody><tr> + <th><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">Core</a></th> + <td>2008-03-11 02:36:20</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Extra">Extra</a></th> + <td>2008-03-10 22:11:44</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Testing">Testing</a></th> + <td>2008-03-10 16:46:04</td> + </tr> + + <tr> + <th><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Unstable">Unstable</a></th> + <td>2008-03-10 19:32:42</td> + </tr> + + </tbody></table> + </div> + <br> + <div class="greybox"> + <h3>Releases</h3> + <table id="releases"> + <tbody><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">2007.08-2</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">Don't Panic</a></td> + <td style="text-align: right;">2007-10-07</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">2007.08.1</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">Don't Panic</a></td> + <td style="text-align: right;">2007-09-10</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">2007.08</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">Don't Panic</a></td> + <td style="text-align: right;">2007-08-05</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">2007.05</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/packages/?repo=Core">Duke</a></td> + <td style="text-align: right;">2007-05-17</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.8.txt">0.8</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.8.txt">Voodoo</a></td> + <td style="text-align: right;">2007-03-31</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.2.txt">0.7.2</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.2.txt">Gimmick</a></td> + <td style="text-align: right;">2006-05-23</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.1.txt">0.7.1</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.1.txt">Noodle</a></td> + <td style="text-align: right;">2006-01-05</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.txt">0.7</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.7.txt">Wombat</a></td> + <td style="text-align: right;">2005-01-24</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.6.txt">0.6</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.6.txt">Widget</a></td> + <td style="text-align: right;">2004-03-01</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.5.txt">0.5</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.5.txt">Nova</a></td> + <td style="text-align: right;">2003-07-21</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.4.txt">0.4</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.4.txt">Dragon</a></td> + <td style="text-align: right;">2002-12-18</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.3.txt">0.3</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.3.txt">Firefly</a></td> + <td style="text-align: right;">2002-08-07</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.2.txt">0.2</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.2.txt">Vega</a></td> + <td style="text-align: right;">2002-04-17</td> + </tr><tr> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.1.txt">0.1</a></td> + <td><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/pkglists/list-0.1.txt">Homer</a></td> + <td style="text-align: right;">2002-03-11</td> + </tr> + </tbody></table> + </div> + <br> + <h3>Documentation:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/docs/arch-install-guide.txt">Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://wiki.archlinux.org/">Wiki</a></li> + </ul> + <h3>Support Arch:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/donate/">Donate</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.zazzle.com/archlinux*">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/art/">Logos & Artwork</a></li> + </ul> + <h3>Community Links:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/mailman/listinfo/">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/irc/">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://planet.archlinux.org/">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/static/newsletters/">Newsletters</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/projects/">Arch-Based Projects</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/moreforums/">Non-English Forums</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/press/">Press</a></li> + </ul> + <h3>Development:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/developers/">Developers</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://bugs.archlinux.org/">Bug Tracker</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/cvs/">CVS</a></li> + <li><a href="http://web.archive.org/web/20080311110003/http://projects.archlinux.org/">Projects</a></li> + </ul> + + </div> + <div class="left"> + + <div id="about" class="box"> + <h2>Welcome to Arch!</h2> + <p> + You've reached the website for <strong>Arch Linux</strong>, a lightweight + and flexible linux distribution that tries to Keep It Simple. + </p><p> + Currently we have official packages optimized for the i686 and x86-64 + architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20080311110003/http://aur.archlinux.org/">community-operated package repository</a> + that grows in size and quality each and every day. + </p><p> + Our strong community is diverse and helpful, and we pride ourselves on + the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20080311110003/http://bbs.archlinux.org/">forums</a> and + <a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/mailman/listinfo/">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20080311110003/http://wiki.archlinux.org/">wiki</a> + if you want to learn more about Arch. + </p><p style="text-align: right"> + <a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/about/"><span style="font-size:x-small">Learn more...</span></a> + </p> + </div> + <br><br> + <div style="float:right;position:relative;bottom:-25px"> + <a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/feeds/news/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + </div> + <h2 class="title">Latest News</h2> + <div> + + <br> + <span style="float:right; font-size:x-small">2008-02-25</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/384/">Newsletter for February 25, 2008</a></h4> + <p class="news">Current: +http://www.archlinux.org/static/newsletters/newsletter-2008-Feb-25.html +Archive: http://www.archlinux.org/static/newsletters/</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-02-10</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/383/">Kernel 2.6.24.1 in Core</a></h4> + <p class="news">After a testing phase kernel 2.6.24.1 has been +moved to Core where it replaces version 2.6.23.14. Some of the most +visible changes for users include: * more mac80211-based wireless +drivers added * tickless support for x86_64 * uvesafb; support for ATI +Xpress 200M and Mac framebuffers * ACPI usage in libata * SATA port +multipliers support * NCQ support on ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-02-10</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/382/">Newsletter for February 11, 2008</a></h4> + <p class="news">This one is actually on time! Probably because I + had nothing to do with it... Current: +http://archlinux.org/static/newsletters/newsletter-2008-Feb-11.html +Archive: http://archlinux.org/static/newsletters/</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-23</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/381/">Newsletter for January 21, 2008</a></h4> + <p class="news">I just want to take this space to apologize. +Kensai had the newsletter ready for me early and I (Jason Chu) have not +had time to write the Devland section since then. Current: +http://archlinux.org/static/newsletters/newsletter-2008-Jan-21.html +Archive: http://archlinux.org/static/newsletters/</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-20</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/380/">QT-4 and QT3 moved to [extra]</a></h4> + <p class="news">As announced last year* and after a longer +period of testing, QT versions 3 and 4 have now been moved to [extra]. +At least until the final release of KDE4 there are plenty of packages +which still use version 3 of QT. Therefore a new package called qt3 was +introduced. The dependencies of all packages are updated according to +this ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-12</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/379/">Website theme update</a></h4> + <p class="news">Greetings Archers, After some hard work from +some very dedicated folks, we have re-themed much of the Arch website. +Special thanks to a few key contributions so far: To Thayer for his logo + and re-theme css work, and to Neotuli for his hard work on bringing the + new look to the other Arch sites. Awesome work guys. Thanks also to ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-12</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/378/">Pacman 3.1.0 moving to [core]</a></h4> + <p class="news">Pacman has now been signed off by our developers + as well as sufficiently tested by its users to allow it to move to the +[core] repository. There have been a few minor issues reported, but no +critical issues are known. Please report any bugs to the Pacman Project +on Flyspray or by sending an email to the pacman-dev mailing list ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-09</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/377/">Pacman 3.1.0 in [testing]</a></h4> + <p class="news">Pacman 3.1.0 has been released to testing. It +has been a long time coming, but a lot of work has been put into it by +several contributors over the last 9 months. Note that some options have + changed so your scripts may be incompatible with the new version and +will need some slight modifications. In addition, makepkg and pacman no +...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2008-01-07</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/376/">PostgreSQL Security Update (8.2.6)</a></h4> + <p class="news">There was a critical security advisory for +PostgreSQL today, which is resolved in version 8.2.6. You should update +as soon as possible. Details here.</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2007-12-22</span> + <h4 class="news"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/375/">Logo Contest Results (and Winner!)</a></h4> + <p class="news">I'm sure this is the announcement many of you +have been waiting for. After much discussion about legal issues at hand, + some voting, we are ready to announce the glorious victor of the logo +competition. Drumroll please! The winner is Thayer Williams' Archer +logo, available for your viewing pleasure in submission form here: +http://dev.archlinux.org/~travis/logo-contest/thayer/1-archer.png It +will be some time before ...</p> + <br> + + <span style="float:right;font-size:x-small"><a href="http://web.archive.org/web/20080311110003/http://www.archlinux.org/news/">More News...</a></span> + <br><br> + </div> + + </div> + + </div> + <div class="foot"> + Copyright © 2002-2008 <a href="mailto:jvinet@zeroflux.org" title="contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="contact Aaron Griffin">Aaron Griffin</a>.<br> + The Arch Linux name and logo are recognized trademarks. Some rights reserved. + </div> + +</body></html> diff --git a/retro/templates/retro/index-20090327.html b/retro/templates/retro/index-20090327.html new file mode 100644 index 00000000..e780d78d --- /dev/null +++ b/retro/templates/retro/index-20090327.html @@ -0,0 +1,318 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" href="{% retro_static year "arch.css" %}"> + <link rel="icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + <link rel="shortcut icon" href="{% retro_static year "favicon.ico" %}" type="image/x-icon"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/feeds/packages/"> + + </head> + <body> + + <div id="head_container"> + <div id="title"> + <div id="logo"><h1 id="archtitle"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/" title="Arch Linux (Home)">Arch Linux</a></h1></div> + </div> + <div id="main_nav"> + <ul> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/download/">Download</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://aur.archlinux.org/">AUR</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://bugs.archlinux.org/">Bugs</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://wiki.archlinux.org/">Wiki</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://bbs.archlinux.org/">Forums</a></li> + <li class="selected"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/">Home</a></li> + </ul> + </div> + <div id="ads"> + </div> + </div> + <div id="content"> + + <div class="right"> + + <div id="search"> + <form method="get" action="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/"> + <p>Package Search: <input name="q" size="20" maxlength="200" type="text"></p> + </form> + </div> + <div id="updates"> + <table width="100%"> + <tbody><tr> + <td><h3>Recent Updates</h3></td> + <td style="vertical-align: top; text-align: right;"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/feeds/packages/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a></td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-da/" class="testing">kde-l10n-da 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-es/" class="testing">kde-l10n-es 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-en_gb/" class="testing">kde-l10n-en_gb 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-el/" class="testing">kde-l10n-el 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-de/" class="testing">kde-l10n-de 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-et/" class="testing">kde-l10n-et 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-csb/" class="testing">kde-l10n-csb 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-cs/" class="testing">kde-l10n-cs 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/digikam/" class="testing">digikam 0.10.0-2</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/hugin/" class="testing">hugin 0.7.0-3</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-ar/" class="testing">kde-l10n-ar 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-bg/" class="testing">kde-l10n-bg 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-bn_in/" class="testing">kde-l10n-bn_in 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-ca/" class="testing">kde-l10n-ca 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/testing/x86_64/kde-l10n-eu/" class="testing">kde-l10n-eu 4.2.2-1</a></td> + <td style="text-align: right;">x86_64</td> + </tr> + + <tr> + <td colspan="2" style="text-align: right; font-size: x-small;"><br><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/packages/?sort=-last_update">More...</a></td> + </tr> + </tbody></table> + </div> + <br> + <h3>Documentation:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20090327235558/http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide">Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://wiki.archlinux.org/">Wiki</a></li> + </ul> + <h3>Support Arch:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/donate/">Donate</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.zazzle.com/archlinux*" title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://schwag.archlinux.ca/" title="USB keys, Jewellery, case badges">More Schwag</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/art/">Logos & Artwork</a></li> + </ul> + <h3>Community Links:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/mailman/listinfo/">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/irc/">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://planet.archlinux.org/">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/static/newsletters/">Newsletters</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/projects/">Arch-Based Projects</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/moreforums/">International Communities</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/press/">Press</a></li> + </ul> + <h3>Development:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/developers/">Developers</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/fellows/">Fellows</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://bugs.archlinux.org/">Bug Tracker</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/svn/">SVN</a></li> + <li><a href="http://web.archive.org/web/20090327235558/http://projects.archlinux.org/">Projects</a></li> + </ul> + <a href="http://web.archive.org/web/20090327235558/http://www.sevenl.net/" title="SevenL Networks - Dedicated Arch Linux servers"><img src="{% retro_static year "sevenl_button.png" %}" class="" title="A big Thank You to SevenL Networks for their generous contribution" alt="We would like to express our thanks to SevenL Networks for their generous contribution"></a> + + </div> + <div class="left"> + + <div id="about" class="box"> + <h2>Welcome to Arch!</h2> + <p> + You've reached the website for <strong>Arch Linux</strong>, a lightweight + and flexible Linux® distribution that tries to Keep It Simple. + </p><p> + Currently we have official packages optimized for the i686 and x86-64 + architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20090327235558/http://aur.archlinux.org/">community-operated package repository</a> + that grows in size and quality each and every day. + </p><p> + Our strong community is diverse and helpful, and we pride ourselves on + the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20090327235558/http://bbs.archlinux.org/">forums</a> and + <a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/mailman/listinfo/">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20090327235558/http://wiki.archlinux.org/">wiki</a> + if you want to learn more about Arch. + </p><p style="text-align: right"> + <a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/about/"><span style="font-size:x-small">Learn more...</span></a> + </p> + </div> + <br><br> + <div style="float:right;position:relative;bottom:-25px"> + <a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/feeds/news/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + </div> + <h2 class="title">Latest News</h2> + <div> + + <br> + <span style="float:right; font-size:x-small">2009-03-23</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/439/">ATI catalyst support dropped</a></h4> + <p class="news">As many of you may have noticed, support for the + catalyst ATI Linux driver, has been moved to the AUR (Arch Linux User +Repository). This was partly due to lack of motivation from the +maintainer in charge of the package and lack of support from AMD to the +general Linux ecosystem. AMD has been great to the Linux community, and +...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-03-09</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/438/">Bug Day - Saturday 21st March</a></h4> + <p class="news">On Saturday the 21st of March we will be holding + a bug day to combat the ever increasing number of reports in our bug +tracker. We will clear outdated reports, fix/implement those that +already have patches provided or are trivial to fix/implement and +discuss the pros and cons of implementing some feature requests. A rough + TODO list that you can ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-03-05</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/437/">Newsletter for March, 2009</a></h4> + <p class="news">The Arch Linux Newsletter team is proud to +announce the Newsletter for March 2009. To discuss this newsletter, +click here. To read past issues of the Arch Linux Newsletter, here they +are.</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-03-02</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/436/">xorg-server 1.6.0 in testing</a></h4> + <p class="news">The upcoming version of xorg-server will have a +lot of workarounds and patches removed. Doing so, the package becomes +easier to understand, as even its maintainer has no idea what is +happening anymore. When upgrading to xorg-server-1.6, you will see these + file conflicts on most systems: error: failed to prepare transaction +(conflicting files) xorg-server: +/usr/lib/xorg/modules/extensions/libdri.so exists in filesystem +xorg-server: /usr/lib/xorg/modules/libwfb.so ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-02-18</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/435/">2009.02 ISO Release Update</a></h4> + <p class="news">The original archlinux-2009.02-ftp-i686.img USB +image was broken, a new image (archlinux-2009.02-2-ftp-i686.img) has +been uploaded. We are sorry for any inconvenience this may have caused +you. With one image broken, we also had to create new torrents: We now +use a single torrent per file again and added more mirrors to the +webseeds. All seeders should stop seeding the old torrent ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-02-16</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/434/">2009.02 ISO Release</a></h4> + <p class="news">We proudly announce the release of the new Arch +Linux installation images, version 2009.02. It took us quite a while, +but we think the result is worth it: we added some cool new things and +ironed out some long-lasting imperfections. 2009.02 comes with the +following features: - Kernel 2.6.28 - Ext4 support. Installation can be +done on a ext4 root ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-02-13</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/433/">Newsletter for February, 2009</a></h4> + <p class="news">The Arch Linux Newsletter team is proud to +announce the Newsletter for February 2009. To discuss this newsletter, +click here. To read past issues of the Arch Linux Newsletter, here they +are.</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-01-26</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/431/">KDE 4.2 is out and we are ready!</a></h4> + <p class="news">Today, on January 27th, the KDE team announces +the stable version of KDE 4.2.0, so we have moved all kde-packages from +[testing] to [extra]. We suggest that you exit from KDE before you +update, backup your ~/.kde4 configuration dir and start with a clean +config. Take a look at old plasmoids, they might not work with the new +Plasma. You ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-01-22</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/430/">Release Engineering Team</a></h4> + <p class="news">I'd like to announce a newly formed team made to + manage our ISO releases. The intent here is to provide you with up to +date installation tools and release ISOs based on the kernel's release +schedule. Current Team Members: Aaron Griffin (that's me!) Gerhard +Brauer (GerBra - ISO and installer) Dieter Plaetinck (Dieter@be - +installer/AIF) If you're interested in ISO ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-01-19</span> + <h4 class="news"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/429/">inetutils-1.6-2 in [core]</a></h4> + <p class="news">To replace several orphaned netkit packages that + were unmaintained upstream, we just added inetutils-1.6-2 in the [core] + repo. This new package will provide the following network +clients/daemons: ftp/ftpd rexec/rexecd rlogin/rlogind rsh/rshd +talk/talkd telnet/telnetd rcp. It will be replacing the following +packages: core/netkit-telnet extra/netkit-ftp extra/netkit-rsh On a +related note, netkit-tftp will be remove from the repo in favor of +tftp-hpa. The ...</p> + <br> + + <span style="float:right;font-size:x-small"><a href="http://web.archive.org/web/20090327235558/http://www.archlinux.org/news/">More News...</a></span> + <br><br> + </div> + + </div> + + </div> + <div class="foot"> + Copyright © 2002-2009 <a href="mailto:jvinet@zeroflux.org" title="contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="contact Aaron Griffin">Aaron Griffin</a>.<br> + The Arch Linux name and logo are recognized trademarks. Some rights + reserved.<br> + The registered trademark Linux® is used pursuant to a +sublicense from LMI, the exclusive licensee of Linus Torvalds, owner of +the mark on a world-wide basis. + </div> + +</body></html> diff --git a/retro/templates/retro/index-20100208.html b/retro/templates/retro/index-20100208.html new file mode 100644 index 00000000..b30d4cb4 --- /dev/null +++ b/retro/templates/retro/index-20100208.html @@ -0,0 +1,318 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" type="text/css" href="{% retro_static year "arch.css" %}"> + <link rel="icon" type="image/x-icon" href="{% retro_static year "favicon.ico" %}"> + <link rel="shortcut icon" type="image/x-icon" href="{% retro_static year "favicon.ico" %}"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/feeds/packages/"> + + </head> + <body> + + <div id="head_container"> + <div id="title"> + <div id="logo"><h1 id="archtitle"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/" title="Arch Linux (Home)">Arch Linux</a></h1></div> + </div> + <div id="main_nav"> + + <ul> + <li class="selected"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/">Home</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://bbs.archlinux.org/">Forums</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/">Wiki</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://bugs.archlinux.org/">Bugs</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://aur.archlinux.org/">AUR</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/download/">Download</a></li> + </ul> + + </div> + <div id="dev_nav"> + + </div> + </div> + <div id="content"> + + + <div class="right"> + + <div id="search"> + <form method="get" action="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/"> + <p>Package Search: <input name="q" size="20" maxlength="200" type="text"></p> + </form> + </div> + <div id="updates"> + <table width="100%"> + <tbody><tr> + <td><h3>Recent Updates</h3></td> + <td style="vertical-align: top; text-align: right;"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/feeds/packages/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a></td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/community/x86_64/zim/" class="community">zim 0.43-2</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/community/x86_64/snort/" class="community">snort 2.8.3.2-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/spamassassin-spamc/" class="extra">spamassassin-spamc 3.3.0-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/any/python-gdata/" class="extra">python-gdata 2.0.7-1</a></td> + <td style="text-align: right;">any</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/i686/wine/" class="extra">wine 1.1.38-1</a></td> + <td style="text-align: right;">i686</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/fetchmail/" class="extra">fetchmail 6.3.14-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/mplayer/" class="extra">mplayer 30325-2</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/community/x86_64/exim/" class="community">exim 4.71-1.1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/hwdetect/" class="extra">hwdetect 2010.02-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/spamassassin/" class="extra">spamassassin 3.3.0-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/lighttpd/" class="extra">lighttpd 1.4.26-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/community/any/hgsvn/" class="community">hgsvn 0.1.8-1</a></td> + <td style="text-align: right;">any</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/testing/any/mkinitcpio/" class="testing">mkinitcpio 0.5.99.4-1</a></td> + <td style="text-align: right;">any</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/extra/x86_64/ardour/" class="extra">ardour 2.8.7-1</a></td> + <td style="text-align: right;">i686/x86_64</td> + </tr> + + <tr> + <td><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/community-testing/i686/qtcreator/" class="community-testing">qtcreator 1.3.1-1</a></td> + <td style="text-align: right;">i686</td> + </tr> + + <tr> + <td style="font-size: x-small;"><br><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/feeds/">More Feeds...</a></td> + <td style="text-align: right; font-size: x-small;"><br><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/packages/?sort=-last_update">More Updates...</a></td> + </tr> + </tbody></table> + </div> + <br> + + <h3>Documentation:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide">Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/index.php/Beginners%27_Guide">Beginners' Guide</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/">Wiki</a></li> + </ul> + <h3>Support Arch:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/donate/">Donate</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://schwag.archlinux.ca/" title="USB keys, Jewellery, case badges">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.zazzle.com/archlinux*" title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Schwag via Zazzle</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.freewear.org/?page=list_items&org=Archlinux" title="T-shirts">Schwag via Freewear</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/art/">Logos & Artwork</a></li> + </ul> + <h3>Community Links:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/mailman/listinfo/">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/irc/">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://planet.archlinux.org/">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/static/newsletters/">Newsletters</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/projects/">Arch-Based Projects</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/moreforums/">International Communities</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/index.php/Arch_Linux_Press_Review">Press</a></li> + </ul> + <h3>Development:</h3> + <ul class="links"> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/developers/">Developers</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/trustedusers/">Trusted Users</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/fellows/">Fellows</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://bugs.archlinux.org/">Bug Tracker</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/svn/">SVN</a></li> + <li><a href="http://web.archive.org/web/20100208061823/http://projects.archlinux.org/">Projects</a></li> + </ul> + <a href="http://web.archive.org/web/20100208061823/http://www.velocitynetwork.net/?hosting_by=ArchLinux" title="velocity network"><img src="{% retro_static year "vnet_button.png" %}" class="" title="" alt="velocity network - it's about time"></a> + <a href="http://web.archive.org/web/20100208061823/https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" title="SevenL Networks - Dedicated Arch Linux servers"><img src="{% retro_static year "sevenl_button.png" %}" class="" title="A big Thank You to SevenL Networks for their generous contribution" alt="We would like to express our thanks to SevenL Networks for their generous contribution"></a> + + </div> + <div class="left"> + + <div id="about" class="box"> + <h2>Welcome to Arch!</h2> + <p> + You've reached the website for <strong>Arch Linux</strong>, a lightweight + and flexible Linux® distribution that tries to Keep It Simple. + </p><p> + Currently we have official packages optimized for the i686 and x86-64 + architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20100208061823/http://aur.archlinux.org/">community-operated package repository</a> + that grows in size and quality each and every day. + </p><p> + Our strong community is diverse and helpful, and we pride ourselves on + the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20100208061823/http://bbs.archlinux.org/">forums</a> and + <a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/mailman/listinfo/">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20100208061823/http://wiki.archlinux.org/">wiki</a> + if you want to learn more about Arch. + </p><p style="text-align: right"> + <a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/about/"><span style="font-size:x-small">Learn more...</span></a> + </p> + </div> + <br><br> + <div style="float:right;position:relative;bottom:-25px"> + <a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/feeds/news/"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + </div> + <h2 class="title">Latest News</h2> + <div> + + <br> + <span style="float:right; font-size:x-small">2010-01-30</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/482/">libpng/libjpeg rebuilds move from [testing]</a></h4> + <p class="news">The new versions of libjpeg and libpng required a + rebuild of all dependent packages. The libjpeg/libpng rebuilds are now +complete and are moving from [testing] into the main repos. Due to the +large number of rebuilds required, packages will take a while to +propagate to the mirrors. It is advisable to check the state of your +mirror before updating (https://www.archlinux.de/?page=MirrorStatus). +...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2010-01-26</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/481/">ArchCon2010 registration</a></h4> + <p class="news">Two prominent community members, Dusty and +ralvez have been working hard to bring Arch Linux it's very own +conference. ArchCon 2010 will take place in Toronto, Canada's largest +city, on July 22 and 23. Registration is now open at +http://archcon.archlinux.ca/ and more information can be found on the +ArchCon site at http://archlinux.ca/archcon2010/. ArchCon will feature +talks and tutorials from prominent ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2010-01-23</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/480/">Bug Day: Saturday, February 6</a></h4> + <p class="news">By popular demand, the next Bug Day will be on +Saturday, February 6. People are usually around all day, but you will +certainly find us in the #archlinux-bugs IRC forum in the afternoon and +evening EST. There's a job for everyone! Come help out however you can.</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2010-01-21</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/479/">Hacklab.CL's Arch Linux Orphan's Day</a></h4> + <p class="news">This weekend on January 23rd, Hacklab.CL is +organizing an event called Arch Linux Orphan's Day. This event will +consist of talks and presentations about Arch Linux packaging, covering +the Packaging Guidelines, the AUR, complementary tools, and much more. +The event concludes with a review of the AUR orphan packages and, +hopefully, some new maintainers. This will happen at "KernelHouse" +(Antonia ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2010-01-13</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/478/">Arch Linux Magazine, January 2010</a></h4> + <p class="news">In with a bang: * Get it! * Discuss it! Enjoy!</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-12-29</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/477/">kernel 2.6.32 series moved to the [core] repository</a></h4> + <p class="news">Hi arch community, The new 2.6.32 kernel series +moved to the [core] repository. Upstream changes Arch Linux +bugfixes/feature requests: # added CONFIG_PM_DEBUG # added +CONFIG_MMIOTRACE KMS changes: - changed intel kms enabled by default - +radeon kms is now disabled by default Please use the modeset option to +enable it. - Early userspace KMS support is broken at the moment ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-12-16</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/476/">filesystem-2009.11-1 and LC_COLLATE</a></h4> + <p class="news">The filesystem-2009.11-1 package has removed +LC_COLLATE=C from /etc/profile as this caused incorrect sorting on some +locales (See FS#15250). Any scripts relying on this value should +manually set the LC_COLLATE variable.</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-12-14</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/475/">Next Bug Day: Sun 1/3</a></h4> + <p class="news">When the holidays are over and mid-winter +depressions sets in, Arch Linux will be there for you. On Sunday 1/3, +we'll have our next Bug Day. We've been making progress each month-- +let's surge in 2010! Join us whenever you can; you can find us in the +#archlinux-bugs IRC forum in the afternoon and evening EST. Happy +holidays, bugs-- they ...</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-11-20</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/474/">Next Bug Day: Sun 12/6</a></h4> + <p class="news">The next Bug Day is scheduled for Sunday 12/6. +The bugs will be there all day, so start whenever you want, but you can +find us in the #archlinux-bugs IRC forum in the afternoon and evening +EST. The more the merrier!</p> + <br> + + <br> + <span style="float:right; font-size:x-small">2009-11-18</span> + <h4 class="news"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/473/">MySQL 5.1.40 - configuration file moved</a></h4> + <p class="news">Starting with the mysql 5.1.40 release, the +mysql configuration file resides in the /etc/mysql/ directory and the +pid and sock files are in the /var/run/mysqld/ directory. This is to +comply with the Filesystem Hierarchy Standard.</p> + <br> + + <span style="float:right;font-size:x-small"><a href="http://web.archive.org/web/20100208061823/http://www.archlinux.org/news/">More News...</a></span> + <br><br> + </div> + + </div> + + </div> + <div class="foot"> + Copyright © 2002-2010 <a href="mailto:jvinet@zeroflux.org" title="contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="contact Aaron Griffin">Aaron Griffin</a>.<br> + The Arch Linux name and logo are recognized trademarks. Some rights + reserved.<br> + The registered trademark Linux® is used pursuant to a +sublicense from LMI, the exclusive licensee of Linus Torvalds, owner of +the mark on a world-wide basis. + </div> + +</body></html> diff --git a/retro/templates/retro/index-20110212.html b/retro/templates/retro/index-20110212.html new file mode 100644 index 00000000..db4dfa41 --- /dev/null +++ b/retro/templates/retro/index-20110212.html @@ -0,0 +1,443 @@ +{% load retro_static from retro %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" type="text/css" href="{% retro_static year "archweb.css" %}" media="screen, projection"> + <link rel="stylesheet" type="text/css" href="{% retro_static year "archweb-print.css" %}" media="print"> + <link rel="icon" type="image/x-icon" href="{% retro_static year "favicon.ico" %}"> + <link rel="shortcut icon" type="image/x-icon" href="{% retro_static year "favicon.ico" %}"> + <link rel="search" type="application/opensearchdescription+xml" href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/opensearch/packages/" title="Arch Linux Packages"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/feeds/packages/"> + +</head> +<body class=""> + + + <div id="archnavbar" class="anb-home"> + <div id="archnavbarlogo"><h1><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/" title="Return to the main page">Arch Linux</a></h1></div> + <div id="archnavbarmenu"> + <ul id="archnavbarlist"> + <li id="anb-home"><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/" title="Arch news, packages, projects and more">Home</a></li> + <li id="anb-packages"><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/" title="Arch Package Database">Packages</a></li> + <li id="anb-forums"><a href="http://web.archive.org/web/20110212035546/https://bbs.archlinux.org/" title="Community forums">Forums</a></li> + <li id="anb-wiki"><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li id="anb-bugs"><a href="http://web.archive.org/web/20110212035546/https://bugs.archlinux.org/" title="Report and track bugs">Bugs</a></li> + <li id="anb-aur"><a href="http://web.archive.org/web/20110212035546/https://aur.archlinux.org/" title="Arch Linux User Repository">AUR</a></li> + <li id="anb-download"><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/download/" title="Get Arch Linux">Download</a></li> + </ul> + </div> + </div><!-- #archnavbar --> + + <div id="content"> + <div id="archdev-navbar"> + + </div><!-- #archdev-navbar --> + + + + + <div id="content-left-wrapper"> + <div id="content-left"> + + +<div id="intro" class="box"> + + <h2>A simple, lightweight distribution</h2> + + <p>You've reached the website for <strong>Arch Linux</strong>, a + lightweight and flexible Linux® distribution that tries to Keep It + Simple.</p> + + <p>Currently we have official packages optimized for the i686 and + x86-64 architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20110212035546/https://aur.archlinux.org/" title="Arch User Repository (AUR)"> + community-operated package repository</a> that grows in size and + quality each and every day.</p> + + <p>Our strong community is diverse and helpful, and we pride ourselves + on the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20110212035546/https://bbs.archlinux.org/" title="Arch Forums">forums</a> + and <a href="http://web.archive.org/web/20110212035546/http://mailman.archlinux.org/mailman/listinfo/" title="Arch Mailing Lists">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/" title="Arch Wiki">wiki</a> + if you want to learn more about Arch.</p> + + <p class="readmore"><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/about/" title="Learn more about Arch Linux">Learn more...</a></p> + +</div><!-- #intro --> + +<div id="news"> + + <h3>Latest News <span class="more">(<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/" title="Browse the news archives">more</a>)</span></h3> + + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/feeds/news/" title="Arch News RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/mysql-55-is-now-in-extra/" title="View full article: MySQL 5.5 is now in [extra]">MySQL 5.5 is now in [extra]</a></h4> + <p class="timestamp">2011-02-07</p> + <div class="article-content"><p>MySQL 5.5 is now in [extra]. This is a major version upgrade from the +5.1 editions previously in the repositories. Archive, Blackhole, and +Federated engine support are no longer included in this package, since +they are not heavily used.</p> +<p>After upgrading the MySQL package and restarting the database, you +will need to run <code>mysql_upgrade</code> to ensure your tables, views and +stored procedures are up to date and compatible with MySQL 5.5.</p> +<p>It ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/kde-sc-46-to-extra/" title="View full article: KDE SC 4.6 to [extra]">KDE SC 4.6 to [extra]</a></h4> + <p class="timestamp">2011-01-26</p> + <div class="article-content"><p>KDE announced the availability of +its Software Compilation 4.6. You will find all upstream changes and new + features on their website: http://kde.org/announcements/4.6/. As usual +we provide the latest packages for Arch.</p> +<p>This release offers UPower, UDev and UDisks support that can be used +instead of the deprecated HAL. For that, the hal package is no more a +requirement of kdebase-workspace and can be removed from your system.</p> +<p>KDE PIM ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/minimum-required-kernel-version-increased-1/" title="View full article: Minimum required kernel version increased">Minimum required kernel version increased</a></h4> + <p class="timestamp">2010-12-28</p> + <div class="article-content"><p>The update to glibc-2.12.2-1 +increases the minimum required kernel version to 2.6.27. This kernel +version was chosen as it is currently the oldest kernel with longterm +support upstream. Users of the Arch "kernel26" and "kernel26-lts" +packages are unaffected by this change.</p> +<p>Those wanting to continue the use of an older kernel version will be +required to rebuild the glibc package with the appropriate adjustment +made to the "--enable-kernel" configuration option.</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/python-is-now-python-3/" title="View full article: Python is now Python 3">Python is now Python 3</a></h4> + <p class="timestamp">2010-10-18</p> + <div class="article-content"><p>A major Python update has just been moved from the testing +repositories and will be available on a mirror near you. The default +"python" package is now for the 3.x series while the 2.x series has +been moved to a "python2" package, with python-2.7 having been +scheduled to be the last major release in the python-2.x series.</p> +<p>Since /usr/bin/python will now point to the 3.x binary, any program ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/mirror-status-and-custom-mirror-lists/" title="View full article: Mirror status and custom mirror lists">Mirror status and custom mirror lists</a></h4> + <p class="timestamp">2010-10-07</p> + <div class="article-content"><p>We now regularly poll all official +mirrors and gather statistics such as syncing delay, check duration, +availability, and error conditions. This information is available on the + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/mirrors/status/">mirror status page</a>. Please consult the page for more details on what is collected, how often it runs, and how it works.</p> +<p>In addition, you can now <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/mirrorlist/">update your mirrorlist</a> and choose to have it automatically sorted using the up-to-date mirror status information.</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/pkgstats-round-two-take-your-vote-and-help-improving-arch/" title="View full article: pkgstats round two: take your vote and help improving Arch">pkgstats round two: take your vote and help improving Arch</a></h4> + <p class="timestamp">2010-09-24</p> + <div class="article-content"><p>Two years ago, we introduced <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/pkgstats-contribution-was-never-that-easy/">pkgstats</a>. +This time, after a major revamp, we are re-introducing it to you!</p> +<p>Contributing is as easy as installing the package - a weekly cron job +will take care of the rest. You will be sending us a list of packages +installed on your system, along with the architecture and mirror you +use. This information is anonymous and cannot be used to identify you, +but it will help us prioritize our ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/the-new-arch-linux-ezine/" title="View full article: The new Arch Linux ezine">The new Arch Linux ezine</a></h4> + <p class="timestamp">2010-09-20</p> + <div class="article-content"><p>Announcing the much-anticipated Arch Linux ezine, <a href="http://web.archive.org/web/20110212035546/http://rollingrelease.com/">Rolling Release</a>! + Based on the Ars Technica model, Rolling Release provides an open +platform for sharing news of interest to the Arch community. Check it +out, contribute, and follow us onsite, or via email, RSS, Twitter, or +Identi.ca!</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/true-multilib-for-arch-linux-x86_64/" title="View full article: True multilib for Arch Linux x86_64">True multilib for Arch Linux x86_64</a></h4> + <p class="timestamp">2010-08-27</p> + <div class="article-content"><p>I am happy to announce the availability of the new multilib repository. +At this time, it contains wine, skype and flashplugin. Furthermore, a +multilib compiler is available.</p> +<p>With the launch of the multilib repository all old 'lib32' packages are +being removed from community - the core/extra/community repositories +will be "pure 64 bit" again.</p> +<p>If you want to use the new multilib packages (and most desktop or laptop +users probably do), add the following lines ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/kde-sc-450-moved-to-extra/" title="View full article: KDE SC 4.5.0 moved to [extra]">KDE SC 4.5.0 moved to [extra]</a></h4> + <p class="timestamp">2010-08-24</p> + <div class="article-content"><p>KDE SC 4.5.0 has moved into the [extra] repository. Notable changes +with respect to previous releases are:</p> +<ul> +<li>kdepim has seen no new release, please continue to use version 4.4.5</li> +<li>due to incompatibility with ruby 1.9, ruby kdebindings are not provided</li> +<li>webkit support in konqueror is provided by kwebkitpart</li> +<li>KDM is now started as the kdm user</li> +<li>upstream removed five translations: csb, mai, mk, si and tg</li> +</ul> +<p>The full upstream changelog ...</p></div> + + <h4><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/perl-5121-moved-to-core/" title="View full article: Perl 5.12.1 moved to Core">Perl 5.12.1 moved to Core</a></h4> + <p class="timestamp">2010-08-02</p> + <div class="article-content"><p>The latest version of perl 5.12.1 has been moved to core.</p> +<p>The perl package no longer implements versioned site_perl directories + but the 5.10.1 directories remains for legacy packages for now. Anyone + who custom builds perl modules into site_perl should rebuild them to +use the proper directories.</p></div> + + +</div><!-- #news --> + + + </div><!-- #content_left --> + </div> + + <div id="content-right"> + + +<div id="pkgsearch" class="widget"> + + <form id="pkgsearch-form" method="get" action="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/"> + <fieldset> + <label for="pkgsearch-field">Package Search:</label> + <input id="pkgsearch-field" name="q" size="18" maxlength="200" type="text"> + </fieldset> + </form> + +</div> + +<div id="pkg-updates" class="widget box"> + + <h3>Recent Updates <span class="more">(<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/?sort=-last_update" title="Browse all of the latest packages">more</a>)</span></h3> + + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/feeds/packages/" title="Arch Package Updates RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + + <table> + + + <tbody><tr> + <td class="pkg-name"><span class="extra">time 1.7-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/i686/time/" title="Details for time [extra]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/x86_64/time/" title="Details for time [extra]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">calibre 0.7.45-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/calibre/" title="Details for calibre [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/calibre/" title="Details for calibre [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">python-bsddb 5.0.0-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/python-bsddb/" title="Details for python-bsddb [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/python-bsddb/" title="Details for python-bsddb [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community-testing">python-bsddb 5.1.0-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community-testing/i686/python-bsddb/" title="Details for python-bsddb [community-testing]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community-testing/x86_64/python-bsddb/" title="Details for python-bsddb [community-testing]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="core">db 5.1.25-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/core/i686/db/" title="Details for db [core]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/core/x86_64/db/" title="Details for db [core]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="extra">python2 2.7.1-5</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/i686/python2/" title="Details for python2 [extra]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/x86_64/python2/" title="Details for python2 [extra]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">task 1.9.3-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/task/" title="Details for task [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/task/" title="Details for task [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="extra">bash-completion 1.3-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/any/bash-completion/" title="Details for bash-completion [extra]">any</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="extra">nxserver 3.4.0-8</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/i686/nxserver/" title="Details for nxserver [extra]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/x86_64/nxserver/" title="Details for nxserver [extra]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">gsoap 2.8.1-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/gsoap/" title="Details for gsoap [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/gsoap/" title="Details for gsoap [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">xloadimage 4.1-11</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/xloadimage/" title="Details for xloadimage [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/xloadimage/" title="Details for xloadimage [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="extra">gio-sharp 0.2-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/any/gio-sharp/" title="Details for gio-sharp [extra]">any</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="extra">django 1.2.5-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/extra/any/django/" title="Details for django [extra]">any</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">docky 2.1.0-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/docky/" title="Details for docky [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/docky/" title="Details for docky [community]">x86_64</a> + </td> + </tr> + + + + <tr> + <td class="pkg-name"><span class="community">clang-analyzer 2.8-5</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/i686/clang-analyzer/" title="Details for clang-analyzer [community]">i686</a>/<a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/community/x86_64/clang-analyzer/" title="Details for clang-analyzer [community]">x86_64</a> + </td> + </tr> + + + </tbody></table> +</div> + +<div id="nav-sidebar" class="widget"> + + <h4>Documentation</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" title="Official installation guide">Official Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/Beginners%27_Guide" title="A good place to start for beginners">Unofficial Beginners' Guide</a></li> + </ul> + + <h4>Community</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/http://mailman.archlinux.org/mailman/listinfo/" title="Community and developer mailing lists">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/IRC_Channels" title="Official and regional IRC communities">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://planet.archlinux.org/" title="Arch in the blogosphere">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://rollingrelease.com/" title="Community online magazine">Rolling Release Ezine</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/International_Communities" title="Arch communities in your native language">International Communities</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/Related_Projects" title="Projects that are in some way related to Arch Linux">Related Projects</a></li> + </ul> + + <h4>Support</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/donate/" title="Help support Arch Linux">Donate</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://schwag.archlinux.ca/" title="USB keys, jewellery, case badges">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.zazzle.com/archlinux*" title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Products via Zazzle</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.freewear.org/?page=list_items&org=Archlinux" title="T-shirts">T-shirts via Freewear</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://stuff.lsupport.net/catalog/22763/" title="T-shirts, keychains, bags, mugs, notebooks from a Ukraine retailer">Merchandise via ProstoPrint</a></li> + </ul> + + <h4>Tools</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/mirrorlist/" title="Get a custom mirrorlist from our database">Mirrorlist Updater</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/mirrors/status/" title="Check the status of all known mirrors">Mirror Status</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/differences/" title="See differences in packages between available architectures">Differences by Architecture</a></li> + </ul> + + <h4>Development</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/packages/" title="View/search the package repository database">Packages</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/groups/" title="View the available package groups">Package Groups</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://bugs.archlinux.org/" title="Report/track bugs or make feature requests">Bug Tracker</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/svn/" title="View SVN entries for packages">SVN Repositories</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://projects.archlinux.org/" title="Official Arch projects (git)">Projects in Git</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/DeveloperWiki" title="Developer Wiki articles">DeveloperWiki</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/todolists/" title="Developer Todo Lists">Todo Lists</a></li> + </ul> + + <h4>About</h4> + + <ul> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/ArchLinux:About" title="Learn more about Arch Linux">About Arch</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/download/" title="Get Arch Linux">Download Arch</a></li> + <li><a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/Arch_Linux_Press_Review" title="Arch Linux in the media">Press Coverage</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/art/" title="Arch logos and other artwork for promotional use">Logos & Artwork</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/news/" title="News Archives">News Archives</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/feeds/" title="Various RSS Feeds">RSS Feeds</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/developers/" title="Active developers">Developer Profiles</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/trustedusers/" title="Active Trusted Users (TUs)">Trusted User Profiles</a></li> + <li><a href="http://web.archive.org/web/20110212035546/http://www.archlinux.org/fellows/" title="Retired Developers">Fellows Profiles</a></li> + </ul> + +</div><!-- #nav-sidebar --> + + + +<div id="arch-sponsors" class="widget"> + + <a href="http://web.archive.org/web/20110212035546/http://www.velocitynetwork.net/?hosting_by=ArchLinux" title="Velocity Network"> + <img src="{% retro_static year "vnet_button.png" %}" alt="Velocity Network - It's about time"> + </a> + <a href="http://web.archive.org/web/20110212035546/https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" title="SevenL Networks - Dedicated Arch Linux servers"> + <img src="{% retro_static year "sevenl_button.png" %}" title="A big Thank You to SevenL Networks for their generous contribution" alt="We would like to express our thanks to SevenL Networks for their generous contribution"> + </a> + <a href="http://web.archive.org/web/20110212035546/http://www.airvm.com/ArchLinux" title="AirVM.com - Your Green Technology Partner"> + <img src="{% retro_static year "airvm_button.png" %}" title="AirVM.com - Your Green Technology Partner" alt="AirVM.com - Your Green Technology Partner"> + </a> + +</div> + + + </div><!-- #content_right --> + + + <div id="footer"> + <p>Copyright © 2002-2011 <a href="mailto:jvinet@zeroflux.org" title="Contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="Contact Aaron Griffin">Aaron Griffin</a>.</p> + + <p>The Arch Linux name and logo are recognized + <a href="http://web.archive.org/web/20110212035546/https://wiki.archlinux.org/index.php/DeveloperWiki:TrademarkPolicy" title="Arch Linux Trademark Policy">trademarks</a>. Some rights reserved.</p> + + <p>The registered trademark Linux® is used pursuant to a sublicense from LMI, + the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide basis.</p> + </div><!-- #footer --> + + </div><!-- #content --> + +</body></html> diff --git a/retro/templates/retro/index-2012-03-09.html b/retro/templates/retro/index-2012-03-09.html new file mode 100644 index 00000000..e130b97f --- /dev/null +++ b/retro/templates/retro/index-2012-03-09.html @@ -0,0 +1,485 @@ +{% load retro_static from retro %}<!DOCTYPE html> +<html lang="en"><head> + <title>Arch Linux</title> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" type="text/css" href="{% retro_static year "archweb.css" %}" media="screen, projection"> + <link rel="stylesheet" type="text/css" href="{% retro_static year "archweb-print.css" %}" media="print"> + <link rel="icon" type="image/x-icon" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/static/favicon.ico"> + <link rel="shortcut icon" type="image/x-icon" href="http://web.archive.org/web/20120309124818im_/http://www.archlinux.org/static/favicon.ico"> + <link rel="apple-touch-icon" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/static/logos/apple-touch-icon-57x57.png"> + <link rel="apple-touch-icon" sizes="72x72" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/static/logos/apple-touch-icon-72x72.png"> + <link rel="apple-touch-icon" sizes="114x114" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/static/logos/apple-touch-icon-114x114.png"> + <link rel="search" type="application/opensearchdescription+xml" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/opensearch/packages/" title="Arch Linux Packages"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/feeds/packages/"> + +</head> +<body class=""> + <div id="archnavbar" class="anb-home"> + <div id="archnavbarlogo"><h1><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/" title="Return to the main page">Arch Linux</a></h1></div> + <div id="archnavbarmenu"> + <ul id="archnavbarlist"> + <li id="anb-home"><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/" title="Arch news, packages, projects and more">Home</a></li> + <li id="anb-packages"><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/" title="Arch Package Database">Packages</a></li> + <li id="anb-forums"><a href="http://web.archive.org/web/20120309124818/https://bbs.archlinux.org/" title="Community forums">Forums</a></li> + <li id="anb-wiki"><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li id="anb-bugs"><a href="http://web.archive.org/web/20120309124818/https://bugs.archlinux.org/" title="Report and track bugs">Bugs</a></li> + <li id="anb-aur"><a href="http://web.archive.org/web/20120309124818/https://aur.archlinux.org/" title="Arch Linux User Repository">AUR</a></li> + <li id="anb-download"><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/download/" title="Get Arch Linux">Download</a></li> + </ul> + </div> + </div><!-- #archnavbar --> + + <div id="content"> + <div id="archdev-navbar"> + + </div><!-- #archdev-navbar --> + + + + + <div id="content-left-wrapper"> + <div id="content-left"> + + +<div id="intro" class="box"> + + <h2>A simple, lightweight distribution</h2> + + <p>You've reached the website for <strong>Arch Linux</strong>, a + lightweight and flexible Linux® distribution that tries to Keep It + Simple.</p> + + <p>Currently we have official packages optimized for the i686 and + x86-64 architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20120309124818/https://aur.archlinux.org/" title="Arch User Repository (AUR)"> + community-operated package repository</a> that grows in size and + quality each and every day.</p> + + <p>Our strong community is diverse and helpful, and we pride ourselves + on the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20120309124818/https://bbs.archlinux.org/" title="Arch Forums">forums</a> + and <a href="http://web.archive.org/web/20120309124818/http://mailman.archlinux.org/mailman/listinfo/" title="Arch Mailing Lists">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/" title="Arch Wiki">wiki</a> + if you want to learn more about Arch.</p> + + <p class="readmore"><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/about/" title="Learn more about Arch Linux">Learn more...</a></p> + +</div><!-- #intro --> + +<div id="news"> + + <h3> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/" title="Browse the news archives">Latest News</a> + <span class="arrow"></span> + </h3> + + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/feeds/news/" title="Arch News RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + + + + <h4> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/minimum-kernel-requirement-2632/" title="View full article: Minimum kernel requirement 2.6.32">Minimum kernel requirement 2.6.32</a> + </h4> + <p class="timestamp">2012-02-07</p> + <div class="article-content"><p>From the glibc-2.15-5 package, the minimum required kernel version will +be increased from 2.6.27 to 2.6.32. This reflects the oldest kernel +version still receiving updates upstream.</p></div> + + + + <h4> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/libpnglibtiff-rebuilds-move-from-testing/" title="View full article: libpng/libtiff rebuilds move from [testing]">libpng/libtiff rebuilds move from [testing]</a> + </h4> + <p class="timestamp">2012-02-05</p> + <div class="article-content"><p>Recent releases of libpng and libtiff have required a rebuild of all +packages that depend on them; these have just been moved from [testing] +to the main repos. As usual, remember to fully update your system and +check your unofficial packages (especially the cairo-* packages from +AUR) for required rebuilds.</p> +<p>The update might output messages similar to:</p> +<pre><code>g_module_open() failed for /usr/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so: +libpng14.so.14: cannot open ...</code></pre></div> + + + + <h4> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/arch-linux-fosdem-2012/" title="View full article: Arch Linux @ FOSDEM 2012">Arch Linux @ FOSDEM 2012</a> + </h4> + <p class="timestamp">2012-01-23</p> + <div class="article-content"><p>The <a href="http://web.archive.org/web/20120309124818/http://fosdem.org/">FOSDEM</a> conference takes place on 4/5 February in Brussels, Belgium and our attendance this year is bigger than ever. +On the <a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/FOSDEM">list of Archers coming</a> we find developers Роман Кирилич (Roman Kyrylych), Tom Gundersen, Thomas Bächler, Jan Steffens, Pierre Schmitz and myself.</p> +<p>We're putting together meetups on Friday afternoon, evening and +Saturday evening. Our program is not definitive yet, so to stay up to +date (or make suggestions) check the <a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/FOSDEM#2012">wiki page ...</a></p></div> + + + + <h4> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/kmod-replaces-module-init-tools/" title="View full article: kmod replaces module-init-tools">kmod replaces module-init-tools</a> + </h4> + <p class="timestamp">2012-01-21</p> + <div class="article-content"><p>With module-init-tools being +declared a dead project by its current maintainer, a new project has +stepped up to take its place: kmod. This is intended to be a drop-in +replacement, though deprecated functionality in module-init-tools has +not been reimplemented.</p> +<p>If, upon upgrade, pacman moves <code>/etc/modprobe.d/modprobe.conf</code> + to a .pacsave, you should move it back. This file, and any other config + read by module-init-tools, is still read by kmod. However, the kmod +package ...</p></div> + + + + <h4> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/pacman-4-moves-to-core/" title="View full article: pacman 4 moves to [core]">pacman 4 moves to [core]</a> + </h4> + <p class="timestamp">2012-01-16</p> + <div class="article-content"><p>Pacman 4 has landed in <code>[core]</code>! Thanks to 24 contributors producing 893 commits, you'll find many <a href="http://web.archive.org/web/20120309124818/http://projects.archlinux.org/pacman.git/tree/NEWS" title="NEWS">new features</a>. + The one explicitly worth calling out is PGP signing. However, until the + last few details regarding database signing and keyring distribution +are ironed out, this is disabled in pacman's default config. If you're +interested trying out package verification, please refer to the +documentation on the wiki about <a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/Pacman-key" title="pacman-key">pacman-key</a> or <a href="http://web.archive.org/web/20120309124818/http://allanmcrae.com/2011/12/pacman-package-signing-4-arch-linux/" title="pacman-package-signing">Allan's blog post</a>.</p> +<p>As ...</p></div> + + + + + <h3> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/" title="Browse the news archives">Older News</a> + <span class="arrow"></span> + </h3> + <dl class="newslist"> + + <dt>2012-01-02</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/users-of-unofficial-kernels-must-enable-devtmpfs-support/" title="View full article: Users of unofficial kernels must enable devtmpfs support">Users of unofficial kernels must enable devtmpfs support</a> + </dd> + + + + + + <dt>2011-12-20</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/filesystem-upgrade-manual-intervention-required/" title="View full article: filesystem upgrade - manual intervention required">filesystem upgrade - manual intervention required</a> + </dd> + + + + + + <dt>2011-10-24</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/wiki-and-bbs-downtime/" title="View full article: wiki and bbs downtime">wiki and bbs downtime</a> + </dd> + + + + + + <dt>2011-10-22</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/initscripts-update-manual-intervention-required/" title="View full article: initscripts update - manual intervention required">initscripts update - manual intervention required</a> + </dd> + + + + + + <dt>2011-10-06</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/hostname-utility-moved-from-net-tools-to-inetutils/" title="View full article: Hostname utility moved from net-tools to inetutils">Hostname utility moved from net-tools to inetutils</a> + </dd> + + + + + + <dt>2011-10-01</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/gnome-320-in-extra/" title="View full article: GNOME 3.2.0 in extra">GNOME 3.2.0 in extra</a> + </dd> + + + + + + <dt>2011-09-15</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/texlive-2011-update/" title="View full article: TeXLive 2011 update">TeXLive 2011 update</a> + </dd> + + + + + + <dt>2011-08-20</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/20110819-installation-media/" title="View full article: 2011.08.19 installation media">2011.08.19 installation media</a> + </dd> + + + + + + <dt>2011-08-14</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/bug-day-sunday-august-21st/" title="View full article: Bug day: Sunday, August 21st">Bug day: Sunday, August 21st</a> + </dd> + + + + + + <dt>2011-08-07</dt> + <dd> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/changes-to-kernel-package-and-filenames/" title="View full article: Changes to kernel package and filenames">Changes to kernel package and filenames</a> + </dd> + + </dl> + + + + +</div><!-- #news --> + + + </div><!-- #content_left --> + </div> + + <div id="content-right"> + + +<div id="pkgsearch" class="widget"> + + <form id="pkgsearch-form" method="get" action="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/"> + <fieldset> + <label for="pkgsearch-field">Package Search:</label> + <input id="pkgsearch-field" name="q" size="18" maxlength="200" type="text"> + </fieldset> + </form> + +</div> + +<div id="pkg-updates" class="widget box"> + + <h3>Recent Updates <span class="more">(<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/?sort=-last_update" title="Browse all of the latest packages">more</a>)</span></h3> + + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/feeds/packages/" title="Arch Package Updates RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed"></a> + + <table> + + <tbody><tr> + <td class="pkg-name"><span class="testing">samba 3.6.3-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/i686/samba/" title="Details for samba [testing]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/x86_64/samba/" title="Details for samba [testing]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">nvidia-lts 295.20-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/i686/nvidia-lts/" title="Details for nvidia-lts [extra]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/x86_64/nvidia-lts/" title="Details for nvidia-lts [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="core">linux-lts 3.0.23-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/core/i686/linux-lts/" title="Details for linux-lts [core]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/core/x86_64/linux-lts/" title="Details for linux-lts [core]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="core">nfs-utils 1.2.5-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/core/i686/nfs-utils/" title="Details for nfs-utils [core]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/core/x86_64/nfs-utils/" title="Details for nfs-utils [core]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">blueman 1.23-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/i686/blueman/" title="Details for blueman [community]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/x86_64/blueman/" title="Details for blueman [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="testing">freetype2 2.4.9-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/i686/freetype2/" title="Details for freetype2 [testing]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/x86_64/freetype2/" title="Details for freetype2 [testing]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">midori 0.4.4-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/i686/midori/" title="Details for midori [community]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/x86_64/midori/" title="Details for midori [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">ext4magic 0.3.0-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/i686/ext4magic/" title="Details for ext4magic [community]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/x86_64/ext4magic/" title="Details for ext4magic [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">python-sqlalchemy 0.7.5-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/i686/python-sqlalchemy/" title="Details for python-sqlalchemy [community]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/x86_64/python-sqlalchemy/" title="Details for python-sqlalchemy [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="testing">subversion 1.7.4-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/i686/subversion/" title="Details for subversion [testing]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/x86_64/subversion/" title="Details for subversion [testing]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="testing">krb5 1.10.1-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/i686/krb5/" title="Details for krb5 [testing]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/x86_64/krb5/" title="Details for krb5 [testing]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">libcroco 0.6.4-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/i686/libcroco/" title="Details for libcroco [extra]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/x86_64/libcroco/" title="Details for libcroco [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">gif2png 2.5.7-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/i686/gif2png/" title="Details for gif2png [extra]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/extra/x86_64/gif2png/" title="Details for gif2png [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">clementine 1.0.1-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/i686/clementine/" title="Details for clementine [community]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/community/x86_64/clementine/" title="Details for clementine [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="testing">libgphoto2 2.4.13-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/i686/libgphoto2/" title="Details for libgphoto2 [testing]">i686</a>/<a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/testing/x86_64/libgphoto2/" title="Details for libgphoto2 [testing]">x86_64</a> + </td> + </tr> + + </tbody></table> +</div> + +<div id="nav-sidebar" class="widget"> + + <h4>Documentation</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" title="Official installation guide">Official Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/Beginners%27_Guide" title="A good place to start for beginners">Unofficial Beginners' Guide</a></li> + </ul> + + <h4>Community</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/http://mailman.archlinux.org/mailman/listinfo/" title="Community and developer mailing lists">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/IRC_Channels" title="Official and regional IRC communities">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://planet.archlinux.org/" title="Arch in the blogosphere">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/International_Communities" title="Arch communities in your native language">International Communities</a></li> + </ul> + + <h4>Support</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/donate/" title="Help support Arch Linux">Donate</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://schwag.archlinux.ca/" title="USB keys, jewellery, case badges">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.zazzle.com/archlinux*" title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Products via Zazzle</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.freewear.org/?page=list_items&org=Archlinux" title="T-shirts">T-shirts via Freewear</a></li> + </ul> + + <h4>Tools</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/mirrorlist/" title="Get a custom mirrorlist from our database">Mirrorlist Updater</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/mirrors/status/" title="Check the status of all known mirrors">Mirror Status</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/packages/differences/" title="See differences in packages between available architectures">Differences Reports</a> + <img src="{% retro_static year "new.png" %}" alt="New"></li> + </ul> + + <h4>Development</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/http://projects.archlinux.org/" title="Official Arch projects (git)">Projects in Git</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/svn/" title="View SVN entries for packages">SVN Repositories</a></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/DeveloperWiki" title="Developer Wiki articles">Developer Wiki</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/groups/" title="View the available package groups">Package Groups</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/todolists/" title="Developer Todo Lists">Todo Lists</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/releng/feedback/" title="Releng Testbuild Feedback">Releng Testbuild Feedback</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/visualize/" title="View visualizations">Visualizations</a> + <img src="{% retro_static year "new.png" %}" alt="New"></li> + </ul> + + <h4>More Resources</h4> + + <ul> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/master-keys/" title="Package/Database signing master keys">Signing Master Keys</a> + <img src="{% retro_static year "new.png" %}" alt="New"></li> + <li><a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/Arch_Linux_Press_Review" title="Arch Linux in the media">Press Coverage</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/art/" title="Arch logos and other artwork for promotional use">Logos & Artwork</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/news/" title="News Archives">News Archives</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/feeds/" title="Various RSS Feeds">RSS Feeds</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/developers/" title="Active developers">Developer Profiles</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/trustedusers/" title="Active Trusted Users (TUs)">Trusted User Profiles</a></li> + <li><a href="http://web.archive.org/web/20120309124818/http://www.archlinux.org/fellows/" title="Retired Developers">Fellows Profiles</a></li> + </ul> + +</div><!-- #nav-sidebar --> + +<div id="home-donate-button" class="widget"> + <a href="http://web.archive.org/web/20120309124818/https://co.clickandpledge.com/Default.aspx?WID=47294"> + <img src="{% retro_static year "CP_EN_BK_S_001.gif" %}" alt="Donate via Click&Pledge to Arch Linux" title="Donate via Click&Pledge to Arch Linux"> + </a> +</div> + +<div id="arch-sponsors" class="widget"> + + <a href="http://web.archive.org/web/20120309124818/http://www.velocitynetwork.net/?hosting_by=ArchLinux" title="Velocity Network"> + <img src="{% retro_static year "vnet_button.png" %}" alt="Velocity Network - It's about time"> + </a> + <a href="http://web.archive.org/web/20120309124818/https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" title="SevenL Networks - Dedicated Arch Linux servers"> + <img src="{% retro_static year "sevenl_button.png" %}" title="A big Thank You to SevenL Networks for their generous contribution" alt="We would like to express our thanks to SevenL Networks for their generous contribution"> + </a> + <a href="http://web.archive.org/web/20120309124818/http://www.airvm.com/ArchLinux" title="AirVM.com - Your Green Technology Partner"> + <img src="{% retro_static year "airvm_button.png" %}" title="AirVM.com - Your Green Technology Partner" alt="AirVM.com - Your Green Technology Partner"> + </a> + +</div> + + + </div><!-- #content_right --> + + + <div id="footer"> + <p>Copyright © 2002-2012 <a href="mailto:jvinet@zeroflux.org" title="Contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="Contact Aaron Griffin">Aaron Griffin</a>.</p> + + <p>The Arch Linux name and logo are recognized + <a href="http://web.archive.org/web/20120309124818/https://wiki.archlinux.org/index.php/DeveloperWiki:TrademarkPolicy" title="Arch Linux Trademark Policy">trademarks</a>. Some rights reserved.</p> + + <p>The registered trademark Linux® is used pursuant to a sublicense from LMI, + the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide basis.</p> + </div><!-- #footer --> + + </div><!-- #content --> + +</body></html> diff --git a/retro/templates/retro/index-2013-03-07.html b/retro/templates/retro/index-2013-03-07.html new file mode 100644 index 00000000..10e7002d --- /dev/null +++ b/retro/templates/retro/index-2013-03-07.html @@ -0,0 +1,482 @@ +{% load retro_static from retro %}<!DOCTYPE html> +<html lang="en"><head> + <meta charset="utf-8"> + <title>Arch Linux</title> + <link rel="stylesheet" type="text/css" href="{% retro_static year "archweb.css" %}" media="screen, projection"> + <link rel="icon" type="image/x-icon" href="{% retro_static year "favicon.29302f683ff8.ico" %}"> + <link rel="shortcut icon" type="image/x-icon" href="{% retro_static year "favicon.29302f683ff8.ico" %}"> + <link rel="apple-touch-icon" href="{% retro_static year "apple-touch-icon-57x57.0cd0ab3349e2.png" %}"> + <link rel="apple-touch-icon" sizes="72x72" href="{% retro_static year "apple-touch-icon-72x72.e502bac6368f.png" %}"> + <link rel="apple-touch-icon" sizes="114x114" href="{% retro_static year "apple-touch-icon-114x114.343cca8f850e.png" %}"> + <link rel="apple-touch-icon" sizes="144x144" href="{% retro_static year "apple-touch-icon-144x144.38cf584757c3.png" %}"> + <link rel="search" type="application/opensearchdescription+xml" href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/opensearch/packages/" title="Arch Linux Packages"> + +<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/feeds/news/"> +<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/feeds/packages/"> + +</head> +<body class=""> + <div id="archnavbar" class="anb-home"> + <div id="archnavbarlogo"><h1><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/" title="Return to the main page">Arch Linux</a></h1></div> + <div id="archnavbarmenu"> + <ul id="archnavbarlist"> + <li id="anb-home"><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/" title="Arch news, packages, projects and more">Home</a></li> + <li id="anb-packages"><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/" title="Arch Package Database">Packages</a></li> + <li id="anb-forums"><a href="http://web.archive.org/web/20130403064440/https://bbs.archlinux.org/" title="Community forums">Forums</a></li> + <li id="anb-wiki"><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li id="anb-bugs"><a href="http://web.archive.org/web/20130403064440/https://bugs.archlinux.org/" title="Report and track bugs">Bugs</a></li> + <li id="anb-aur"><a href="http://web.archive.org/web/20130403064440/https://aur.archlinux.org/" title="Arch Linux User Repository">AUR</a></li> + <li id="anb-download"><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/download/" title="Get Arch Linux">Download</a></li> + </ul> + </div> + </div> + <div id="content"> + <div id="archdev-navbar"> + + </div> + + + <div id="content-left-wrapper"> + <div id="content-left"> + + +<div id="intro" class="box"> + <h2>A simple, lightweight distribution</h2> + + <p>You've reached the website for <strong>Arch Linux</strong>, a + lightweight and flexible Linux® distribution that tries to Keep It + Simple.</p> + + <p>Currently we have official packages optimized for the i686 and + x86-64 architectures. We complement our official package sets with a + <a href="http://web.archive.org/web/20130403064440/https://aur.archlinux.org/" title="Arch User Repository (AUR)"> + community-operated package repository</a> that grows in size and + quality each and every day.</p> + + <p>Our strong community is diverse and helpful, and we pride ourselves + on the range of skillsets and uses for Arch that stem from it. Please + check out our <a href="http://web.archive.org/web/20130403064440/https://bbs.archlinux.org/" title="Arch Forums">forums</a> + and <a href="http://web.archive.org/web/20130403064440/https://mailman.archlinux.org/mailman/listinfo/" title="Arch Mailing Lists">mailing lists</a> + to get your feet wet. Also glance through our <a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/" title="Arch Wiki">wiki</a> + if you want to learn more about Arch.</p> + + <p class="readmore"><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/about/" title="Learn more about Arch Linux">Learn more...</a></p> +</div> + +<div id="news"> + <h3> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/" title="Browse the news archives">Latest News</a> + <span class="arrow"></span> + </h3> + + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/feeds/news/" title="Arch News RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed" height="16" width="16"></a> + + + <h4> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/" title="View full article: MariaDB replaces MySQL in repositories">MariaDB replaces MySQL in repositories</a> + </h4> + <p class="timestamp">2013-03-25</p> + <div class="article-content"> + <p>MariaDB is now officially our default implementation of MySQL. MariaDB is <a href="http://web.archive.org/web/20130403064440/https://kb.askmonty.org/en/mariadb-vs-mysql-compatibility/">almost</a> + a drop in replacement, so an upgrade should be possible with minimum +hassle. However, due to remaining compatibility concerns, an automatic +replace is not done.</p> +<p>It is recommended for all users to upgrade. MySQL will be dropped from the repositories to the AUR in a month.</p> +<p>Users who want to switch will need to install <code>mariadb</code>, <code>libmariadbclient</code> or <code>mariadb-clients</code> and execute <code>mysql_upgrade</code> in order to migrate their systems.</p> +<p>Migration example:</p> +<pre><code># systemctl stop mysqld +# pacman -S mariadb libmariadbclient mariadb-clients +# systemctl start mysqld +# mysql_upgrade -p +</code></pre> +<p><code>percona-server</code> is another MySQL fork available in +[community]. It should be closer to Oracle MySQL Enterprise, but is +missing the new features included in MariaDB.</p> +<p>Together with <code>mysql 5.5.30-7</code> in [extra], all packages +depending on it have been rebuilt against their MariaDB counterparts. +Other package maintainers should move their dependencies to the MariaDB +packages.</p> +<p>More information can be found on our <a href="http://web.archive.org/web/20130403064440/https://mailman.archlinux.org/pipermail/arch-dev-public/2013-February/024478.html">mailing list</a>.</p> + + </div> + + <h4> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/qt4-replaces-qt/" title="View full article: qt4 replaces qt">qt4 replaces qt</a> + </h4> + <p class="timestamp">2013-03-01</p> + <div class="article-content"> + <p>A new <code>qt4</code> package is in [extra]. This replaces the current <code>qt</code> package.</p> +<p>All packages depending on <code>qt</code> need to be rebuilt to depend on <code>qt4</code>. We have done this for all official packages, but you will need to rebuild packages installed from the AUR that depend on <code>qt</code>.</p> +<p>Qt 5.x is now also available in [extra]. When you install both <code>qt5-base</code> and <code>qt4</code> + any Qt tool will refer to the 5.x version. We provide *-qt4 symlinks so + you can explicitly force the 4.x version when you need it.</p> + </div> + + <h4> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/changes-to-lvm/" title="View full article: Changes to LVM">Changes to LVM</a> + </h4> + <p class="timestamp">2013-02-12</p> + <div class="article-content"> + <p>With <code>lvm2 2.02.98-3</code>, we now utilize <code>lvmetad</code> to activate LVM volumes automatically. This implies the following changes:</p> +<ul> +<li>The <code>lvm2</code> initramfs hook now requires the <code>udev</code> hook.</li> +<li>The <code>use_lvmetad = 1</code> must be set in <code>/etc/lvm/lvm.conf</code>. This is the default now - if you have a <code>lvm.conf.pacnew</code> file, you <strong>must</strong> merge this change.</li> +<li>You can restrict the volumes that are activated automatically by setting the <code>auto_activation_volume_list</code> in <code>/etc/lvm/lvm.conf</code>. If in doubt, leave this option <strong>commented out</strong>.</li> +<li>If you need monitoring (needed for snapshots), run <code>systemctl enable lvm-monitoring.service</code>.</li> +<li>The <code>lvmwait</code> kernel command line ...</li></ul> + </div> + + <h4> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/final-sysvinit-deprecation-warning/" title="View full article: Final sysvinit deprecation warning">Final sysvinit deprecation warning</a> + </h4> + <p class="timestamp">2013-02-04</p> + <div class="article-content"> + <p>As previously announced, <code>initscripts</code> are no longer receiving any +testing and support has been dropped from various packages. Any users +still using them should switch to <code>systemd</code>.</p> +<p><code>initscripts</code>, <code>sysvinit</code> and the various <code>rc</code> scripts are being removed +from the repositories to avoid any confusion about their status.</p> + </div> + + <h4> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/update-filesystem-201301-1-and-glibc-217-2-together/" title="View full article: Update filesystem-2013.01-1 and glibc-2.17-2 together">Update filesystem-2013.01-1 and glibc-2.17-2 together</a> + </h4> + <p class="timestamp">2013-01-26</p> + <div class="article-content"> + <p>Due to moving of the /lib symlink from the glibc package to the more +appropriate filesystem package, it is required to update glibc-2.17-2 +and filesystem-2013.01-1 together. This will happen automatically when +you run "pacman -Syu". Remember, partial updates are not supported and never use the "--force" option...</p> +<p>A potential issue with the upgrade on x86_64 is finding conflicting +files in /usr/lib64. All Arch Linux packages that had files in this +directory have been updated, so update these individually first. Any +AUR packages with files in this directory should be updated to install +them in /usr/lib.</p> + </div> + + <h3> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/" title="Browse the news archives">Older News</a> + <span class="arrow"></span> + </h3> + <dl class="newslist"> + + <dt>2012-12-01</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/december-time-for-a-new-install-medium/" title="View full article: December: time for a new install medium">December: time for a new install medium</a> + </dd> + + + <dt>2012-11-04</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/end-of-initscripts-support/" title="View full article: End of initscripts support">End of initscripts support</a> + </dd> + + + <dt>2012-11-02</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/november-release-of-install-media-available/" title="View full article: November release of install media available">November release of install media available</a> + </dd> + + + <dt>2012-11-01</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/bug-squashing-day-saturday-17th-november/" title="View full article: Bug Squashing Day: Saturday 17th November">Bug Squashing Day: Saturday 17th November</a> + </dd> + + + <dt>2012-10-30</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/consolekit-replaced-by-logind/" title="View full article: ConsoleKit replaced by logind">ConsoleKit replaced by logind</a> + </dd> + + + <dt>2012-10-13</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/systemd-is-now-the-default-on-new-installations/" title="View full article: systemd is now the default on new installations">systemd is now the default on new installations</a> + </dd> + + + <dt>2012-10-07</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/install-medium-20121006-introduces-systemd/" title="View full article: Install medium 2012.10.06 introduces systemd">Install medium 2012.10.06 introduces systemd</a> + </dd> + + + <dt>2012-09-08</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/new-install-medium-20120907/" title="View full article: New install medium 2012.09.07">New install medium 2012.09.07</a> + </dd> + + + <dt>2012-09-06</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/fontconfig-2101-update-manual-intervention-required/" title="View full article: Fontconfig 2.10.1 update - manual intervention required">Fontconfig 2.10.1 update - manual intervention required</a> + </dd> + + + <dt>2012-08-11</dt> + <dd> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/netcfg-289-drops-initscripts-compatibility/" title="View full article: netcfg-2.8.9 drops deprecated rc.conf compatibility">netcfg-2.8.9 drops deprecated rc.conf compatibility</a> + </dd> + </dl> + +</div> + + + </div> + </div> + <div id="content-right"> + + +<div id="pkgsearch" class="widget"> + <form id="pkgsearch-form" method="get" action="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/"> + <fieldset> + <label for="pkgsearch-field">Package Search:</label> + <input autocomplete="off" id="pkgsearch-field" name="q" size="18" maxlength="200" type="text"> + </fieldset> + </form> +</div> + +<div id="pkg-updates" class="widget box"> + <h3>Recent Updates <span class="more">(<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/?sort=-last_update" title="Browse all of the latest packages">more</a>)</span></h3> + + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/feeds/packages/" title="Arch Package Updates RSS Feed" class="rss-icon"><img src="{% retro_static year "rss.png" %}" alt="RSS Feed" height="16" width="16"></a> + + <table> + + <tbody><tr> + <td class="pkg-name"><span class="extra">firefox 20.0-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/i686/firefox/" title="Details for firefox [extra]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/x86_64/firefox/" title="Details for firefox [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">firefox-i18n 20.0-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/any/firefox-i18n/" title="Details for firefox-i18n [extra]">any</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="testing">nvidia-utils 313.26-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/testing/i686/nvidia-utils/" title="Details for nvidia-utils [testing]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/testing/x86_64/nvidia-utils/" title="Details for nvidia-utils [testing]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">rust 0.6-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/rust/" title="Details for rust [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/rust/" title="Details for rust [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">murmur 1.2.3-13</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/murmur/" title="Details for murmur [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/murmur/" title="Details for murmur [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">0ad a13-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/0ad/" title="Details for 0ad [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/0ad/" title="Details for 0ad [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">0ad-data a13-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/any/0ad-data/" title="Details for 0ad-data [community]">any</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">nginx 1.2.8-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/nginx/" title="Details for nginx [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/nginx/" title="Details for nginx [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">sxiv 1.1-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/sxiv/" title="Details for sxiv [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/sxiv/" title="Details for sxiv [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">vtk 5.10.1-7</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/vtk/" title="Details for vtk [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/vtk/" title="Details for vtk [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">openmpi 1.6.4-2</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/i686/openmpi/" title="Details for openmpi [extra]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/x86_64/openmpi/" title="Details for openmpi [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">hexchat 2.9.5-3</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/hexchat/" title="Details for hexchat [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/hexchat/" title="Details for hexchat [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">libwebp 0.3.0-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/i686/libwebp/" title="Details for libwebp [extra]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/x86_64/libwebp/" title="Details for libwebp [extra]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="community">pcsc-perl 1.4.13-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/i686/pcsc-perl/" title="Details for pcsc-perl [community]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/community/x86_64/pcsc-perl/" title="Details for pcsc-perl [community]">x86_64</a> + </td> + </tr> + + <tr> + <td class="pkg-name"><span class="extra">live-media 2013.04.01-1</span></td> + <td class="pkg-arch"> + <a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/i686/live-media/" title="Details for live-media [extra]">i686</a>/<a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/extra/x86_64/live-media/" title="Details for live-media [extra]">x86_64</a> + </td> + </tr> + + </tbody></table> +</div> + + + +<div id="nav-sidebar" class="widget"> + <h4>Documentation</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" title="Official installation guide">Official Installation Guide</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/Beginners%27_Guide" title="A good place to start for beginners">Unofficial Beginners' Guide</a></li> + </ul> + + <h4>Community</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://mailman.archlinux.org/mailman/listinfo/" title="Community and developer mailing lists">Mailing Lists</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/IRC_Channels" title="Official and regional IRC communities">IRC Channels</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://planet.archlinux.org/" title="Arch in the blogosphere">Planet Arch</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/International_Communities" title="Arch communities in your native language">International Communities</a></li> + </ul> + + <h4>Support</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/donate/" title="Help support Arch Linux">Donate</a></li> + <li><a href="http://web.archive.org/web/20130403064440/http://schwag.archlinux.ca/" title="USB keys, jewellery, case badges">Arch Schwag</a></li> + <li><a href="http://web.archive.org/web/20130403064440/http://www.zazzle.com/archlinux*" title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Products via Zazzle</a></li> + <li><a href="http://web.archive.org/web/20130403064440/http://www.freewear.org/?page=list_items&org=Archlinux" title="T-shirts">T-shirts via Freewear</a></li> + </ul> + + <h4>Tools</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/mirrorlist/" title="Get a custom mirrorlist from our database">Mirrorlist Updater</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/mirrors/" title="See a listing of all available mirrors">Mirror List</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/mirrors/status/" title="Check the status of all known mirrors">Mirror Status</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/packages/differences/" title="See differences in packages between available architectures">Differences Reports</a></li> + </ul> + + <h4>Development</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://projects.archlinux.org/" title="Official Arch projects (git)">Projects in Git</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/svn/" title="View SVN entries for packages">SVN Repositories</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/DeveloperWiki" title="Developer Wiki articles">Developer Wiki</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/groups/" title="View the available package groups">Package Groups</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/todo/" title="Developer Todo Lists">Todo Lists</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/visualize/" title="View visualizations">Visualizations</a></li> + </ul> + + <h4>More Resources</h4> + + <ul> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/master-keys/" title="Package/Database signing master keys">Signing Master Keys</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/Arch_Linux_Press_Review" title="Arch Linux in the media">Press Coverage</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/art/" title="Arch logos and other artwork for promotional use">Logos & Artwork</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/news/" title="News Archives">News Archives</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/feeds/" title="Various RSS Feeds">RSS Feeds</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/developers/" title="Active developers">Developer Profiles</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/trustedusers/" title="Active Trusted Users (TUs)">Trusted User Profiles</a></li> + <li><a href="http://web.archive.org/web/20130403064440/https://www.archlinux.org/fellows/" title="Retired Developers">Fellows Profiles</a></li> + </ul> + +</div> + +<div id="home-donate-button" class="widget"> + <a href="http://web.archive.org/web/20130403064440/https://co.clickandpledge.com/Default.aspx?WID=47294"> + <img src="{% retro_static year "click_and_pledge.png" %}" alt="Donate via Click&Pledge to Arch Linux" title="Donate via Click&Pledge to Arch Linux" height="34" width="210"> + </a> +</div> + +<div id="arch-sponsors" class="widget"> + <a href="http://web.archive.org/web/20130403064440/http://www.velocitynetwork.net/?hosting_by=ArchLinux" title="Velocity Network"> + <img src="{% retro_static year "vnet_button.png" %}" alt="Velocity Network - It's about time" height="58" width="252"> + </a> + <a href="http://web.archive.org/web/20130403064440/http://www.airvm.com/ArchLinux" title="AirVM.com - Your Green Technology Partner"> + <img src="{% retro_static year "airvm_button.png" %}" alt="AirVM.com - Your Green Technology Partner" height="58" width="252"> + </a> +</div> + + + </div> + + <div id="footer"> + <p>Copyright © 2002-2013 <a href="mailto:jvinet@zeroflux.org" title="Contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="Contact Aaron Griffin">Aaron Griffin</a>.</p> + + <p>The Arch Linux name and logo are recognized + <a href="http://web.archive.org/web/20130403064440/https://wiki.archlinux.org/index.php/DeveloperWiki:TrademarkPolicy" title="Arch Linux Trademark Policy">trademarks</a>. Some rights reserved.</p> + + <p>The registered trademark Linux® is used pursuant to a sublicense from LMI, + the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide basis.</p> + </div> + </div> + +<div id="konami" style="display:none;"></div> + +<script type="text/javascript" src="{% retro_static year "jquery.js" %}"></script> +<script type="text/javascript"> +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '<ul class="pkgsearch-typeahead"></ul>', + items: 10 + }).attr('autocomplete', 'off'); +} +function setupKonami() { + var konami = new Konami(function() { + $('#konami').html('<img src="{% retro_static year "vector_tux.864e6cdcc23e.png" %}" alt=""/>'); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} +$(document).ready(function() { + $.ajax({ url: "{% retro_static year "bootstrap-typeahead.min.1aacd3d7f4db.js" %}", cache: true, dataType: "script", success: setupTypeahead }); + $.ajax({ url: "{% retro_static year "konami.min.e165c814457d.js" %}", cache: true, dataType: "script", success: setupKonami }); +}); +</script> + +<ul class="pkgsearch-typeahead"></ul></body></html> diff --git a/retro/templatetags/__init__.py b/retro/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/retro/templatetags/__init__.py diff --git a/retro/templatetags/retro.py b/retro/templatetags/retro.py new file mode 100644 index 00000000..c7fd9f00 --- /dev/null +++ b/retro/templatetags/retro.py @@ -0,0 +1,13 @@ +from django import template +from django.contrib.staticfiles.storage import staticfiles_storage + +register = template.Library() + + +@register.simple_tag +def retro_static(year, path): + """Like the built-in {% static %} tag but with a little extra magic.""" + full_path = "%s/%s" % (year, path) + return staticfiles_storage.url(full_path) + +# vim: set ts=4 sw=4 et: diff --git a/retro/tests.py b/retro/tests.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/retro/tests.py diff --git a/retro/views.py b/retro/views.py new file mode 100644 index 00000000..7301a97e --- /dev/null +++ b/retro/views.py @@ -0,0 +1,33 @@ +from django.http import Http404 +from django.shortcuts import render +from django.views.decorators.cache import cache_page + + +RETRO_YEAR_MAP = { + 2002: 'index-20020328.html', + 2003: 'index-20030330.html', + 2004: 'index-20040327.html', + 2005: 'index-20050328.html', + 2006: 'index-20060328.html', + 2007: 'index-20070324.html', + 2008: 'index-20080311.html', + 2009: 'index-20090327.html', + 2010: 'index-20100208.html', + 2011: 'index-20110212.html', + 2012: 'index-2012-03-09.html', + 2013: 'index-2013-03-07.html', +} + + +@cache_page(1800) +def retro_homepage(request, year): + year = int(year) + template = RETRO_YEAR_MAP.get(year, None) + if template is None: + raise Http404 + context = { + 'year': year, + } + return render(request, 'retro/%s' % template, context) + +# vim: set ts=4 sw=4 et: diff --git a/settings.py b/settings.py index ea87c2cd..071735cf 100644 --- a/settings.py +++ b/settings.py @@ -1,21 +1,30 @@ import os -# Django settings for archweb project. - -## Import local settings -from local_settings import * +# Django settings for parabolaweb project. ## Set the debug values +DEBUG = False TEMPLATE_DEBUG = DEBUG +DEBUG_TOOLBAR = False + +## Notification admins +ADMINS = () # Set managers to admins MANAGERS = ADMINS +# Package out-of-date emails for orphans +NOTIFICATIONS = ['dev@lists.parabola.nu'] + # Full path to the data directory DEPLOY_PATH = os.path.dirname(os.path.realpath(__file__)) -# Local time zone for this installation. All choices can be found here: -# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE -TIME_ZONE = 'US/Eastern' +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +TIME_ZONE = 'UTC' # Language code for this installation. All choices can be found here: # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes @@ -25,84 +34,79 @@ DEFAULT_CHARSET = 'utf-8' SITE_ID = 1 -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = False - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale -USE_L10N = False - # Default date format in templates for 'date' filter DATE_FORMAT = 'Y-m-d' +DATETIME_FORMAT = 'Y-m-d H:i' -# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a -# trailing slash. -# Examples: "http://foo.com/media/", "/media/". -ADMIN_MEDIA_PREFIX = '/media/admin_media/' - -# login url +# Login URL configuration LOGIN_URL = '/login/' LOGIN_REDIRECT_URL = '/' -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - 'django.template.loaders.eggs.load_template_source', - 'django.template.loaders.app_directories.load_template_source', -) +# Set django's User stuff to use our profile model +AUTH_PROFILE_MODULE = 'devel.UserProfile' # We add a processor to determine if the request is secure or not TEMPLATE_CONTEXT_PROCESSORS = ( 'django.contrib.auth.context_processors.auth', 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', 'django.contrib.messages.context_processors.messages', 'main.context_processors.secure', + 'main.context_processors.branding', +) + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates". + # Always use forward slashes, even on Windows. + '%s/templates' % DEPLOY_PATH, +) + +TEMPLATE_LOADERS = ( + 'django_jinja.loaders.FileSystemLoader', + 'django_jinja.loaders.AppLoader', ) -# This bug is a real bummer: -# http://code.djangoproject.com/ticket/14105 +# Send templates matching the following to the Jinja2 engine +DEFAULT_JINJA2_TEMPLATE_EXTENSION = '.jinja' + MIDDLEWARE_CLASSES = ( - 'main.middleware.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.http.ConditionalGetMiddleware', - 'django.middleware.doc.XViewMiddleware', - 'django.middleware.cache.FetchFromCacheMiddleware', ) +# Base of the URL hierarchy ROOT_URLCONF = 'urls' -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates". - # Always use forward slashes, even on Windows. - '%s/templates' % DEPLOY_PATH, -) +# URL to serve static files +STATIC_URL = '/static/' -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.eggs.Loader', - 'django.template.loaders.app_directories.Loader', -) +# Location to collect static files +STATIC_ROOT = os.path.join(DEPLOY_PATH, 'collected_static') -# Enable caching templates in production environments -if not TEMPLATE_DEBUG: - TEMPLATE_LOADERS = ( - ('django.template.loaders.cached.Loader', TEMPLATE_LOADERS), - ) +# Look for more static files in these locations +STATICFILES_DIRS = ( + os.path.join(DEPLOY_PATH, 'sitestatic'), +) -# Set django's User stuff to use our profile model -# format is app.model -AUTH_PROFILE_MODULE = 'main.UserProfile' +# Static files backend that allows us to use far future Expires headers +STATICFILES_STORAGE = 'main.storage.MinifiedStaticFilesStorage' +# Configure where messages should reside MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' +# Session configuration SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' +SESSION_COOKIE_HTTPONLY = True + +# Clickjacking protection +X_FRAME_OPTIONS = 'DENY' + +# Use new test runner +TEST_RUNNER = 'django.test.runner.DiscoverRunner' INSTALLED_APPS = ( 'django.contrib.auth', @@ -112,15 +116,111 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.sitemaps', 'django.contrib.admin', - 'django.contrib.markup', - 'main', # contains shared models and libs + 'django.contrib.staticfiles', + 'django_countries', + 'django_jinja', + + 'main', 'mirrors', 'news', 'packages', 'todolists', 'devel', 'public', - 'south', # database migration support + 'releng', + 'visualize', + 'retro', ) +# Logging configuration for not getting overspammed +LOGGING = { + 'version': 1, + 'filters': { + 'ratelimit': { + '()': 'main.log.RateLimitFilter', + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['ratelimit'], + 'class': 'django.utils.log.AdminEmailHandler', + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + } + }, +} + +## Server used for linking to PGP keysearch results +PGP_SERVER = 'pgp.mit.edu' +PGP_SERVER_SECURE = True + +# URL to fetch a current list of available ISOs +ISO_LIST_URL = 'https://repo.parabola.nu/iso/' + +# URL to the PXE netboot instructions +PXEBOOT_URL = 'https://repo.parabola.nu/pxeboot/' + +# URL for SVN access for fetching commit messages (note absence of packages or +# community bit on the end, repo.svn_root is appended) +#SVN_BASE_URL = 'svn://svn.archlinux.org/' + +# URL for linking to mailing lists +MAILMAN_BASE_URL = 'https://lists.parabola.nu/' + +# URL for linking to the bugtracker +BUGTRACKER_URL = 'https://labs.parabola.nu/' + +# URL for linking to the release engineering/iso project on the bugtracker +BUGTRACKER_RELENG_URL = 'https://labs.parabola.nu/projects/isos' + +# URL for linking to projects in git +PROJECTS_URL = 'https://projects.parabola.nu' + +# Trackers used for ISO download magnet links +TORRENT_TRACKERS = ( + 'udp://tracker.publicbt.com:80', + 'udp://tracker.openbittorrent.com:80', + 'udp://tracker.istole.it:80', +) + +DOMAIN_RE = r'^(.+\.)?parabola(\.nu|gnulinux\.org)$' + +BRANDING_APPNAME = 'parabolaweb' +BRANDING_DISTRONAME = 'Parabola GNU/Linux-libre' +BRANDING_SHORTNAME = 'Parabola' +BRANDING_SLUG = 'parabola' +BRANDING_WIKINAME = 'ParabolaWiki' +BRANDING_EMAIL = 'Parabola Website Notification <nobody@parabola.nu>' +BRANDING_OSEARCH_TAGS = 'gnu linuxlibre parabola package software' + +# Shorten some names just a bit +COUNTRIES_OVERRIDE = { + 'GB': 'United Kingdom', + 'US': 'United States', +} + +## Import local settings +from local_settings import * + +# Enable caching templates in production environments +if not TEMPLATE_DEBUG: + TEMPLATE_LOADERS = ( + ('django.template.loaders.cached.Loader', TEMPLATE_LOADERS), + ) + JINJA2_BYTECODE_CACHE_ENABLE = True + +# Enable the debug toolbar if requested +if DEBUG_TOOLBAR: + MIDDLEWARE_CLASSES = \ + [ 'debug_toolbar.middleware.DebugToolbarMiddleware' ] + \ + list(MIDDLEWARE_CLASSES) + + INSTALLED_APPS = list(INSTALLED_APPS) + [ 'debug_toolbar' ] + # vim: set ts=4 sw=4 et: diff --git a/sitemaps.py b/sitemaps.py index e321fe85..03ad9254 100644 --- a/sitemaps.py +++ b/sitemaps.py @@ -1,23 +1,42 @@ +from datetime import datetime, timedelta +from pytz import utc + from django.contrib.sitemaps import Sitemap +from django.core.urlresolvers import reverse + from main.models import Package from news.models import News -from packages.utils import get_group_info +from packages.utils import get_group_info, get_split_packages_info +from releng.models import Release +from todolists.models import Todolist -class PackagesSitemap(Sitemap): - changefreq = "weekly" - priority = "0.5" +class PackagesSitemap(Sitemap): def items(self): - return Package.objects.select_related('arch', 'repo').all() - return Package.objects.all() + return Package.objects.normal().only( + 'pkgname', 'last_update', 'files_last_update', + 'repo__name', 'repo__testing', 'repo__staging', + 'arch__name').order_by() def lastmod(self, obj): return obj.last_update + def changefreq(self, obj): + if obj.repo.testing or obj.repo.staging: + return "daily" + return "weekly" + + def priority(self, obj): + if obj.repo.testing: + return "0.4" + if obj.repo.staging: + return "0.1" + return "0.5" + class PackageFilesSitemap(PackagesSitemap): - changefreq = "monthly" - priority = "0.3" + changefreq = "weekly" + priority = "0.1" def location(self, obj): return PackagesSitemap.location(self, obj) + 'files/' @@ -40,14 +59,129 @@ class PackageGroupsSitemap(Sitemap): return '/groups/%s/%s/' % (obj['arch'], obj['name']) +class SplitPackagesSitemap(Sitemap): + changefreq = "weekly" + priority = "0.3" + + def items(self): + return get_split_packages_info() + + def lastmod(self, obj): + return obj['last_update'] + + def location(self, obj): + return '/packages/%s/%s/%s/' % ( + obj['repo'].name.lower(), obj['arch'], obj['pkgbase']) + + class NewsSitemap(Sitemap): - changefreq = "never" - priority = "0.7" + def __init__(self): + now = datetime.utcnow().replace(tzinfo=utc) + self.one_day_ago = now - timedelta(days=1) + self.one_week_ago = now - timedelta(days=7) + + def items(self): + return News.objects.all().defer('content', 'guid', 'title').order_by() + + def lastmod(self, obj): + return obj.last_modified + + def priority(self, obj): + if obj.last_modified > self.one_week_ago: + return "0.9" + return "0.8" + + def changefreq(self, obj): + if obj.last_modified > self.one_day_ago: + return 'daily' + if obj.last_modified > self.one_week_ago: + return 'weekly' + return 'yearly' + + +class RecentNewsSitemap(NewsSitemap): + def items(self): + now = datetime.utcnow().replace(tzinfo=utc) + cutoff = now - timedelta(days=30) + return super(RecentNewsSitemap, self).items().filter(postdate__gte=cutoff) + + +class ReleasesSitemap(Sitemap): + changefreq = "monthly" def items(self): - return News.objects.all() + return Release.objects.all().defer('info', 'torrent_data').order_by() def lastmod(self, obj): - return obj.postdate + return obj.last_modified + + def priority(self, obj): + if obj.available: + return "0.6" + return "0.2" + + +class TodolistSitemap(Sitemap): + priority = "0.4" + + def __init__(self): + now = datetime.utcnow().replace(tzinfo=utc) + self.two_weeks_ago = now - timedelta(days=14) + + def items(self): + return Todolist.objects.all().defer('raw').order_by() + + def lastmod(self, obj): + return obj.last_modified + + def changefreq(self, obj): + if obj.last_modified > self.two_weeks_ago: + return 'weekly' + return 'monthly' + + +class BaseSitemap(Sitemap): + DEFAULT_PRIORITY = 0.7 + + base_viewnames = ( + ('index', 1.0, 'hourly'), + ('packages-search', 0.8, 'hourly'), + ('page-download', 0.8, 'monthly'), + ('page-keys', 0.8, 'weekly'), + ('news-list', 0.7, 'weekly'), + ('groups-list', 0.5, 'weekly'), + ('mirror-status', 0.4, 'hourly'), + 'page-about', + 'page-art', + 'page-svn', + 'page-donate', + 'feeds-list', + 'mirror-list', + 'mirror-status', + 'mirrorlist', + 'packages-differences', + ('releng-test-overview', 0.3, 'monthly'), + 'releng-release-list', + 'visualize-index', + ) + + def items(self): + return self.base_viewnames + + def location(self, obj): + name = obj + if isinstance(obj, tuple): + name = obj[0] + return reverse(name) + + def priority(self, obj): + if isinstance(obj, tuple): + return obj[1] + return self.DEFAULT_PRIORITY + + def changefreq(self, obj): + if isinstance(obj, tuple): + return obj[2] + return 'monthly' # vim: set ts=4 sw=4 et: diff --git a/sitestatic/1984.png b/sitestatic/1984.png Binary files differnew file mode 100644 index 00000000..fbca6924 --- /dev/null +++ b/sitestatic/1984.png diff --git a/sitestatic/airvm_button.png b/sitestatic/airvm_button.png Binary files differnew file mode 100644 index 00000000..0acadc9c --- /dev/null +++ b/sitestatic/airvm_button.png diff --git a/sitestatic/archnavbar/archnavbar.css b/sitestatic/archnavbar/archnavbar.css new file mode 100644 index 00000000..4fcd6cc6 --- /dev/null +++ b/sitestatic/archnavbar/archnavbar.css @@ -0,0 +1,34 @@ +/* + * ARCH GLOBAL NAVBAR + * We're forcing all generic selectors with !important + * to help prevent other stylesheets from interfering. + */ + +/* container for the entire bar */ +#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #000 !important; border-bottom: 5px #787DAB solid !important; } +#archnavbarlogo { float: left !important; margin: -5px 0 0 0 !important; padding: 0 !important; height: 50px !important; width: 324px !important; background: url('archlogo.png') no-repeat !important; } + +/* move the heading/paragraph text offscreen */ +#archnavbarlogo p { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } +#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } + +/* make the link the same size as the logo */ +#archnavbarlogo a { display: block !important; height: 50px !important; width: 324px !important; } + +/* display the list inline, float it to the right and style it */ +#archnavbar ul { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } +#archnavbar ul li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } + +/* style the links */ +#archnavbar ul li a { color: #999; font-weight: bold !important; text-decoration: none !important; } +#archnavbar ul li a:hover { color: white !important; text-decoration: underline !important; } + +/* END MAIN NAVBAR STYLES */ + +/* highlight current website in the navbar */ +li.anb-selected a, +#archnavbar.anb-home ul li#anb-home a, +#archnavbar.anb-packages ul li#anb-packages a, +#archnavbar.anb-download ul li#anb-download a { + color: white !important; +} diff --git a/sitestatic/archweb.css b/sitestatic/archweb.css new file mode 100644 index 00000000..851f17ad --- /dev/null +++ b/sitestatic/archweb.css @@ -0,0 +1,1113 @@ +/* + * Font sizing based on 16px browser defaults (use em): + * 14px = 0.875em + * 13px = 0.812em + * 12px = 0.75em + * 11px = 0.6875em + */ + +@import url("archnavbar/archnavbar.css"); + +/* simple reset */ +* { + margin: 0; + padding: 0; + line-height: 1.4; +} + +/* general styling */ +body { + min-width: 650px; + background: #f6f9fc; + color: #222; + font: normal 100% sans-serif; + text-align: center; +} + +p { + margin: .33em 0 1em; +} + +ol, +ul { + margin-bottom: 1em; + padding-left: 2em; +} + + ul { + list-style: square; + } + +code { + font: 1.2em monospace; + background: #ffd; + padding: 0.15em 0.25em; +} + +pre { + font: 1.2em monospace; + border: 1px solid #bdb; + background: #dfd; + padding: 0.5em; + margin: 1em; +} + + pre code { + display: block; + background: none; + overflow: auto; + } + +blockquote { + margin: 1.5em 2em; +} + +input { + vertical-align: middle; +} + +select[multiple] { + padding: 1px 0; +} + + select[multiple] option { + padding: 0 0.5em 0 0.3em; + } + +input[type=submit] { + padding: 0 0.6em; +} + +.clear { + clear: both; +} + +.hide { + display: none; +} + +hr { + border: none; + border-top: 1px solid #888; +} + +img { + border: 0; +} + +/* scale fonts down to a sane default (16 * .812 = 13px) */ +#content { + font-size: 0.812em; +} + +/* link style */ +a { + text-decoration: none; +} + + a:link, + th a:visited { + color: #07b; + } + + a:visited { + color: #666; + } + + a:hover { + text-decoration: underline; + color: #666; + } + + a:active { + color: #e90; + } + +/* special anchor elements */ +a.headerlink { + visibility: hidden; + padding-left: 0.5em; +} + +h3:hover > a.headerlink { + visibility: visible; +} + +/* headings */ +h2 { + font-size: 1.5em; + margin-bottom: 0.5em; + border-bottom: 1px solid #888; +} + +h3 { + font-size: 1.25em; + margin-top: .5em; +} + +h4 { + font-size: 1.15em; + margin-top: 1em; +} + +h5 { + font-size: 1em; + margin-top: 1em; +} + +/* general layout */ +#content { + width: 95%; + margin: 0 auto; + text-align: left; +} + +#content-left-wrapper { + float: left; + width: 100%; /* req to keep content above sidebar in source code */ +} + +#content-left { + margin: 0 340px 0 0; +} + +#content-right { + float: left; + width: 300px; + margin-left: -300px; +} + +div.box { + margin-bottom: 1.5em; + padding: 0.65em; + background: #ecf2f5; + border: 1px solid #bcd; +} + +#footer { + clear: both; + margin: 2em 0 1em; +} + + #footer p { + margin: 0; + text-align: center; + font-size: 0.85em; + } + +/* alignment */ +div.center, +table.center, +img.center { + width: auto; + margin-left: auto; + margin-right: auto; +} + +p.center, +td.center, +th.center { + text-align: center; +} + +/* table generics */ +table { + width: 100%; + border-collapse: collapse; +} + + table .wrap { + white-space: normal; + } + +th, +td { + white-space: nowrap; + text-align: left; +} + + th { + vertical-align: middle; + font-weight: bold; + } + + td { + vertical-align: top; + } + +/* table pretty styles */ +table.pretty1 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bcd; +} + + .pretty1 th { + padding: 0.35em; + background: #e4eeff; + border: 1px solid #bcd; + } + + .pretty1 td { + padding: 0.35em; + border: 1px dotted #bcd; + } + +table.pretty2 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bbb; +} + + .pretty2 th { + padding: 0.35em; + background: #eee; + border: 1px solid #bbb; + } + + .pretty2 td { + padding: 0.35em; + border: 1px dotted #bbb; + } + +table.compact { + width: auto; +} + + .compact td { + padding: 0.25em 0 0.25em 1.5em; + } + + +/* definition lists */ +dl { + clear: both; +} + + dl dt, + dl dd { + margin-bottom: 4px; + padding: 8px 0 4px; + font-weight: bold; + border-top: 1px dotted #bbb; + } + + dl dt { + color: #333; + float:left; + padding-right:15px; + } + +/* forms and input styling */ +form p { + margin: 0.5em 0; +} + +fieldset { + border: 0; +} + +label { + width: 12em; + vertical-align: top; + display: inline-block; + font-weight: bold; +} + +input[type=text], +input[type=password], +textarea { + padding: 0.10em; +} + +form.general-form label, +form.general-form .form-help { + width: 10em; + vertical-align: top; + display: inline-block; +} + +form.general-form input[type=text], +form.general-form textarea { + width: 45%; +} + +/* archdev navbar */ +#archdev-navbar { + margin: 1.5em 0; +} + + #archdev-navbar ul { + list-style: none; + margin: -0.5em 0; + padding: 0; + } + + #archdev-navbar li { + display: inline; + margin: 0; + padding: 0; + font-size: 0.9em; + } + + #archdev-navbar li a { + padding: 0 0.5em; + color: #07b; + } + +/* error/info messages (x pkg is already flagged out-of-date, etc) */ +#sys-message { + width: 35em; + text-align: center; + margin: 1em auto; + padding: 0.5em; + background: #fff; + border: 1px solid #f00; +} + + #sys-message p { + margin: 0; + } + +ul.errorlist { + color: red; +} + +form ul.errorlist { + margin: 0.5em 0; +} + +/* JS sorting via tablesorter */ +table th.tablesorter-header { + padding-right: 20px; + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} + +table thead th.tablesorter-headerAsc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +} + +table thead th.tablesorter-headerDesc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); +} + +table thead th.sorter-false { + background-image: none; + cursor: default; +} + +/** + * PAGE SPECIFIC STYLES + */ + +/* home: introduction */ +#intro p.readmore { + margin: -0.5em 0 0 0; + font-size: .9em; + text-align: right; +} + +/* home: news */ +#news { + margin-top: 1.5em; +} + + #news h3 { + float: left; + padding-bottom: .5em + } + + #news div { + margin-bottom: 1em; + } + + #news div p { + margin-bottom: 0.5em; + } + + #news .more { + font-weight: normal; + } + + #news .rss-icon { + float: right; + margin-top: 1em; + } + + #news h4 { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; + } + + #news .timestamp { + float: right; + font-size: 0.85em; + margin: -1.8em 0.5em 0 0; + } + +/* home: arrowed headings */ +#news h3 a { + display: block; + background: #787DAB; + font-size: 15px; + padding: 2px 10px; + color: white; +} + + #news a:active { + color: white; + } + +h3 span.arrow { + display: block; + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #787DAB; + margin: 0 auto; + font-size: 0; + line-height: 0px; +} + +/* home: pkgsearch box */ +#pkgsearch { + padding: 1em 0.75em; + background: #787DAB; + color: #fff; + border: 1px solid #08b; +} + + #pkgsearch label { + width: auto; + padding: 0.1em 0; + } + + #pkgsearch input { + width: 10em; + float: right; + font-size: 1em; + color: #000; + background: #fff; + border: 1px solid #09c; + } + + .pkgsearch-typeahead { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + padding: 0.15em 0.1em; + margin: 0; + min-width: 10em; + font-size: 0.812em; + text-align: left; + list-style: none; + background-color: #f6f9fc; + border: 1px solid #09c; + } + + .pkgsearch-typeahead li a { + color: #000; + } + + .pkgsearch-typeahead li.active a { + color: #07b; + } + +/* home: recent pkg updates */ +#pkg-updates h3 { + margin: 0 0 0.3em; +} + + #pkg-updates .more { + font-weight: normal; + } + + #pkg-updates .rss-icon { + float: right; + margin: -2em 0 0 0; + } + + #pkg-updates table { + margin: 0; + } + + #pkg-updates td.pkg-name { + white-space: normal; + } + + #pkg-updates td.pkg-arch { + text-align: right; + } + + #pkg-updates span.testing { + font-style: italic; + } + + #pkg-updates span.staging { + font-style: italic; + color: #ff8040; + } + +/* home: sidebar navigation */ +#nav-sidebar ul { + list-style: none; + margin: 0.5em 0 0.5em 1em; + padding: 0; +} + +/* home: sponsor banners */ +#arch-sponsors img { + padding: 0.3em 0; +} + +/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ +div.widget { + margin-bottom: 1.5em; +} + +/* home: other stuff */ +#konami { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + opacity: 0.6; +} + +/* feeds page */ +#rss-feeds .rss { + padding-right: 20px; + background: url(rss.png) top right no-repeat; +} + +/* artwork: logo images */ +#artwork img.inverted { + background: #333; + padding: 0; +} + +#artwork div.imagelist img { + display: inline; + margin: 0.75em; +} + +/* news: article list */ +.news-nav { + float: right; + margin-top: -2.2em; +} + + .news-nav .prev, + .news-nav .next { + margin: 0 1em; + } + +/* news: article pages */ +div.news-article .article-info { + margin: 0; + color: #999; +} + +/* news: add/edit article */ +#newsform { + width: 60em; +} + + #newsform input[type=text], + #newsform textarea { + width: 75%; + } + +/* todolists: list */ +.todolist-nav { + float: right; + margin-top: -2.2em; +} + + .todolist-nav .prev, + .todolist-nav .next { + margin: 0 1em; + } + +/* donate: donor list */ +#donor-list ul { + width: 100%; +} + /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ + #donor-list li { + float: left; + width: 25%; + min-width: 20em; + } + +/* download page */ +#arch-downloads h3 { + border-bottom: 1px dotted #bbb; +} + +/* pkglists/devlists */ +table.results { + font-size: 0.846em; + border-top: 1px dotted #999; + border-bottom: 1px dotted #999; +} + + .results th { + padding: 0.5em 1em 0.25em 0.25em; + border-bottom: 1px solid #999; + white-space: nowrap; + background-color:#fff; + } + + .results td { + padding: .3em 1em .3em 3px; + } + + .results tr.odd { + background: #fff; + } + + .results tr.even { + background: #e4eeff; + } + + .results .flagged { + color: red; + } + + .results tr.empty td { + text-align: center; + } + +/* pkglist: layout */ +#pkglist-about { + margin-top: 1.5em; +} + +/* pkglist: results navigation */ +.pkglist-stats { + font-size: 0.85em; +} + +#pkglist-results .pkglist-nav { + float: right; + margin-top: -2.2em; +} + +.pkglist-nav .prev { + margin-right: 1em; +} + +.pkglist-nav .next { + margin-right: 1em; +} + +/* search fields and other filter selections */ +.filter-criteria { + margin-bottom: 1em; +} + +.filter-criteria h3 { + font-size: 1em; + margin-top: 0; +} + +.filter-criteria div { + float: left; + margin-right: 1.65em; + font-size: 0.85em; +} + +.filter-criteria legend { + display: none; +} + +.filter-criteria label { + width: auto; + display: block; + font-weight: normal; +} + +/* pkgdetails: details links that float on the right */ +#pkgdetails #detailslinks { + float: right; +} + + #pkgdetails #detailslinks h4 { + margin-top: 0; + margin-bottom: 0.25em; + } + + #pkgdetails #detailslinks ul { + list-style: none; + padding: 0; + margin-bottom: 0; + font-size: 0.846em; + } + + #pkgdetails #detailslinks > div { + padding: 0.5em; + margin-bottom: 1em; + background: #eee; + border: 1px solid #bbb; + } + +#pkgdetails #actionlist .flagged { + color: red; + font-size: 0.9em; + font-style: italic; +} + +/* pkgdetails: pkg info */ +#pkgdetails #pkginfo { + width: auto; +} + + #pkgdetails #pkginfo td { + padding: 0.25em 0 0.25em 1.5em; + } + + #pkgdetails #pkginfo .userdata { + font-size: 0.85em; + padding: 0.5em; + } + +/* pkgdetails: flag package */ +#flag-pkg-form label { + width: 10em; +} + +#flag-pkg-form textarea, +#flag-pkg-form input[type=text] { + width: 45%; +} + +/* pkgdetails: deps, required by and file lists */ +#pkgdetails #metadata { + clear: both; +} + +#pkgdetails #metadata h3 { + background: #555; + color: #fff; + font-size: 1em; + margin-bottom: 0.5em; + padding: 0.2em 0.35em; +} + +#pkgdetails #metadata ul { + list-style: none; + margin: 0; + padding: 0; +} + +#pkgdetails #metadata li { + padding-left: 0.5em; +} + +#pkgdetails #metadata p { + padding-left: 0.5em; +} + +#pkgdetails #metadata .message { + font-style: italic; +} + +#pkgdetails #metadata br { + clear: both; +} + +#pkgdetails #pkgdeps { + float: left; + width: 48%; + margin-right: 2%; +} + +#pkgdetails #metadata .virtual-dep, +#pkgdetails #metadata .testing-dep, +#pkgdetails #metadata .staging-dep, +#pkgdetails #metadata .opt-dep, +#pkgdetails #metadata .make-dep, +#pkgdetails #metadata .check-dep, +#pkgdetails #metadata .dep-desc { + font-style: italic; +} +#pkgdetails #pkgreqs { + float: left; + width: 50%; +} + +#pkgdetails #pkgfiles { + clear: left; + padding-top: 1em; +} + +#pkgfilelist li.d { + color: #666; +} + +#pkgfilelist li.f { +} + +/* mirror stuff */ +table td.country { + white-space: normal; +} + +#list-generator div ul { + list-style: none; + display: inline; + padding-left: 0; +} + + #list-generator div ul li { + display: inline; + } + +.visualize-mirror .axis path, +.visualize-mirror .axis line { + fill: none; + stroke: #000; + stroke-width: 3px; + shape-rendering: crispEdges; +} + +.visualize-mirror .url-dot { + stroke: #000; +} + +.visualize-mirror .url-line { + fill: none; + stroke-width: 1.5px; +} + +/* dev/TU biographies */ +#arch-bio-toc { + width: 75%; + margin: 0 auto; + text-align: center; +} + + #arch-bio-toc a { + white-space: nowrap; + } + +.arch-bio-entry { + width: 75%; + min-width: 640px; + margin: 0 auto; +} + + .arch-bio-entry td.pic { + vertical-align: top; + padding-right: 15px; + padding-top: 2.25em; + } + + .arch-bio-entry td.pic img { + padding: 4px; + border: 1px solid #ccc; + } + + .arch-bio-entry td h3 { + border-bottom: 1px dotted #ccc; + margin-bottom: 0.5em; + } + + .arch-bio-entry table.bio { + margin-bottom: 2em; + } + + .arch-bio-entry table.bio th { + color: #666; + font-weight: normal; + text-align: right; + padding-right: 0.5em; + vertical-align: top; + white-space: nowrap; + } + + .arch-bio-entry table.bio td { + width: 100%; + padding-bottom: 0.25em; + white-space: normal; + } + +/* dev: login/out */ +#dev-login { + width: auto; +} + +/* dev dashboard: flagged packages */ +#dash-pkg-notify { + text-align: right; + padding: 1em 0 0; + margin-top: 1em; + font-size: 0.85em; + border-top: 1px dotted #bbb; +} + + #dash-pkg-notify label { + width: auto; + font-weight: normal; + } + + #dash-pkg-notify input { + vertical-align: middle; + margin: 0 0.25em; + } + + #dash-pkg-notify input[type=submit] { + margin-top: -0.25em; + } + + #dash-pkg-notify p { + margin: 0; + } + +table.dash-stats .key { + width: 50%; +} + +/* dev dashboard: admin actions (add news items, todo list, etc) */ +ul.admin-actions { + float: right; + list-style: none; + margin-top: -2.5em; +} + + ul.admin-actions li { + display: inline; + padding-left: 1.5em; + } + +/* colored yes/no type values */ +.todo-table .complete, +.signoff-yes, +#key-status .signed-yes, +#releng-result .success-yes, +#release-list .available-yes { + color: green; +} + +.todo-table .incomplete, +.signoff-no, +#key-status .signed-no, +#releng-result .success-no, +#release-list .available-no { + color: red; +} + +.todo-table .inprogress, +.signoff-bad { + color: darkorange; +} + + +/* todo lists (public and private) */ +.todo-info { + color: #999; + border-bottom: 1px dotted #bbb; +} + +.todo-description { + margin-top: 1em; + padding-left: 2em; + max-width: 900px; +} + +.todo-pkgbases { + border-top: 1px dotted #bbb; +} + +.todo-list h4 { + margin-top: 0; + margin-bottom: 0.4em; +} + +/* dev: signoff page */ +#dev-signoffs tr:hover { + background: #ffd; +} + +ul.signoff-list { + list-style: none; + margin: 0; + padding: 0; +} + +.signoff-yes { + font-weight: bold; +} + +.signoff-disabled { + color: gray; +} + +/* iso testing feedback form */ +#releng-feedback label { + width: auto; + display: inline; + font-weight: normal; +} + +#releng-feedback ul { + padding-left: 1em; +} + +#releng-feedback li { + list-style: none; +} + +#releng-feedback ul+.helptext { + position: relative; top: -0.9em; +} + +/* visualizations page */ +.visualize-buttons { + margin: 0.5em 0.33em; +} + + .visualize-buttons button.active { + depressed: true; + } + +.visualize-chart { + position: relative; + height: 500px; + margin: 0.33em; +} + +#visualize-archrepo .treemap-cell { + border: solid 1px white; + overflow: hidden; + position: absolute; +} + + #visualize-archrepo .treemap-cell span { + padding: 3px; + font-size: 0.85em; + line-height: 1em; + } + +#visualize-keys svg { + width: 100%; + height: 100%; +} diff --git a/sitestatic/archweb.js b/sitestatic/archweb.js new file mode 100644 index 00000000..dce9cd0c --- /dev/null +++ b/sitestatic/archweb.js @@ -0,0 +1,577 @@ +/* archweb.js + * Homepage: https://projects.archlinux.org/archweb.git/ + * Copyright: 2007-2013 The Archweb Team + * License: GPLv2 + * + * This file is part of Archweb. + * + * Archweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Archweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Archweb. If not, see <http://www.gnu.org/licenses/>. + */ + +/*'use strict';*/ +/* tablesorter custom parsers for various pages: + * devel/index.html, mirrors/status.html, todolists/view.html */ +if (typeof $ !== 'undefined' && typeof $.tablesorter !== 'undefined') { + $.tablesorter.addParser({ + id: 'pkgcount', + is: function(s) { return false; }, + format: function(s) { + var m = s.match(/\d+/); + return m ? parseInt(m[0], 10) : 0; + }, + type: 'numeric' + }); + + $.tablesorter.addParser({ + id: 'todostatus', + is: function(s) { return false; }, + format: function(s) { + if (s.match(/incomplete/i)) { + return 1; + } else if (s.match(/in-progress/i)) { + return 0.5; + } + return 0; + }, + type: 'numeric' + }); + + $.tablesorter.addParser({ + /* sorts numeric, but put '', 'unknown', and '∞' last. */ + id: 'mostlydigit', + special: ['', 'unknown', '∞'], + is: function(s, table) { + var c = table.config; + return ($.inArray(s, this.special) > -1) || $.tablesorter.isDigit(s, c); + }, + format: function(s, t) { + if ($.inArray(s, this.special) > -1) { + return Number.MAX_VALUE; + } + return $.tablesorter.formatFloat(s, t); + }, + type: 'numeric' + }); + + $.tablesorter.addParser({ + /* sorts duration; put '', 'unknown', and '∞' last. */ + id: 'duration', + re: /^([0-9]+):([0-5][0-9])$/, + special: ['', 'unknown', '∞'], + is: function(s) { + return ($.inArray(s, this.special) > -1) || this.re.test(s); + }, + format: function(s) { + if ($.inArray(s, this.special) > -1) { + return Number.MAX_VALUE; + } + var matches = this.re.exec(s); + if (!matches) { + return Number.MAX_VALUE; + } + return matches[1] * 60 + matches[2]; + }, + type: 'numeric' + }); + $.tablesorter.addParser({ + id: 'epochdate', + is: function(s) { return false; }, + format: function(s, t, c) { + /* TODO: this assumes our magic class is the only one */ + var epoch = $(c).attr('class'); + if (epoch.indexOf('epoch-') !== 0) { + return 0; + } + return epoch.slice(6); + }, + type: 'numeric' + }); + + $.tablesorter.addParser({ + id: 'longDateTime', + re: /^(\d{4})-(\d{2})-(\d{2}) ([012]\d):([0-5]\d)(:([0-5]\d))?( (\w+))?$/, + is: function(s) { + return this.re.test(s); + }, + format: function(s, t) { + var matches = this.re.exec(s); + if (!matches) { + return 0; + } + /* skip group 6, group 7 is optional seconds */ + if (matches[7] === undefined) { + matches[7] = 0; + } + /* The awesomeness of the JS date constructor. Month needs to be + * between 0-11, because things have to be difficult. */ + var date = new Date(matches[1], matches[2] - 1, matches[3], + matches[4], matches[5], matches[7]); + return $.tablesorter.formatFloat(date.getTime(), t); + }, + type: 'numeric' + }); + + $.tablesorter.addParser({ + id: 'filesize', + re: /^(\d+(?:\.\d+)?)[ \u00a0](bytes?|[KMGTPEZY]i?B)$/, + is: function(s) { + return this.re.test(s); + }, + format: function(s) { + var matches = this.re.exec(s); + if (!matches) { + return 0; + } + var size = parseFloat(matches[1]), + suffix = matches[2]; + + switch(suffix) { + /* intentional fall-through at each level */ + case 'YB': + case 'YiB': + size *= 1024; + case 'ZB': + case 'ZiB': + size *= 1024; + case 'EB': + case 'EiB': + size *= 1024; + case 'PB': + case 'PiB': + size *= 1024; + case 'TB': + case 'TiB': + size *= 1024; + case 'GB': + case 'GiB': + size *= 1024; + case 'MB': + case 'MiB': + size *= 1024; + case 'KB': + case 'KiB': + size *= 1024; + } + return size; + }, + type: 'numeric' + }); + + $.tablesorter.removeParser = function(id) { + $.tablesorter.parsers = $.grep($.tablesorter.parsers, + function(ele, i) { + return ele.id !== id; + }); + }; + + // We don't use currency, and the parser is over-zealous at deciding it + // matches. Kill it from the parser selection. + $.tablesorter.removeParser('currency'); +} + +(function($) { + $.fn.enableCheckboxRangeSelection = function() { + var lastCheckbox = null, + spec = this; + + spec.unbind("click.checkboxrange"); + spec.bind("click.checkboxrange", function(e) { + if (lastCheckbox !== null && e.shiftKey) { + spec.slice( + Math.min(spec.index(lastCheckbox), spec.index(e.target)), + Math.max(spec.index(lastCheckbox), spec.index(e.target)) + 1 + ).attr({checked: e.target.checked ? "checked" : ""}); + } + lastCheckbox = e.target; + }); + + }; +})(jQuery); + +/* news/add.html */ +function enablePreview() { + $('#news-preview-button').click(function(event) { + event.preventDefault(); + $.post('/news/preview/', { + data: $('#id_content').val(), + csrfmiddlewaretoken: $('#newsform input[name=csrfmiddlewaretoken]').val() + }, + function(data) { + $('#news-preview-data').html(data); + $('#news-preview').show(); + } + ); + $('#news-preview-title').html($('#id_title').val()); + }); +} + +/* packages/details.html */ +function ajaxifyFiles() { + $('#filelink').click(function(event) { + event.preventDefault(); + $.getJSON(this.href + 'json/', function(data) { + // Map each file item into an <li/> with the correct class + var list_items = $.map(data.files, function(value, i) { + var cls = value.match(/\/$/) ? 'd' : 'f'; + return ['<li class="', cls, '">', value, '</li>']; + }); + $('#pkgfilelist').empty(); + if (data.pkg_last_update > data.files_last_update) { + $('#pkgfilelist').append('<p class="message">Note: This file list was generated from a previous version of the package; it may be out of date.</p>'); + } + if (list_items.length > 0) { + $('#pkgfilelist').append('<ul>' + list_items.join('') + '</ul>'); + } else if (data.files_last_update === null) { + $('#pkgfilelist').append('<p class="message">No file list available.</p>'); + } else { + $('#pkgfilelist').append('<p class="message">Package has no files.</p>'); + } + }); + }); +} + +function collapseDependsList(list) { + list = $(list); + // Hide everything past a given limit. Don't do anything if we don't have + // enough items, or the link already exists. + var limit = 20, + linkid = list.attr('id') + 'link', + items = list.find('li').slice(limit); + if (items.length <= 1 || $('#' + linkid).length > 0) { + return; + } + items.hide(); + list.after('<p><a id="' + linkid + '" href="#">Show More…</a></p>'); + + // add link and wire it up to show the hidden items + $('#' + linkid).click(function(event) { + event.preventDefault(); + list.find('li').show(); + // remove the full <p/> node from the DOM + $(this).parent().remove(); + }); +} + +function collapseRelatedTo(elements) { + var limit = 5; + $(elements).each(function(idx, ele) { + ele = $(ele); + // Hide everything past a given limit. Don't do anything if we don't + // have enough items, or the link already exists. + var items = ele.find('span.related').slice(limit); + if (items.length <= 1 || ele.find('a.morelink').length > 0) { + return; + } + items.hide(); + ele.append('<a class="morelink" href="#">More…</a>'); + + // add link and wire it up to show the hidden items + ele.find('a.morelink').click(function(event) { + event.preventDefault(); + ele.find('span.related').show(); + $(this).remove(); + }); + }); +} + +/* packages/differences.html */ +function filter_packages() { + /* start with all rows, and then remove ones we shouldn't show */ + var rows = $('#tbody_differences').children(), + all_rows = rows; + if (!$('#id_multilib').is(':checked')) { + rows = rows.not('.multilib').not('.multilib-testing'); + } + var arch = $('#id_archonly').val(); + if (arch !== 'all') { + rows = rows.filter('.' + arch); + } + if (!$('#id_minor').is(':checked')) { + /* this check is done last because it is the most expensive */ + var pat = /(.*)-(.+)/; + rows = rows.filter(function(index) { + var cells = $(this).children('td'); + + /* all this just to get the split version out of the table cell */ + var ver_a = cells.eq(2).text().match(pat); + if (!ver_a) { + return true; + } + + var ver_b = cells.eq(3).text().match(pat); + if (!ver_b) { + return true; + } + + /* first check pkgver */ + if (ver_a[1] !== ver_b[1]) { + return true; + } + /* pkgver matched, so see if rounded pkgrel matches */ + if (Math.floor(parseFloat(ver_a[2])) === + Math.floor(parseFloat(ver_b[2]))) { + return false; + } + /* pkgrel didn't match, so keep the row */ + return true; + }); + } + /* hide all rows, then show the set we care about */ + all_rows.hide(); + rows.show(); + /* make sure we update the odd/even styling from sorting */ + $('.results').trigger('applyWidgets', [false]); +} +function filter_packages_reset() { + $('#id_archonly').val('both'); + $('#id_multilib').removeAttr('checked'); + $('#id_minor').removeAttr('checked'); + filter_packages(); +} + +/* todolists/view.html */ +function todolist_flag() { + // TODO: fix usage of this + var link = this; + $.getJSON(link.href, function(data) { + $(link).text(data.status).removeClass( + 'complete inprogress incomplete').addClass( + data.css_class.toLowerCase()); + /* let tablesorter know the cell value has changed */ + $('.results').trigger('updateCell', [$(link).closest('td')[0], false, null]); + }); + return false; +} + +function filter_pkgs_list(filter_ele, tbody_ele) { + /* start with all rows, and then remove ones we shouldn't show */ + var rows = $(tbody_ele).children(), + all_rows = rows; + /* apply the filters, cheaper ones first */ + if ($('#id_mine_only').is(':checked')) { + rows = rows.filter('.mine'); + } + /* apply arch and repo filters */ + $(filter_ele + ' .arch_filter').add( + filter_ele + ' .repo_filter').each(function() { + if (!$(this).is(':checked')) { + rows = rows.not('.' + $(this).val()); + } + }); + /* more expensive filter because of 'has' call */ + if ($('#id_incomplete').is(':checked')) { + rows = rows.has('.incomplete'); + } + /* hide all rows, then show the set we care about */ + all_rows.hide(); + rows.show(); + $('#filter-count').text(rows.length); + /* make sure we update the odd/even styling from sorting */ + $('.results').trigger('applyWidgets', [false]); +} +function filter_pkgs_reset(callback) { + $('#id_incomplete').removeAttr('checked'); + $('#id_mine_only').removeAttr('checked'); + $('.arch_filter').attr('checked', 'checked'); + $('.repo_filter').attr('checked', 'checked'); + callback(); +} + +function filter_todolist_save(list_id) { + var state = $('#todolist_filter').serializeArray(); + localStorage['filter_todolist_' + list_id] = JSON.stringify(state); +} +function filter_todolist_load(list_id) { + var state = localStorage['filter_todolist_' + list_id]; + if (!state) + return; + state = JSON.parse(state); + $('#todolist_filter input[type="checkbox"]').removeAttr('checked'); + $.each(state, function (i, v) { + // this assumes our only filters are checkboxes + $('#todolist_filter input[name="' + v['name'] + '"]').attr('checked', 'checked'); + }); +} + +function filter_report_save(report_id) { + var state = $('#report_filter').serializeArray(); + localStorage['filter_report_' + report_id] = JSON.stringify(state); +} +function filter_report_load(report_id) { + var state = localStorage['filter_report_' + report_id]; + if (!state) + return; + state = JSON.parse(state); + $('#report_filter input[type="checkbox"]').removeAttr('checked'); + $.each(state, function (i, v) { + // this assumes our only filters are checkboxes + $('#report_filter input[name="' + v['name'] + '"]').attr('checked', 'checked'); + }); +} + +/* signoffs.html */ +function signoff_package() { + // TODO: fix usage of this + var link = this; + $.getJSON(link.href, function(data) { + link = $(link); + var signoff = null, + cell = link.closest('td'); + if (data.created) { + signoff = $('<li>').addClass('signed-username').text(data.user); + var list = cell.children('ul.signoff-list'); + if (list.size() === 0) { + list = $('<ul class="signoff-list">').prependTo(cell); + } + list.append(signoff); + } else if(data.user) { + signoff = link.closest('td').find('li').filter(function(index) { + return $(this).text() == data.user; + }); + } + if (signoff && data.revoked) { + signoff.text(signoff.text() + ' (revoked)'); + } + /* update the approved column to reflect reality */ + var approved = link.closest('tr').children('.approval'); + approved.attr('class', 'approval'); + if (data.known_bad) { + approved.text('Bad').addClass('signoff-bad'); + } else if (!data.enabled) { + approved.text('Disabled').addClass('signoff-disabled'); + } else if (data.approved) { + approved.text('Yes').addClass('signoff-yes'); + } else { + approved.text('No').addClass('signoff-no'); + } + link.removeAttr('title'); + /* Form our new link. The current will be something like + * '/packages/repo/arch/package/...' */ + var base_href = link.attr('href').split('/').slice(0, 5).join('/'); + if (data.revoked) { + link.text('Signoff'); + link.attr('href', base_href + '/signoff/'); + /* should we be hiding the link? */ + if (data.known_bad || !data.enabled) { + link.remove(); + } + } else { + link.text('Revoke Signoff'); + link.attr('href', base_href + '/signoff/revoke/'); + } + /* let tablesorter know the cell value has changed */ + $('.results').trigger('updateCell', [approved[0], false, null]); + }); + return false; +} + +function filter_signoffs() { + /* start with all rows, and then remove ones we shouldn't show */ + var rows = $('#tbody_signoffs').children(), + all_rows = rows; + /* apply arch and repo filters */ + $('#signoffs_filter .arch_filter').add( + '#signoffs_filter .repo_filter').each(function() { + if (!$(this).is(':checked')) { + rows = rows.not('.' + $(this).val()); + } + }); + /* and then the slightly more expensive pending check */ + if ($('#id_pending').is(':checked')) { + rows = rows.has('td.signoff-no'); + } + /* hide all rows, then show the set we care about */ + all_rows.hide(); + rows.show(); + $('#filter-count').text(rows.length); + /* make sure we update the odd/even styling from sorting */ + $('.results').trigger('applyWidgets', [false]); + filter_signoffs_save(); +} +function filter_signoffs_reset() { + $('#signoffs_filter .arch_filter').attr('checked', 'checked'); + $('#signoffs_filter .repo_filter').attr('checked', 'checked'); + $('#id_pending').removeAttr('checked'); + filter_signoffs(); +} +function filter_signoffs_save() { + var state = $('#signoffs_filter').serializeArray(); + localStorage['filter_signoffs'] = JSON.stringify(state); +} +function filter_signoffs_load() { + var state = localStorage['filter_signoffs']; + if (!state) + return; + state = JSON.parse(state); + $('#signoffs_filter input[type="checkbox"]').removeAttr('checked'); + $.each(state, function (i, v) { + // this assumes our only filters are checkboxes + $('#signoffs_filter input[name="' + v['name'] + '"]').attr('checked', 'checked'); + }); +} + +function collapseNotes(elements) { + // Remove any trailing <br/> tags from the note contents + $(elements).children('br').filter(':last-child').filter(function(i, e) { return !e.nextSibling; }).remove(); + + var maxElements = 8; + $(elements).each(function(idx, ele) { + ele = $(ele); + // Hide everything past a given limit. Don't do anything if we don't + // have enough items, or the link already exists. + var contents = ele.contents(); + if (contents.length <= maxElements || ele.find('a.morelink').length > 0) { + return; + } + contents.slice(maxElements).wrapAll('<div class="hide"/>'); + ele.append('<br class="morelink-spacer"/><a class="morelink" href="#">Show More…</a>'); + + // add link and wire it up to show the hidden items + ele.find('a.morelink').click(function(event) { + event.preventDefault(); + $(this).remove(); + ele.find('br.morelink-spacer').remove(); + // move the div contents back and delete the empty div + var hidden = ele.find('div.hide'); + hidden.contents().appendTo(ele); + hidden.remove(); + }); + }); +} + +/* visualizations */ +function format_filesize(size, decimals) { + /*var labels = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];*/ + var labels = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], + label = 0; + + while (size > 2048.0 && label < labels.length - 1) { + label++; + size /= 1024.0; + } + if (decimals === undefined) { + decimals = 2; + } + + return size.toFixed(decimals) + ' ' + labels[label]; +} + +/* HTML5 input type and attribute enhancements */ +function modify_attributes(to_change) { + /* jQuery doesn't let us change the 'type' attribute directly due to IE + woes, so instead we can clone and replace, setting the type. */ + $.each(to_change, function(id, attrs) { + var obj = $(id); + obj.replaceWith(obj.clone().attr(attrs)); + }); +} diff --git a/sitestatic/ceata-parabola.png b/sitestatic/ceata-parabola.png Binary files differnew file mode 100644 index 00000000..0afea73a --- /dev/null +++ b/sitestatic/ceata-parabola.png diff --git a/sitestatic/click_and_pledge.png b/sitestatic/click_and_pledge.png Binary files differnew file mode 100644 index 00000000..078bf88e --- /dev/null +++ b/sitestatic/click_and_pledge.png diff --git a/sitestatic/download.png b/sitestatic/download.png Binary files differnew file mode 100644 index 00000000..9ab858c2 --- /dev/null +++ b/sitestatic/download.png diff --git a/sitestatic/flags/fam.css b/sitestatic/flags/fam.css new file mode 100644 index 00000000..f4c047d0 --- /dev/null +++ b/sitestatic/flags/fam.css @@ -0,0 +1,270 @@ +/** + * fam flag icons CSS. + */ + +.fam-flag { + display: inline-block; + width: 16px; + height: 11px; + line-height: 11px; + background-image: url("fam.png"); + background-position: -208px -188px; + background-repeat: no-repeat; +} + +.fam-flag-zw { background-position: 0px 0px; } +.fam-flag-zm { background-position: -16px 0px; } +.fam-flag-za { background-position: 0px -11px; } +.fam-flag-yt { background-position: -16px -11px; } +.fam-flag-ye { background-position: -32px 0px; } +.fam-flag-ws { background-position: -32px -11px; } +.fam-flag-wf { background-position: 0px -22px; } +.fam-flag-wales { background-position: -16px -22px; } +.fam-flag-vu { background-position: -32px -22px; } +.fam-flag-vn { background-position: 0px -33px; } +.fam-flag-vi { background-position: -16px -33px; } +.fam-flag-vg { background-position: -32px -33px; } +.fam-flag-ve { background-position: -48px 0px; } +.fam-flag-vc { background-position: -48px -11px; } +.fam-flag-va { background-position: -48px -22px; } +.fam-flag-uz { background-position: -48px -33px; } +.fam-flag-uy { background-position: 0px -44px; } +.fam-flag-us { background-position: -16px -44px; } +.fam-flag-um { background-position: -16px -44px; } +.fam-flag-ug { background-position: -32px -44px; } +.fam-flag-ua { background-position: -48px -44px; } +.fam-flag-tz { background-position: -64px 0px; } +.fam-flag-tw { background-position: -64px -11px; } +.fam-flag-tv { background-position: -64px -22px; } +.fam-flag-tt { background-position: -64px -33px; } +.fam-flag-tr { background-position: -64px -44px; } +.fam-flag-to { background-position: 0px -55px; } +.fam-flag-tn { background-position: -16px -55px; } +.fam-flag-tm { background-position: -32px -55px; } +.fam-flag-tl { background-position: -48px -55px; } +.fam-flag-tk { background-position: -64px -55px; } +.fam-flag-tj { background-position: 0px -66px; } +.fam-flag-th { background-position: -16px -66px; } +.fam-flag-tg { background-position: -32px -66px; } +.fam-flag-tf { background-position: -48px -66px; } +.fam-flag-td { background-position: -64px -66px; } +.fam-flag-tc { background-position: -80px 0px; } +.fam-flag-sz { background-position: -80px -11px; } +.fam-flag-sy { background-position: -80px -22px; } +.fam-flag-sx { background-position: -80px -33px; } +.fam-flag-sv { background-position: -80px -44px; } +.fam-flag-st { background-position: -80px -55px; } +.fam-flag-ss { background-position: -80px -66px; } +.fam-flag-sr { background-position: 0px -77px; } +.fam-flag-so { background-position: -16px -77px; } +.fam-flag-sn { background-position: -32px -77px; } +.fam-flag-sm { background-position: -48px -77px; } +.fam-flag-sl { background-position: -64px -77px; } +.fam-flag-sk { background-position: -80px -77px; } +.fam-flag-si { background-position: -96px 0px; } +.fam-flag-sh { background-position: -96px -11px; } +.fam-flag-sg { background-position: -96px -22px; } +.fam-flag-se { background-position: -96px -33px; } +.fam-flag-sd { background-position: -96px -44px; } +.fam-flag-scotland { background-position: -96px -55px; } +.fam-flag-sc { background-position: -96px -66px; } +.fam-flag-sb { background-position: -96px -77px; } +.fam-flag-sa { background-position: 0px -88px; } +.fam-flag-rw { background-position: -16px -88px; } +.fam-flag-ru { background-position: -32px -88px; } +.fam-flag-rs { background-position: -48px -88px; } +.fam-flag-ro { background-position: -64px -88px; } +.fam-flag-qa { background-position: -80px -88px; } +.fam-flag-py { background-position: -96px -88px; } +.fam-flag-pw { background-position: 0px -99px; } +.fam-flag-pt { background-position: -16px -99px; } +.fam-flag-ps { background-position: -32px -99px; } +.fam-flag-pr { background-position: -48px -99px; } +.fam-flag-pn { background-position: -64px -99px; } +.fam-flag-pm { background-position: -80px -99px; } +.fam-flag-pl { background-position: -96px -99px; } +.fam-flag-pk { background-position: -112px 0px; } +.fam-flag-ph { background-position: -112px -11px; } +.fam-flag-pg { background-position: -112px -22px; } +.fam-flag-pf { background-position: -112px -33px; } +.fam-flag-pe { background-position: -112px -44px; } +.fam-flag-pa { background-position: -112px -55px; } +.fam-flag-om { background-position: -112px -66px; } +.fam-flag-nz { background-position: -112px -77px; } +.fam-flag-nu { background-position: -112px -88px; } +.fam-flag-nr { background-position: -112px -99px; } +.fam-flag-no { background-position: 0px -110px; } +.fam-flag-bv { background-position: 0px -110px; } +.fam-flag-sj { background-position: 0px -110px; } +.fam-flag-nl { background-position: -16px -110px; } +.fam-flag-ni { background-position: -32px -110px; } +.fam-flag-ng { background-position: -48px -110px; } +.fam-flag-nf { background-position: -64px -110px; } +.fam-flag-ne { background-position: -80px -110px; } +.fam-flag-nc { background-position: -96px -110px; } +.fam-flag-na { background-position: -112px -110px; } +.fam-flag-mz { background-position: -128px 0px; } +.fam-flag-my { background-position: -128px -11px; } +.fam-flag-mx { background-position: -128px -22px; } +.fam-flag-mw { background-position: -128px -33px; } +.fam-flag-mv { background-position: -128px -44px; } +.fam-flag-mu { background-position: -128px -55px; } +.fam-flag-mt { background-position: -128px -66px; } +.fam-flag-ms { background-position: -128px -77px; } +.fam-flag-mr { background-position: -128px -88px; } +.fam-flag-mq { background-position: -128px -99px; } +.fam-flag-mp { background-position: -128px -110px; } +.fam-flag-mo { background-position: 0px -121px; } +.fam-flag-mn { background-position: -16px -121px; } +.fam-flag-mm { background-position: -32px -121px; } +.fam-flag-ml { background-position: -48px -121px; } +.fam-flag-mk { background-position: -64px -121px; } +.fam-flag-mh { background-position: -80px -121px; } +.fam-flag-mg { background-position: -96px -121px; } +.fam-flag-me { background-position: 0px -132px; width: 16px; height: 12px; } +.fam-flag-md { background-position: -112px -121px; } +.fam-flag-mc { background-position: -128px -121px; } +.fam-flag-ma { background-position: -16px -132px; } +.fam-flag-ly { background-position: -32px -132px; } +.fam-flag-lv { background-position: -48px -132px; } +.fam-flag-lu { background-position: -64px -132px; } +.fam-flag-lt { background-position: -80px -132px; } +.fam-flag-ls { background-position: -96px -132px; } +.fam-flag-lr { background-position: -112px -132px; } +.fam-flag-lk { background-position: -128px -132px; } +.fam-flag-li { background-position: -144px 0px; } +.fam-flag-lc { background-position: -144px -11px; } +.fam-flag-lb { background-position: -144px -22px; } +.fam-flag-la { background-position: -144px -33px; } +.fam-flag-kz { background-position: -144px -44px; } +.fam-flag-ky { background-position: -144px -55px; } +.fam-flag-kw { background-position: -144px -66px; } +.fam-flag-kr { background-position: -144px -77px; } +.fam-flag-kp { background-position: -144px -88px; } +.fam-flag-kn { background-position: -144px -99px; } +.fam-flag-km { background-position: -144px -110px; } +.fam-flag-ki { background-position: -144px -121px; } +.fam-flag-kh { background-position: -144px -132px; } +.fam-flag-kg { background-position: 0px -144px; } +.fam-flag-ke { background-position: -16px -144px; } +.fam-flag-jp { background-position: -32px -144px; } +.fam-flag-jo { background-position: -48px -144px; } +.fam-flag-jm { background-position: -64px -144px; } +.fam-flag-je { background-position: -80px -144px; } +.fam-flag-it { background-position: -96px -144px; } +.fam-flag-is { background-position: -112px -144px; } +.fam-flag-ir { background-position: -128px -144px; } +.fam-flag-iq { background-position: -144px -144px; } +.fam-flag-io { background-position: -160px 0px; } +.fam-flag-in { background-position: -160px -11px; } +.fam-flag-im { background-position: -160px -22px; width: 16px; height: 9px; } +.fam-flag-il { background-position: -160px -31px; } +.fam-flag-ie { background-position: -160px -42px; } +.fam-flag-id { background-position: -160px -53px; } +.fam-flag-hu { background-position: -160px -64px; } +.fam-flag-ht { background-position: -160px -75px; } +.fam-flag-hr { background-position: -160px -86px; } +.fam-flag-hn { background-position: -160px -97px; } +.fam-flag-hk { background-position: -160px -108px; } +.fam-flag-gy { background-position: -160px -119px; } +.fam-flag-gw { background-position: -160px -130px; } +.fam-flag-gu { background-position: -160px -141px; } +.fam-flag-gt { background-position: 0px -155px; } +.fam-flag-gs { background-position: -16px -155px; } +.fam-flag-gr { background-position: -32px -155px; } +.fam-flag-gq { background-position: -48px -155px; } +.fam-flag-gp { background-position: -64px -155px; } +.fam-flag-gn { background-position: -80px -155px; } +.fam-flag-gm { background-position: -96px -155px; } +.fam-flag-gl { background-position: -112px -155px; } +.fam-flag-gi { background-position: -128px -155px; } +.fam-flag-gh { background-position: -144px -155px; } +.fam-flag-gg { background-position: -160px -155px; } +.fam-flag-ge { background-position: -176px 0px; } +.fam-flag-gd { background-position: -176px -11px; } +.fam-flag-gb { background-position: -176px -22px; } +.fam-flag-ga { background-position: -176px -33px; } +.fam-flag-fr { background-position: -176px -44px; } +.fam-flag-gf { background-position: -176px -44px; } +.fam-flag-re { background-position: -176px -44px; } +.fam-flag-mf { background-position: -176px -44px; } +.fam-flag-bl { background-position: -176px -44px; } +.fam-flag-fo { background-position: -176px -55px; } +.fam-flag-fm { background-position: -176px -66px; } +.fam-flag-fk { background-position: -176px -77px; } +.fam-flag-fj { background-position: -176px -88px; } +.fam-flag-fi { background-position: -176px -99px; } +.fam-flag-fam { background-position: -176px -110px; } +.fam-flag-eu { background-position: -176px -121px; } +.fam-flag-et { background-position: -176px -132px; } +.fam-flag-es { background-position: -176px -143px; } +.fam-flag-er { background-position: -176px -154px; } +.fam-flag-england { background-position: 0px -166px; } +.fam-flag-eh { background-position: -16px -166px; } +.fam-flag-eg { background-position: -32px -166px; } +.fam-flag-ee { background-position: -48px -166px; } +.fam-flag-ec { background-position: -64px -166px; } +.fam-flag-dz { background-position: -80px -166px; } +.fam-flag-do { background-position: -96px -166px; } +.fam-flag-dm { background-position: -112px -166px; } +.fam-flag-dk { background-position: -128px -166px; } +.fam-flag-dj { background-position: -144px -166px; } +.fam-flag-de { background-position: -160px -166px; } +.fam-flag-cz { background-position: -176px -166px; } +.fam-flag-cy { background-position: 0px -177px; } +.fam-flag-cx { background-position: -16px -177px; } +.fam-flag-cw { background-position: -32px -177px; } +.fam-flag-cv { background-position: -48px -177px; } +.fam-flag-cu { background-position: -64px -177px; } +.fam-flag-cs { background-position: -80px -177px; } +.fam-flag-cr { background-position: -96px -177px; } +.fam-flag-co { background-position: -112px -177px; } +.fam-flag-cn { background-position: -128px -177px; } +.fam-flag-cm { background-position: -144px -177px; } +.fam-flag-cl { background-position: -160px -177px; } +.fam-flag-ck { background-position: -176px -177px; } +.fam-flag-ci { background-position: -192px 0px; } +.fam-flag-cg { background-position: -192px -11px; } +.fam-flag-cf { background-position: -192px -22px; } +.fam-flag-cd { background-position: -192px -33px; } +.fam-flag-cc { background-position: -192px -44px; } +.fam-flag-catalonia { background-position: -192px -55px; } +.fam-flag-ca { background-position: -192px -66px; } +.fam-flag-bz { background-position: -192px -77px; } +.fam-flag-by { background-position: -192px -88px; } +.fam-flag-bw { background-position: -192px -99px; } +.fam-flag-bt { background-position: -192px -110px; } +.fam-flag-bs { background-position: -192px -121px; } +.fam-flag-br { background-position: -192px -132px; } +.fam-flag-bq { background-position: -192px -143px; } +.fam-flag-bo { background-position: -192px -154px; } +.fam-flag-bn { background-position: -192px -165px; } +.fam-flag-bm { background-position: -192px -176px; } +.fam-flag-bj { background-position: 0px -188px; } +.fam-flag-bi { background-position: -16px -188px; } +.fam-flag-bh { background-position: -32px -188px; } +.fam-flag-bg { background-position: -48px -188px; } +.fam-flag-bf { background-position: -64px -188px; } +.fam-flag-be { background-position: -80px -188px; } +.fam-flag-bd { background-position: -96px -188px; } +.fam-flag-bb { background-position: -112px -188px; } +.fam-flag-ba { background-position: -128px -188px; } +.fam-flag-az { background-position: -144px -188px; } +.fam-flag-ax { background-position: -160px -188px; } +.fam-flag-aw { background-position: -176px -188px; } +.fam-flag-au { background-position: -192px -188px; } +.fam-flag-hm { background-position: -192px -188px; } +.fam-flag-at { background-position: -208px 0px; } +.fam-flag-as { background-position: -208px -11px; } +.fam-flag-ar { background-position: -208px -22px; } +.fam-flag-ao { background-position: -208px -33px; } +.fam-flag-an { background-position: -208px -44px; } +.fam-flag-am { background-position: -208px -55px; } +.fam-flag-al { background-position: -208px -66px; } +.fam-flag-ai { background-position: -208px -77px; } +.fam-flag-ag { background-position: -208px -88px; } +.fam-flag-af { background-position: -208px -99px; } +.fam-flag-ae { background-position: -208px -110px; } +.fam-flag-ad { background-position: -208px -121px; } +.fam-flag-np { background-position: -208px -132px; width: 9px; } +.fam-flag-ch { background-position: -208px -143px; width: 11px; } diff --git a/sitestatic/flags/fam.png b/sitestatic/flags/fam.png Binary files differnew file mode 100644 index 00000000..953287b9 --- /dev/null +++ b/sitestatic/flags/fam.png diff --git a/sitestatic/gandi.png b/sitestatic/gandi.png Binary files differnew file mode 100644 index 00000000..85c8e1ee --- /dev/null +++ b/sitestatic/gandi.png diff --git a/sitestatic/kartenzia_button.png b/sitestatic/kartenzia_button.png Binary files differnew file mode 100644 index 00000000..c156fc86 --- /dev/null +++ b/sitestatic/kartenzia_button.png diff --git a/sitestatic/magnet.png b/sitestatic/magnet.png Binary files differnew file mode 100644 index 00000000..f67e69b9 --- /dev/null +++ b/sitestatic/magnet.png diff --git a/sitestatic/new.png b/sitestatic/new.png Binary files differnew file mode 100644 index 00000000..6a9bf037 --- /dev/null +++ b/sitestatic/new.png diff --git a/sitestatic/robofun.jpg b/sitestatic/robofun.jpg Binary files differnew file mode 100644 index 00000000..c01ce645 --- /dev/null +++ b/sitestatic/robofun.jpg diff --git a/sitestatic/vector_tux.png b/sitestatic/vector_tux.png Binary files differnew file mode 100644 index 00000000..ab4be6d0 --- /dev/null +++ b/sitestatic/vector_tux.png diff --git a/sitestatic/vnet_button.png b/sitestatic/vnet_button.png Binary files differnew file mode 100644 index 00000000..22cfa9e4 --- /dev/null +++ b/sitestatic/vnet_button.png diff --git a/templates/404.html b/templates/404.html index 33271c66..7a667bac 100644 --- a/templates/404.html +++ b/templates/404.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Page Not Found{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Page Not Found{% endblock %} {% block content %} <div id="error-page" class="box 404"> diff --git a/templates/admin/index.html b/templates/admin/index.html index 6f7f98ee..89ee1df1 100644 --- a/templates/admin/index.html +++ b/templates/admin/index.html @@ -1,11 +1,11 @@ {% extends "admin/base_site.html" %} -{% load i18n %} +{% load i18n admin_static %} -{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% load adminmedia %}{% admin_media_prefix %}css/dashboard.css" />{% endblock %} +{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %} {% block coltype %}colMS{% endblock %} -{% block bodyclass %}dashboard{% endblock %} +{% block bodyclass %}{{ block.super }} dashboard{% endblock %} {% block breadcrumbs %}{% endblock %} @@ -14,33 +14,43 @@ <div class="module"> <table> <caption>Custom Admin Pages</caption> + {% if perms.auth.add_user %} <tr> <th scope="row"><a href="/devel/newuser/">Create New User</a></th> <td></td><td></td> </tr> + {% endif %} + {% if user.is_superuser %} + <tr> + <th scope="row"><a href="/devel/admin_log/">Admin Actions Log</a></th> + <td></td><td></td> + </tr> + {% endif %} </table> </div> {% if app_list %} {% for app in app_list %} - <div class="module"> - <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}"> - <caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption> + <div class="app-{{ app.app_label }} module"> + <table> + <caption> + <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a> + </caption> {% for model in app.models %} - <tr> - {% if model.perms.change %} + <tr class="model-{{ model.object_name|lower }}"> + {% if model.admin_url %} <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th> {% else %} <th scope="row">{{ model.name }}</th> {% endif %} - {% if model.perms.add %} - <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td> + {% if model.add_url %} + <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td> {% else %} <td> </td> {% endif %} - {% if model.perms.change %} + {% if model.admin_url %} <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td> {% else %} <td> </td> @@ -69,7 +79,7 @@ <ul class="actionlist"> {% for entry in admin_log %} <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}"> - {% if entry.is_deletion %} + {% if entry.is_deletion or not entry.get_admin_url %} {{ entry.object_repr }} {% else %} <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a> diff --git a/templates/base.html b/templates/base.html index 71b3f87f..b27554c9 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,54 +1,56 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +{% load static from staticfiles %}{% load wiki %}<!DOCTYPE html> +<html lang="en"> <head> - <title>{% block title %}Arch Linux{% endblock %}</title> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <link rel="stylesheet" type="text/css" href="/media/archweb.css" media="screen, projection" /> - <link rel="stylesheet" type="text/css" href="/media/archweb-print.css" media="print" /> - <link rel="icon" type="image/x-icon" href="/media/favicon.ico" /> - <link rel="shortcut icon" type="image/x-icon" href="/media/favicon.ico" /> - <link rel="search" type="application/opensearchdescription+xml" href="{% url opensearch-packages as osp %}{{ osp }}" title="Arch Linux Packages" /> + <meta charset="utf-8" /> + <title>{% block title %}{{ BRANDING_DISTRONAME }}{% endblock %}</title> + <link rel="stylesheet" type="text/css" href="{% static "archweb.css" %}" media="screen, projection" /> + <link rel="icon" type="image/x-icon" href="{% static "favicon.ico" %}" /> + <link rel="shortcut icon" type="image/x-icon" href="{% static "favicon.ico" %}" /> + <link rel="apple-touch-icon" href="{% static "logos/apple-touch-icon-57x57.png" %}" /> + <link rel="apple-touch-icon" sizes="72x72" href="{% static "logos/apple-touch-icon-72x72.png" %}" /> + <link rel="apple-touch-icon" sizes="114x114" href="{% static "logos/apple-touch-icon-114x114.png" %}" /> + <link rel="apple-touch-icon" sizes="144x144" href="{% static "logos/apple-touch-icon-144x144.png" %}" /> + <link rel="search" type="application/opensearchdescription+xml" href="{% url 'opensearch-packages' as osp %}{{ osp }}" title="{{ BRANDING_DISTRONAME }} Packages" /> {% block head %}{% endblock %} </head> <body class="{% if user.is_authenticated %}devmode {% endif %}{% block bodyclass %}{% endblock %}"> - <div id="archnavbar" class="{% block navbarclass %}anb-home{% endblock %}"> - <div id="archnavbarlogo"><h1><a href="/" title="Return to the main page">Arch Linux</a></h1></div> + <div id="archnavbarlogo"><h1><a href="/" title="Return to the main page">{{ BRANDING_DISTRONAME }}</a></h1></div> <div id="archnavbarmenu"> <ul id="archnavbarlist"> - <li id="anb-home"><a href="/" title="Arch news, packages, projects and more">Home</a></li> - <li id="anb-packages"><a href="/packages/" title="Arch Package Database">Packages</a></li> - <li id="anb-forums"><a href="https://bbs.archlinux.org/" title="Community forums">Forums</a></li> - <li id="anb-wiki"><a href="http://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> - <li id="anb-bugs"><a href="https://bugs.archlinux.org/" title="Report and track bugs">Bugs</a></li> - <li id="anb-aur"><a href="http://aur.archlinux.org/" title="Arch Linux User Repository">AUR</a></li> - <li id="anb-download"><a href="{% url page-download as pdl %}{{ pdl }}" title="Get Arch Linux">Download</a></li> + <li id="anb-home"><a href="/" title="{{ BRANDING_SHORTNAME }} news, packages, projects and more">Home</a></li> + <li id="anb-packages"><a href="/packages/" title="{{ BRANDING_SHORTNAME }} Packages Database">Packages</a></li> + <!-- Free Culture or multimedia with mediagoblin --> + <!-- Social with GNU Social, Diaspora or another, it needs consensus --> + <li id="anb-wiki"><a href="{% wiki_url %}" title="Parabola and community documentations">Wiki</a></li> + <li id="anb-bugs"><a href="{{ BUGTRACKER_URL }}" title="Report and track on labs">Labs</a></li> + <!-- PUR --> + <li id="anb-projects"><a href="{{ PROJECTS_URL }}" title="Our code">Projects</a></li> + <li id="anb-download"><a href="{% url 'page-download' as pdl %}{{ pdl }}" title="Get {{ BRANDING_DISTRONAME }}">Download</a></li> </ul> </div> - </div><!-- #archnavbar --> - + </div> <div id="content"> <div id="archdev-navbar"> {% if user.is_authenticated %} <ul> - <li><a href="/devel/" title="Developer Dashboard">Dashboard</a></li> - <li><a href="http://wiki.archlinux.org/index.php/DeveloperWiki" - title="Developer HOWTOs and documentation">DevWiki</a></li> - <li><a href="http://projects.archlinux.org/" title="Git Projects">Projects</a></li> - <li><a href="{% url news-list as newsl %}{{ newsl }}" title="Manage news articles">News</a></li> + <li><a href="{% url 'devel-index' %}" title="Developer Dashboard">Dashboard</a></li> + <li><a href="{% wiki_url 'DeveloperWiki' %}" + title="Developer Wiki">DevWiki</a></li> + <li><a href="{% url 'news-list' as newsl %}{{ newsl }}" title="Manage news articles">News</a></li> <li><a href="/packages/signoffs/" title="Package signoffs">Signoffs</a></li> <li><a href="/todo/" title="Developer todo lists">Todos</a></li> - <li><a href="/packages/differences/" title="Package architecture differences">Arch Differences</a></li> - <li><a href="http://www.archlinux.org/mailman/private/arch-dev/" - title="arch-dev mailing list archives">Archives</a></li> - <li><a href="/mirrors/" title="Mirror server statistics">Mirrors</a></li> + <li><a href="{% url 'devel-clocks' %}" title="Developer world clocks">Dev Clocks</a></li> + <li><a href="{{ MAILMAN_BASE_URL }}/mailman/listinfo/dev/" + title="dev mailing list archives">Archives</a></li> + {% if user.is_staff %} + <li><a href="{% url 'admin:index' %}" title="Django Admin Interface">Django Admin</a></li> + {% endif %} <li><a href="/devel/profile/" title="Modify your account profile">Profile</a></li> - <li><a href="/accounts/logout/" title="Logout of the developer interface">Logout</a></li> + <li><a href="/logout/" title="Logout of the developer interface">Logout</a></li> </ul> {% endif %} - </div><!-- #archdev-navbar --> - + </div> {% if messages %} <div id="sys-message" class="box"> {% for message in messages %} @@ -56,33 +58,39 @@ {% endfor %} </div> {% endif %} - {% block content %} <div id="content-left-wrapper"> <div id="content-left"> {% block content_left %}{% endblock %} - </div><!-- #content_left --> + </div> </div> - <div id="content-right"> {% block content_right %}{% endblock %} - </div><!-- #content_right --> + </div> {% endblock %} - <div id="footer"> - <p>Copyright © 2002-{% now "Y" %} <a href="mailto:jvinet@zeroflux.org" + <p>Copyright © 2009-{% now "Y" %} Parabola Project. All content is + released under the <a + href="http://creativecommons.org/licenses/by-sa/3.0/" + rel="license">cc by-sa 3.0 unported</a> license.</p> + <p>Website software and layout is derivative of archweb, + Copyright © 2002-{% now "Y" %} <a href="mailto:jvinet@zeroflux.org" title="Contact Judd Vinet">Judd Vinet</a> and <a href="mailto:aaron@archlinux.org" title="Contact Aaron Griffin">Aaron Griffin</a>.</p> - - <p>The Arch Linux name and logo are recognized - <a href="http://wiki.archlinux.org/index.php/DeveloperWiki:TrademarkPolicy" - title="Arch Linux Trademark Policy">trademarks</a>. Some rights reserved.</p> - - <p>The registered trademark Linux® is used pursuant to a sublicense from LMI, - the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide basis.</p> - </div><!-- #footer --> - - </div><!-- #content --> - + </div> + </div> + <script type="application/ld+json"> + { + "@context": "http://schema.org", + "@type": "WebSite", + "url": "{{ domain }}/", + "potentialAction": { + "@type": "SearchAction", + "target": "{{ domain }}/packages/?q={search_term}", + "query-input": "required name=search_term" + } + } + </script> + {% block script_block %}{% endblock %} </body> </html> diff --git a/templates/devel/admin_log.html b/templates/devel/admin_log.html new file mode 100644 index 00000000..05130491 --- /dev/null +++ b/templates/devel/admin_log.html @@ -0,0 +1,62 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_static %} + +{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %} + +{% block breadcrumbs %}<div class="breadcrumbs"><a href="/admin/">{% trans 'Home' %}</a>{% if title %} › {{ title }}{% endif %}</div>{% endblock %} + +{% block content %} +<div id="content-main"> + <div class="module"> +{% load log %} +{% if log_user %} +{% get_admin_log 100 as admin_log for_user log_user %} +{% else %} +{% get_admin_log 100 as admin_log %} +{% endif %} +{% if not admin_log %} +<p>{% trans 'None available' %}</p> +{% else %} +<table id="change-history"> + <thead> + <tr> + <th scope="col">{% trans 'Date/time' %}</th> + <th scope="col">{% trans 'User' %}</th> + <th>Type</th> + <th>Object</th> + <th scope="col">{% trans 'Action' %}</th> + </tr> + </thead> + <tbody> + {% for entry in admin_log %} + <tr> + <th scope="row">{{ entry.action_time|date:"DATETIME_FORMAT" }}</th> + {% if log_user %} + <td>{{ entry.user.username }}{% if entry.user.get_full_name %} ({{ entry.user.get_full_name }}){% endif %}</td> + {% else %} + <td><a href="{{ entry.user.username }}/">{{ entry.user.username }}</a>{% if entry.user.get_full_name %} ({{ entry.user.get_full_name }}){% endif %}</td> + {% endif %} + <td> + {% if entry.content_type %} + <span>{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span> + {% else %} + <span>{% trans 'Unknown content' %}</span> + {% endif %} + </td> + <td> + <span class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}"></span> + {% if entry.is_deletion %} + {{ entry.object_repr }} + {% else %} + <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a> + {% endif %} + </td> + <td>{{ entry.change_message }}</td> + </tr> + {% endfor %} + </tbody> +</table> +{% endif %} + </div> +</div> +{% endblock %} diff --git a/templates/devel/clock.html b/templates/devel/clock.html new file mode 100644 index 00000000..6ed890c1 --- /dev/null +++ b/templates/devel/clock.html @@ -0,0 +1,75 @@ +{% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load flags %} +{% load tz %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Hacker World Clocks{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} + +{% block content %} +<div id="dev-clocks-box" class="box"> + <h2>Hacker World Clocks</h2> + + <p>This page helps prevent you from waking a sleeping hacker. It also + depends on hackers keeping the time zone information up to date, so if + you see 'UTC' listed, pester them to update their settings.</p> + <p>The "Last Action" column shows the last time this developer has done + something we know about. Considered dates for each developer include:</p> + <ul> + <li>Build date of a package in the repositories</li> + <li>Last login to the developer side of this site</li> + <li>Admin log entry on this site (e.g., adding a donor, modifying a + mirror)</li> + <li>Post date of a news item</li> + <li>Signing off on a package</li> + <li>Flagging a package out-of-date</li> + </ul> + <p> + Current UTC Time: {{ utc_now|date:"Y-m-d H:i T" }} + </p> + + <table id="clocks-table" class="results"> + <thead> + <tr> + <th>Hacker</th> + <th>Username</th> + <th>Alias</th> + <th>Last Action</th> + <th>Location</th> + <th>Time Zone</th> + <th>Current Time</th> + </tr> + </thead> + <tbody> + {% for dev in developers %} + <tr class="{% cycle 'odd' 'even' %}"> + <td><a href="mailto:{{ dev.email }}">{{ dev.get_full_name }}</a></td> + <td>{{ dev.username }}</td> + <td>{{ dev.userprofile.alias }}</td> + <td>{{ dev.last_action }}</td> + <td>{% country_flag dev.userprofile.country %}{{ dev.userprofile.location }}</td> + <td>{{ dev.userprofile.time_zone }}</td> + <td>{{ utc_now|timezone:dev.userprofile.time_zone|date:"Y-m-d H:i T" }}<span class="hide"> {{ dev.userprofile.time_zone }}</span></td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $("#clocks-table:has(tbody tr)").tablesorter({ + widgets: ['zebra'], + sortLocaleCompare: true, + sortList: [[0,0]], + headers: { 4: { sorter: false } } + }); +}); +</script> +{% endblock %} diff --git a/templates/devel/index.html b/templates/devel/index.html index f285f7f6..3a0fb9a9 100644 --- a/templates/devel/index.html +++ b/templates/devel/index.html @@ -1,5 +1,11 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Developer Dashboard{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load cache %} +{% load package_extras %} +{% load todolists %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Hacker Dashboard{% endblock %} {% block content %} <div id="dev-dashboard" class="box"> @@ -8,37 +14,45 @@ <h3>My Flagged Packages</h3> - <table id="dash-myflagged" class="results dash-stats"> + <table id="dash-myflagged" class="results"> <thead> <tr> - <th class="key">Name</th> - <th>Repo</th> + <th>Name</th> <th>Version</th> + <th>Testing Version</th> + <th>Repo</th> <th>Arch</th> + <th>Flagged</th> + <th>Last Updated</th> </tr> </thead> <tbody> {% for pkg in flagged %} <tr class="{% cycle 'odd' 'even' %}"> - <td><a href="{{ pkg.get_absolute_url }}" - title="View package details for {{ pkg.pkgname }}">{{ pkg.pkgname }}</a></td> + <td>{% pkg_details_link pkg %}</td> + <td>{{ pkg.full_version }}</td> + <td>{% with pkg.in_testing as tp %}{% if tp %} + <a href="{{ tp.get_absolute_url }}" + title="Testing package details for {{ tp.pkgname }}">{{ tp.full_version }}</a> + {% endif %}{% endwith %}</td> <td>{{ pkg.repo.name }}</td> - <td>{{ pkg.pkgver }}</td> <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.flag_date|date }}</td> + <td>{{ pkg.last_update|date }}</td> </tr> {% empty %} - <tr class="empty"><td colspan="4"><em>No flagged packages to display</em></td></tr> + <tr class="empty"><td colspan="7"><em>No flagged packages to display</em></td></tr> {% endfor %} </tbody> </table> <h3>My Incomplete Todo List Packages</h3> - <table id="dash-mytodolist" class="results dash-stats"> + <table id="dash-mytodolist" class="results"> <thead> <tr> <th>Todo List</th> - <th class="key">Name</th> + <th>Name</th> <th>Repo</th> <th>Arch</th> <th>Maintainer(s)</th> @@ -47,12 +61,11 @@ <tbody> {% for todopkg in todopkgs %} <tr class="{% cycle 'odd' 'even' %}"> - <td><a href="{{ todopkg.list.get_absolute_url }}" - title="View todo list: {{ todopkg.list.name }}">{{ todopkg.list.name }}</a></td> - <td><a href="{{ todopkg.pkg.get_absolute_url }}" - title="View package details for {{ todopkg.pkg.pkgname }}">{{ todopkg.pkg.pkgname }}</a></td> - <td>{{ todopkg.pkg.repo.name }}</td> - <td>{{ todopkg.pkg.arch.name }}</td> + <td><a href="{{ todopkg.todolist.get_absolute_url }}" + title="View todo list: {{ todopkg.todolist.name }}">{{ todopkg.todolist.name }}</a></td> + <td>{% todopkg_details_link todopkg %}</td> + <td>{{ todopkg.repo.name }}</td> + <td>{{ todopkg.arch.name }}</td> <td>{{ todopkg.pkg.maintainers|join:', ' }}</td> </tr> {% empty %} @@ -63,156 +76,128 @@ <h3>Package Todo Lists</h3> - <table id="dash-todo" class="results dash-stats"> + <table id="dash-todo" class="results"> <thead> <tr> <th>Name</th> <th>Creation Date</th> + <th>Creator</th> <th>Description</th> + <th>Package Count</th> + <th>Incomplete Count</th> </tr> </thead> <tbody> {% for todo in todos %} - <tr class="{% cycle 'odd' 'even' %}"> - <td class="key"><a href="{{ todo.get_absolute_url }}" - title="View todo list: {{ todo.name }}">{{ todo.name }}</a></td> - <td>{{ todo.date_added }}</td> - <td>{{ todo.description|safe }}</td> - </tr> + <tr class="{% cycle 'odd' 'even' %}"> + <td><a href="{{ todo.get_absolute_url }}" + title="View todo list: {{ todo.name }}">{{ todo.name }}</a></td> + <td>{{ todo.created|date }}</td> + <td>{{ todo.creator.get_full_name }}</td> + <td class="wrap">{{ todo.description|urlize }}</td> + <td>{{ todo.pkg_count }}</td> + <td>{{ todo.incomplete_count }}</td> + </tr> {% empty %} - <tr class="empty"><td colspan="3"><em>No package todo lists to display</em></td></tr> + <tr class="empty"><td colspan="6"><em>No package todo lists to display</em></td></tr> {% endfor %} </tbody> </table> - <form id="dash-pkg-notify" method="post" action="/devel/notify/">{% csrf_token %} - <fieldset> - <p><input id="notify" name="notify" type="checkbox" value="yes" - {% if user.get_profile.notify %} checked="checked"{% endif %} /> - <label for="notify">Notify me when packages are flagged out-of-date</label> - <input title="Update notification status" type="submit" value="Update" /></p> - </fieldset> - </form> - -</div><!-- #dev-dashboard --> + <h3>Signoff Status</h3> -<div id="dash-by-arch" class="dash-stats box"> - - <h3 class="dash-stats" style="cursor: pointer" - title="Click to toggle stats by architecture"> - Stats by Architecture <span class="dash-click">(click to toggle)</span></h3> - - <table id="stats-by-arch" class="results dash-stats"> + <table id="dash-signoffs" class="results"> <thead> <tr> - <th class="key">Arch</th> - <th># Packages</th> - <th># Flagged</th> + <th>Name</th> + <th>Version</th> + <th>Arch</th> + <th>Target Repo</th> + <th>Last Updated</th> + <th>Approved</th> + <th>Signoffs</th> </tr> </thead> <tbody> - {% for arch in arches %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ arch.name }}</td> - <td><a href="/packages/?arch={{ arch.name }}" - title="View all packages for the {{ arch.name }} architecture"> - <strong>{{ arch.packages.count }}</strong> packages</a></td> - <td><a href="/packages/?arch={{ arch.name }}&flagged=Flagged" - title="View all flagged packages for the {{ arch.name }} architecture"> - <strong>{{ arch.packages.flagged.count }}</strong> packages</a></td> - </tr> - {% endfor %} - </tbody> - </table> - -</div><!-- #dash-by-arch --> - -<div id="dash-by-repo" class="dash-stats box"> - - <h3 class="dashboard dash-stats" style="cursor: pointer" - title="Click to toggle stats by repository"> - Stats by Repository <span class="dash-click">(click to toggle)</span></h3> - - <table id="stats-by-repo" class="results dash-stats"> - <thead> - <tr> - <th class="key">Repository</th> - <th># Packages</th> - <th># Flagged</th> + {% for group in signoffs %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{% pkg_details_link group.package %}</td> + <td>{{ group.version }}</td> + <td>{{ group.arch.name }}</td> + <td>{{ group.target_repo }}</td> + <td>{{ group.last_update|date }}</td> + {% if group.specification.known_bad %} + <td class="approval signoff-bad">Bad</td> + {% else %} + {% if not group.specification.enabled %} + <td class="approval signoff-disabled">Disabled</td> + {% else %} + <td class="approval signoff-{{ group.approved|yesno }}">{{ group.approved|yesno|capfirst }}</td> + {% endif %} + {% endif %} + <td><ul class="signoff-list"> + {% for signoff in group.signoffs %} + <li class="signed-username" title="Signed off by {{ signoff.user }}">{{ signoff.user }}{% if signoff.revoked %} (revoked){% endif %}</li> + {% endfor %} + </ul></td> </tr> - </thead> - <tbody> - {% for repo in repos %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ repo.name }}</td> - <td><a href="/packages/?repo={{ repo.name }}" - title="View all packages in the {{ repo.name }} repository"> - <strong>{{ repo.packages.count }}</strong> packages</a></td> - <td><a href="/packages/?repo={{ repo.name }}&flagged=Flagged" - title="View all flagged packages in the {{ repo.name }} repository"> - <strong>{{ repo.packages.flagged.count }}</strong> packages</a></td> - </tr> + {% empty %} + <tr class="empty"><td colspan="7"><em>No packages you maintain or have packaged need signoffs</em></td></tr> {% endfor %} </tbody> </table> -</div><!-- dash-by-arch --> - -<div id="dash-by-maintainer" class="dash-stats box"> - - <h3 class="dashboard dash-stats" style="cursor: pointer" - title="Click to toggle stats by maintainer"> - Stats by Maintainer <span class="dash-click">(click to toggle)</span></h3> - - <table id="stats-by-maintainer" class="results dash-stats"> - <thead> - <tr> - <th class="key">Maintainer</th> - <th># Packages</th> - <th># Flagged</th> - </tr> - </thead> - <tbody> - {% for maint in maintainers %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ maint.get_full_name }}</td> - <td><a href="/packages/?maintainer={{ maint.username }}" - title="View all packages maintained by {{ maint.get_full_name }}"> - <strong>{{ maint.package_count }}</strong> packages</a></td> - <td><a href="/packages/?maintainer={{ maint.username }}&flagged=Flagged" - title="View all flagged packages maintained by {{ maint.get_full_name }}"> - <strong>{{ maint.flagged_count }}</strong> packages</a></td> - </tr> - {% endfor %} - </tbody> - </table> + <h3>Developer Reports</h3> + <ul> + {% for report in reports %} + <li><a href="reports/{{ report.slug }}/">{{ report.name }}</a>: + {{ report.description }} + {% if report.personal %}(<a href="reports/{{ report.slug }}/{{ user.username }}/">yours only</a>){% endif %}</li> + {% endfor %} + </ul> +</div>{# #dev-dashboard #} + +<div id="stats-area"> + <div class="box"> + <h2>Developer Stats</h2> + <p id="stats-message">Enable JavaScript to get more useful info here.</p> + </div> +</div> +{% endblock %} -</div><!-- #dash-by-maintainer --> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> -$.tablesorter.addParser({ - id: 'pkgcount', - is: function(s) { return false; }, - format: function(s) { - var m = s.match(/\d+/); - return m ? parseInt(m[0]) : 0; - }, - type: 'numeric' -}); $(document).ready(function() { + $("#stats-message").html('Loading developer stats…'); + $("#stats-area").load('stats/', function(response, status, xhr) { + if (status === 'error' || status === 'timeout') { + $("#stats-message").html('Developer stats loading encountered an error. Sorry.'); + return; + } + var settings = { + widgets: ['zebra'], + sortList: [[0,0]], + headers: { 1: { sorter: 'pkgcount' }, 2: { sorter: 'pkgcount' }, 3: { sorter: 'pkgcount' } } + }; + + $(".dash-stats").not($("#stats-by-maintainer")).tablesorter(settings); + settings['sortLocaleCompare'] = true; + $("#stats-by-maintainer").tablesorter(settings); + }); + $("#dash-myflagged:not(:has(tbody tr.empty))").tablesorter( {widgets: ['zebra'], sortList: [[0,0]]}); $("#dash-mytodolist:not(:has(tbody tr.empty))").tablesorter( {widgets: ['zebra'], sortList: [[0,0], [1,0]]}); $("#dash-todo:not(:has(tbody tr.empty))").tablesorter( {widgets: ['zebra'], sortList: [[1,1]]}); - $("#stats-by-arch").add("#stats-by-repo").add("#stats-by-maintainer").tablesorter( - {widgets: ['zebra'], sortList: [[0,0]], - headers: { 1: { sorter: 'pkgcount' }, 2: { sorter: 'pkgcount' } } }); - $("h3.dash-stats").click( - function(e) { $(this).next().toggle(); } - ); + $("#dash-signoffs:not(:has(tbody tr.empty))").tablesorter({ + widgets: ['zebra'], + sortList: [[0,0]], + headers: { 6: {sorter: false } } + }); }); </script> {% endblock %} diff --git a/templates/devel/new_account.txt b/templates/devel/new_account.txt new file mode 100644 index 00000000..1159992a --- /dev/null +++ b/templates/devel/new_account.txt @@ -0,0 +1,5 @@ +You can now log into https://{{ site.domain }}/login/ with these login details: +Username: {{ user.username }} +Password: {{ password }} + +Please update your profile once logged in and change your password. diff --git a/templates/devel/packages.html b/templates/devel/packages.html new file mode 100644 index 00000000..63dd91aa --- /dev/null +++ b/templates/devel/packages.html @@ -0,0 +1,98 @@ +{% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load attributes %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - {{ title }}{% endblock %} + +{% block content %} +<div class="box"> + <h2>{{ title }}{% if maintainer %}, + maintained by {{ maintainer.get_full_name }}{% endif%}</h2> + <p>{{ packages|length }} package{{ packages|pluralize }} found. + {% if maintainer %}This report only includes packages maintained by + {{ maintainer.get_full_name }} ({{ maintainer.username }}).{% endif %} + </p> + + <div class="box filter-criteria"> + <h3>Filter Packages</h3> + <form id="report_filter" method="post" action="."> + <fieldset> + <legend>Select filter criteria</legend> + {% for arch in arches %} + <div><label for="id_arch_{{ arch.name }}" title="Architecture {{ arch.name }}">Arch {{ arch.name }}</label> + <input type="checkbox" name="arch_{{ arch.name }}" id="id_arch_{{ arch.name }}" class="arch_filter" value="{{ arch.name }}" checked="checked"/></div> + {% endfor %} + {% for repo in repos %} + <div><label for="id_repo_{{ repo.name|lower }}" title="Target Repository {{ repo.name }}">[{{ repo.name|lower }}]</label> + <input type="checkbox" name="repo_{{ repo.name|lower }}" id="id_repo_{{ repo.name|lower }}" class="repo_filter" value="{{ repo.name|lower }}" checked="checked"/></div> + {% endfor %} + <div ><label> </label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div> + <div class="clear"></div> + <div id="filter-info"><span id="filter-count">{{ packages|length }}</span> packages displayed.</div> + </fieldset> + </form> + </div> + + <table id="dev-report-results" class="results"> + <thead> + <tr> + <th>Arch</th> + <th>Repo</th> + <th>Name</th> + <th>Version</th> + <th>Description</th> + <th>Last Updated</th> + <th>Build Date</th> + <th>Flag Date</th> + {% for name in column_names %} + <th>{{ name }}</th> + {% endfor %} + </tr> + </thead> + <tbody> + {% for pkg in packages %} + <tr class="{% cycle pkgr2,pkgr1 %} {{ pkg.arch.name }} {{ pkg.repo.name|lower }}"> + <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.repo.name|capfirst }}</td> + <td>{% pkg_details_link pkg %}</td> + {% if pkg.flag_date %} + <td><span class="flagged">{{ pkg.full_version }}</span></td> + {% else %} + <td>{{ pkg.full_version }}</td> + {% endif %} + <td class="wrap">{{ pkg.pkgdesc }}</td> + <td>{{ pkg.last_update|date }}</td> + <td>{{ pkg.build_date|date }}</td> + <td>{{ pkg.flag_date|date }}</td> + {% for attr in column_attrs %} + <td>{{ pkg|attribute:attr }}</td> + {% endfor %} + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $(".results").tablesorter({widgets: ['zebra']}); +}); +$(document).ready(function() { + var filter_func = function() { + filter_pkgs_list('#report_filter', '#dev-report-results tbody'); + filter_report_save('{{ report.slug }}'); + }; + $('#report_filter input').change(filter_func); + $('#criteria_reset').click(function() { filter_pkgs_reset(filter_func); }); + // run on page load to ensure current form selections take effect + filter_report_load('{{ report.slug }}'); + filter_func(); +}); +</script> +{% endblock %} diff --git a/templates/devel/profile.html b/templates/devel/profile.html index 0dde9349..dff5d925 100644 --- a/templates/devel/profile.html +++ b/templates/devel/profile.html @@ -1,18 +1,41 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Edit Profile{% endblock %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Edit Profile{% endblock %} {% block content %} <div id="dev-edit-profile" class="box"> <h2>Developer Profile</h2> - <form id="edit-profile-form" method="post">{% csrf_token %} + <form id="edit-profile-form" enctype="multipart/form-data" method="post" action="">{% csrf_token %} + <p><em>Note:</em> This is the public information shown on the developer + and/or TU profiles page, so please be appropriate with the information + you provide here.</p> <fieldset> - <legend>Username: <strong>{{ user.username }}</strong></legend> + <p><label>Username:</label> + <strong>{{ user.username }}</strong></p> {{ form.as_p }} </fieldset> + <fieldset> + {{ profile_form.as_p }} + </fieldset> <p><label></label> <input title="Save changes" type="submit" value="Save" /></p> </form> </div> {% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> + modify_attributes({ + '#id_email': {type: 'email'}, + '#id_alias': {autocorrect: 'off', autocapitalize: 'off'}, + '#id_public_email': {autocorrect: 'off', autocapitalize: 'off'}, + '#id_website': {type: 'url'}, + '#id_yob': {pattern: '[0-9]*'} + }); +</script> +{% endblock %} diff --git a/templates/devel/stats.html b/templates/devel/stats.html new file mode 100644 index 00000000..9b3b1d28 --- /dev/null +++ b/templates/devel/stats.html @@ -0,0 +1,121 @@ +{% load cycle from future %} +{% load cache %} + +{% cache 60 dev-dash-by-arch %} +<div id="dash-by-arch" class="box"> + + <h2>Stats by Architecture</h2> + + <table id="stats-by-arch" class="results dash-stats"> + <thead> + <tr> + <th class="key">Arch</th> + <th># Packages</th> + <th># Flagged</th> + </tr> + </thead> + <tbody> + {% for arch in arches %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ arch.name }}</td> + <td><a href="/packages/?arch={{ arch.name }}" + title="View all packages for the {{ arch.name }} architecture"> + <strong>{{ arch.total_ct }}</strong> packages</a></td> + <td><a href="/packages/?arch={{ arch.name }}&flagged=Flagged" + title="View all flagged packages for the {{ arch.name }} architecture"> + <strong>{{ arch.flagged_ct }}</strong> packages</a></td> + </tr> + {% endfor %} + </tbody> + </table> +</div>{# #dash-by-arch #} +{% endcache %} + +{% cache 60 dev-dash-by-repo %} +<div id="dash-by-repo" class="box"> + + <h2>Stats by Repository</h2> + + <table id="stats-by-repo" class="results dash-stats"> + <thead> + <tr> + <th class="key">Repository</th> + <th># Packages</th> + <th># Flagged</th> + <th># Maintainers</th> + </tr> + </thead> + <tbody> + {% for repo in repos %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ repo.name }}</td> + <td><a href="/packages/?repo={{ repo.name }}" + title="View all packages in the {{ repo.name }} repository"> + <strong>{{ repo.total_ct }}</strong> packages</a></td> + <td><a href="/packages/?repo={{ repo.name }}&flagged=Flagged" + title="View all flagged packages in the {{ repo.name }} repository"> + <strong>{{ repo.flagged_ct }}</strong> packages</a></td> + <td><strong>{{ repo.maintainer_ct }}</strong> maintainers</td> + </tr> + </tr> + {% endfor %} + </tbody> + </table> +</div>{# dash-by-arch #} +{% endcache %} + +{% cache 60 dev-dash-by-developer %} +<div id="dash-by-developer" class="box"> + + <h2>Stats by Developer</h2> + + {% if perms.main.change_package %} + <p><a href="/packages/stale_relations/">Look for stale relations</a></p> + {% endif %} + + <table id="stats-by-maintainer" class="results dash-stats"> + <thead> + <tr> + <th class="key">Maintainer</th> + <th># Maintained</th> + <th># Flagged</th> + <th># Last Packager</th> + </tr> + <tr class="even"> + <td><em>Orphan/Unknown</em></td> + <td><a href="/packages/?maintainer=orphan" + title="View all orphan packages"> + <strong>{{ orphan.package_count }}</strong> packages</a> + </td> + <td><a href="/packages/?maintainer=orphan&flagged=Flagged" + title="View all flagged orphan packages"> + <strong>{{ orphan.flagged_count }}</strong> packages</a> + </td> + <td><a href="/packages/?packager=unknown" + title="View all packages last updated by unknown"> + <strong>{{ orphan.updated_count }}</strong> packages</a> + </td> + </tr> + </thead> + <tbody> + {% for maint in maintainers %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ maint.get_full_name }}</td> + <td><a href="/packages/?maintainer={{ maint.username }}" + title="View all packages maintained by {{ maint.get_full_name }}"> + <strong>{{ maint.package_count }}</strong> packages</a> + </td> + <td><a href="/packages/?maintainer={{ maint.username }}&flagged=Flagged" + title="View all flagged packages maintained by {{ maint.get_full_name }}"> + <strong>{{ maint.flagged_count }}</strong> packages</a> + </td> + <td><a href="/packages/?packager={{ maint.username }}" + title="View all packages last updated by {{ maint.get_full_name }}"> + <strong>{{ maint.updated_count }}</strong> packages</a> + </td> + </tr> + {% endfor %} + </tbody> + </table> +</div>{# #dash-by-developer #} +{% endcache %} diff --git a/templates/feeds/news_description.html b/templates/feeds/news_description.html deleted file mode 100644 index a1e6446f..00000000 --- a/templates/feeds/news_description.html +++ /dev/null @@ -1,3 +0,0 @@ -{% load markup %} -<p>{{obj.author.get_full_name}} wrote:</p> -{{ obj.content|markdown }} diff --git a/templates/feeds/news_title.html b/templates/feeds/news_title.html deleted file mode 100644 index d355de5b..00000000 --- a/templates/feeds/news_title.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj.title }} diff --git a/templates/feeds/packages_description.html b/templates/feeds/packages_description.html deleted file mode 100644 index 6b9c47b3..00000000 --- a/templates/feeds/packages_description.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj.pkgdesc }} diff --git a/templates/feeds/packages_title.html b/templates/feeds/packages_title.html deleted file mode 100644 index 910c6207..00000000 --- a/templates/feeds/packages_title.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj.pkgname }} {{ obj.pkgver }}-{{ obj.pkgrel }} {{ obj.arch.name }} diff --git a/templates/general_form.html b/templates/general_form.html index 12b35463..c6d6cb1c 100644 --- a/templates/general_form.html +++ b/templates/general_form.html @@ -1,19 +1,23 @@ {% extends "base.html" %} -{% block title %}Arch Linux - {{title}}{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - {{title}}{% endblock %} {% block content %} <div id="generic-form" class="box"> <h2>{{title}}</h2> - {% if description %}{{description}}{% endif %} + {{description}} + {{form.non_field_errors}} <form class="general-form" method="post">{% csrf_token %} <fieldset> {% for field in form %} - <p><label>{{field.label}}{% if field.help_text %}:</label><br /> - <span class="form-help">{{field.help_text}}</span> {% else %}:</label> {% endif %} - {{field}} {% if field.required %}<span class="form-req-field">*</span>{% endif%}</p> + {{field.errors}} + <p><label for="{{field.auto_id}}">{{field.label}}:</label> + {% if field.help_text %}<br/><span class="form-help">{{field.help_text}}</span>{% endif %} + {{field}} + {% if field.field.required %}<span class="form-req-field">*</span>{% endif %} + </p> {% endfor %} </fieldset> <p><label></label> <input type="submit" value="{{submit_text}}" /></p> diff --git a/templates/mirrors/error_table.html.jinja b/templates/mirrors/error_table.html.jinja new file mode 100644 index 00000000..132aae63 --- /dev/null +++ b/templates/mirrors/error_table.html.jinja @@ -0,0 +1,24 @@ +<table id="errorlog_mirrors" class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>Error Message</th> + <th>Last Occurred</th> + <th>Occurrences (last {{ cutoff|hours }})</th> + <th></th> + </tr> + </thead> + <tbody> + {% for log in error_logs %}<tr class="{{ loop.cycle('odd', 'even') }}"> + <td>{{ log.url.url }}</td> + <td>{{ log.url.protocol.protocol }}</td> + <td class="country">{{ country_flag(log.url.country) }}{{ log.url.country.name }}</td> + <td class="wrap">{{ log.error|linebreaksbr }}</td> + <td>{{ log.last_occurred|date('Y-m-d H:i') }}</td> + <td>{{ log.error_count }}</td> + <td><a href="{{ log.url.get_absolute_url() }}">details</a></td> + </tr>{% endfor %} + </tbody> +</table> diff --git a/templates/mirrors/mirror_details.html b/templates/mirrors/mirror_details.html index 90baa75d..3220195d 100644 --- a/templates/mirrors/mirror_details.html +++ b/templates/mirrors/mirror_details.html @@ -1,58 +1,125 @@ {% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load mirror_status %} +{% load flags %} +{% load admin_urls %} +{% load bugs %} -{% block title %}Arch Linux - {{ mirror.name }} - Mirror Details{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - {{ mirror.name }} - Mirror Details{% endblock %} -{% block content %} -<!-- TODO: ids and classes --> -<div id="pkgdetails" class="box"> +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} +{% block content %} +<div class="box"> <h2>Mirror Details: {{ mirror.name }}</h2> - <table id="pkginfo"> + {% if perms.mirrors.change_mirror %} + <ul class="admin-actions"> + <li><a href="{% url 'admin:mirrors_mirror_change' mirror.pk %}" title="Edit mirror">Edit Mirror</a></li> + </ul> + {% endif %} + + <table class="compact"> <tr> <th>Name:</th> <td>{{ mirror.name }}</td> - </tr><tr> + </tr> + <tr> <th>Tier:</th> <td>{{ mirror.get_tier_display }}</td> - </tr><tr> + </tr> + <tr> + <th>Has ISOs:</th> + <td>{{ mirror.isos|yesno|capfirst }}</td> + </tr> + {% if user.is_authenticated %} + <tr> + <th>Public:</th> + <td>{{ mirror.public|yesno|capfirst }}</td> + </tr> + <tr> + <th>Active:</th> + <td>{{ mirror.active|yesno|capfirst }}</td> + </tr> + <tr> + <th>Created:</th> + <td>{{ mirror.created }}</td> + </tr> + <tr> + <th>Last Modified:</th> + <td>{{ mirror.last_modified }}</td> + </tr> + <tr> + <th>Rsync IPs:</th> + <td class="wrap">{{mirror.rsync_ips.all|join:', '}}</td> + </tr> + <tr> + <th>Admin Email:</th> + <td>{% if mirror.admin_email %}<a href="mailto:{{ mirror.admin_email }}">{{ mirror.admin_email }}</a>{% else %}None{% endif %}</td> + </tr> + <tr> + <th>Alternate Email:</th> + <td>{% if mirror.alternate_email %}<a href="mailto:{{ mirror.alternate_email }}">{{ mirror.alternate_email }}</a>{% else %}None{% endif %}</td> + </tr> + <tr> + <th>Notes:</th> + <td class="wrap">{{ mirror.notes|linebreaks }}</td> + </tr> + <tr> <th>Upstream:</th> - <!-- TODO: linking to non-public mirrors --> <td>{% if mirror.upstream %} <a href="{{ mirror.upstream.get_absolute_url }}" title="Mirror details for {{ mirror.upstream.name }}">{{ mirror.upstream.name }}</a> {% else %}None{% endif %}</td> - </tr><tr> + </tr> + <tr> <th>Downstream:</th> {% with mirror.downstream as ds_mirrors %} - <td>{% if ds_mirrors %} + <td class="wrap">{% if ds_mirrors %} {% for ds in ds_mirrors %} <a href="{{ ds.get_absolute_url }}" - title="Mirror details for {{ ds.name }}">{{ ds.name }}</a><br/> - {% endfor %} - {% else %}None{% endif %} - </td> - {% endwith %} - </tr><tr> - <th>Country:</th> - <td>{{ mirror.country }}</td> - </tr><tr> - <th>Has ISOs:</th> - <td>{{ mirror.isos|yesno }}</td> - </tr><tr> - <th>Protocols:</th> - <td>{{ mirror.supported_protocols }}</td> - </tr><tr> - <th>Mirror URLs:</th> - {% with mirror.urls.all as urls %} - <td>{% if urls %} - {% for u in urls %} - <a href="{{ u.url }}">{{ u.url }}</a><br/> - {% endfor %} - {% else %}None{% endif %} - </td> + title="Mirror details for {{ ds.name }}">{{ ds.name }}</a>{% comment %} + {% endcomment %}{% if not ds.active %} <span class="testing-dep">(inactive)</span>{% endif %}{% comment %} + {% endcomment %}{% if not ds.public %} <span class="testing-dep">(private)</span>{% endif %}{% comment %} + {% endcomment %}{% if not forloop.last %}, {% endif %}{% endfor %} + {% else %}None{% endif %}</td> {% endwith %} </tr> + {% endif %} </table> + + <h3>Available URLs</h3> + {% include "mirrors/mirror_details_urls.html.jinja" %} + + <h3>Error Log</h3> + {% include "mirrors/error_table.html.jinja" %} </div> + +<div class="box"> + <h2>Mirror Status Charts</h2> + + <p>Periodic checks of the mirrors are done from various geographic + locations, IP addresses, and using IPv4 or IPv6. These results are + summarized in graphical form below.</p> + + <div id="charts-container"></div> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "d3-3.0.6.min.js" %}"></script> +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript" src="{% static "mirror_status.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $("#available_urls:has(tbody tr)").tablesorter( + {widgets: ['zebra'], sortList: [[1,0], [2,0]], + headers: { 8: { sorter: 'mostlydigit' }, 9: { sorter: 'mostlydigit' }, 10: { sorter: 'mostlydigit' } } }); +}); +$(document).ready(function() { + draw_graphs("/mirrors/locations/json/", "./json/", "#charts-container"); +}); +</script> {% endblock %} diff --git a/templates/mirrors/mirror_details_urls.html.jinja b/templates/mirrors/mirror_details_urls.html.jinja new file mode 100644 index 00000000..7ab1548b --- /dev/null +++ b/templates/mirrors/mirror_details_urls.html.jinja @@ -0,0 +1,36 @@ +<table id="available_urls" class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>IPv4</th> + <th>IPv6</th> + <th>Last Sync</th> + <th>Completion %</th> + <th>μ Delay (hh:mm)</th> + <th>μ Duration (s)</th> + <th>σ Duration (s)</th> + <th>Score</th> + <th>Details</th> + </tr> + </thead> + <tbody> + {% for m_url in urls %} + <tr class="{{ loop.cycle('odd', 'even') }}"> + <td>{% if m_url.protocol.is_download %}<a href="{{ m_url.url }}">{{ m_url.url }}</a>{% else %}{{ m_url.url }}{% endif %}</td> + <td>{{ m_url.protocol }}</td> + <td class="country">{{ country_flag(m_url.country) }}{{ m_url.country.name }}</td> + <td>{{ m_url.has_ipv4|yesno|capfirst }}</td> + <td>{{ m_url.has_ipv6|yesno|capfirst }}</td> + <td>{{ m_url.last_sync|date('Y-m-d H:i')|default('unknown') }}</td> + <td>{{ m_url.completion_pct|percentage(1) }}</td> + <td>{{ m_url.delay|duration|default('unknown') }}</td> + <td>{{ m_url.duration_avg|floatvalue(2) }}</td> + <td>{{ m_url.duration_stddev|floatvalue(2) }}</td> + <td>{{ m_url.score|floatvalue(1)|default('∞') }}</td> + <td><a href="{{ m_url.id }}/">Details</a></td> + </tr> + {% endfor %} + </tbody> +</table> diff --git a/templates/mirrors/mirrorlist.txt b/templates/mirrors/mirrorlist.txt index 2eedbd71..b8eada93 100644 --- a/templates/mirrors/mirrorlist.txt +++ b/templates/mirrors/mirrorlist.txt @@ -4,10 +4,10 @@ them, sacrifices have to be made. If editing this template, it is easiest to forget about where line breaks are happening until you are done getting the content right, and then go back later to fix it all up. {% endcomment %}{% autoescape off %}## -## Arch Linux repository mirrorlist +## {{ BRANDING_DISTRONAME }} repository mirrorlist ## Generated on {% now "Y-m-d" %} ##{% for mirror_url in mirror_urls %}{% ifchanged %} -## {{ mirror_url.mirror.country }}{% endifchanged %} +## {{ mirror_url.country.name|default:'Worldwide' }}{% endifchanged %} #Server = {{ mirror_url.url}}$repo/os/$arch{% endfor %} {% endautoescape %} diff --git a/templates/mirrors/index.html b/templates/mirrors/mirrorlist_generate.html index 1d620b14..c2a79fa8 100644 --- a/templates/mirrors/index.html +++ b/templates/mirrors/mirrorlist_generate.html @@ -1,14 +1,15 @@ {% extends "base.html" %} {% load package_extras %} -{% block title %}Arch Linux - Pacman Mirrorlist Generator{% endblock %} +{% load wiki %} +{% block title %}{{ BRANDING_DISTRONAME }} - Pacman Mirrorlist Generator{% endblock %} {% block content %} <div id="mirrorlist-gen" class="box"> <h2>Pacman Mirrorlist Generator</h2> - <p>This page generates the most up-to-date mirrorlist possible for Arch - Linux. The data used here comes straight from the developers' internal + <p>This page generates the most up-to-date mirrorlist possible for {{ BRANDING_DISTRONAME }}. + The data used here comes straight from the developers' internal mirror database used to track mirror availability and tiering. There are two main options: get a mirrorlist with every available mirror, or get a mirrorlist tailored to your geography.</p> @@ -21,22 +22,22 @@ <ul> <li><a href="all/">All mirrors</a></li> - <li><a href="all/ftp/">All mirrors, FTP only</a></li> <li><a href="all/http/">All mirrors, HTTP only</a></li> + <li><a href="all/https/">All mirrors, HTTPS only</a></li> </ul> <h3>Customized by country mirrorlist</h3> <p>The following form can generate a custom up-to-date - <a href="http://wiki.archlinux.org/index.php/Pacman" - title="ArchWiki: Pacman">pacman</a> mirrorlist based on geography and + <a href="{% wiki_url 'Pacman' %}" + title="{{BRANDING_WIKINAME}}: Pacman">pacman</a> mirrorlist based on geography and desired protocol(s). Simply replace the contents of <code>/etc/pacman.d/mirrorlist</code> with your generated list. Additionally, the mirror status data can be incorporated into the generated mirror list and used to pre-order the mirrors.</p> <form id="list-generator" method="get"> - {{ mirrorlist_form.as_p }} + {{ mirrorlist_form.as_div }} <p><label></label> <input type="submit" value="Generate List" /></p> </form> </div> diff --git a/templates/mirrors/mirrorlist_status.txt b/templates/mirrors/mirrorlist_status.txt index e2fbc1e6..746aae76 100644 --- a/templates/mirrors/mirrorlist_status.txt +++ b/templates/mirrors/mirrorlist_status.txt @@ -1,13 +1,14 @@ -{% comment %} +{% load mirror_status %}{% comment %} Yes, ugly templates are ugly, but in order to keep line breaks where we want them, sacrifices have to be made. If editing this template, it is easiest to forget about where line breaks are happening until you are done getting the content right, and then go back later to fix it all up. {% endcomment %}{% autoescape off %}## -## Arch Linux repository mirrorlist +## {{ BRANDING_DISTRONAME }} repository mirrorlist ## Sorted by mirror score from mirror status page ## Generated on {% now "Y-m-d" %} +## {% for mirror_url in mirror_urls %} -## Score: {{ mirror_url.score|floatformat:1|default:'unknown' }}, {{ mirror_url.mirror.country }} +## Score: {{ mirror_url.score|floatvalue:1|default:'unknown' }}, {{ mirror_url.country.name|default:'Worldwide' }} #Server = {{ mirror_url.url}}$repo/os/$arch{% endfor %} {% endautoescape %} diff --git a/templates/mirrors/mirrors.html b/templates/mirrors/mirrors.html index 56f23db5..3450d439 100644 --- a/templates/mirrors/mirrors.html +++ b/templates/mirrors/mirrors.html @@ -1,5 +1,11 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Mirror Overview{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load flags %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Mirror Overview{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} {% block content %} <div id="dev-mirrorlist" class="box"> @@ -8,14 +14,13 @@ <thead> <tr> <th>Server</th> - <th>Tier</th> <th>Country</th> + <th>Tier</th> <th>ISOs</th> <th>Protocols</th> {% if user.is_authenticated %} <th>Public</th> <th>Active</th> - <th>Rsync IPs</th> <th>Admin Email</th> <th>Notes</th> {% endif %} @@ -26,27 +31,26 @@ <tr class="{% cycle 'odd' 'even' %}"> <td><a href="{{ mirror.get_absolute_url }}" title="Mirror details for {{ mirror.name }}">{{ mirror.name }}</a></td> - <td>{{mirror.get_tier_display}}</td> - <td>{{mirror.country}}</td> - <td>{{mirror.isos|yesno}}</td> - <td class="wrap">{{mirror.supported_protocols}}</td> + <td class="country">{% if mirror.country %}{% country_flag mirror.country %}{{ mirror.country.name }}{% else %}Various{% endif %}</td> + <td>{{ mirror.get_tier_display }}</td> + <td>{{ mirror.isos|yesno|capfirst }}</td> + <td class="wrap">{{ mirror.protocols|join:", " }}</td> {% if user.is_authenticated %} - <td>{{mirror.public|yesno}}</td> - <td>{{mirror.active|yesno}}</td> - <td class="wrap">{{mirror.rsync_ips.all|join:', '}}</td> - <td>{{mirror.admin_email}}</td> - <td class="wrap">{{mirror.notes|linebreaks}}</td> + <td>{{ mirror.public|yesno|capfirst }}</td> + <td>{{ mirror.active|yesno|capfirst }}</td> + <td>{{ mirror.admin_email }}</td> + <td class="wrap">{{ mirror.notes|linebreaks }}</td> {% endif %} </tr> {% endfor %} </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> $(document).ready(function() { - $(".results").tablesorter({widgets: ['zebra'], sortList: [[1,0], [2,0]]}); + $(".results").tablesorter({widgets: ['zebra'], sortList: [[2,0], [0,0]]}); }); </script> {% endblock %} diff --git a/templates/mirrors/status.html b/templates/mirrors/status.html index 10f409c9..f11d57ca 100644 --- a/templates/mirrors/status.html +++ b/templates/mirrors/status.html @@ -1,12 +1,16 @@ {% extends "base.html" %} +{% load static from staticfiles %} {% load mirror_status %} +{% load flags %} -{% block title %}Arch Linux - Mirror Status{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Mirror Status{% if tier != None %} - Tier {{ tier }}{% endif %}{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} {% block content %} <div id="mirrorstatus" class="box"> - <h2>Mirror Status</h2> - <p>This page reports the status of all known, public, and active Arch Linux + <h2>Mirror Status{% if tier != None %} - Tier {{ tier }}{% endif %}</h2> + <p>This page reports the status of all known, public, and active {{ BRANDING_DISTRONAME }} mirrors. All data on this page reflects the status of the mirrors within the <em>last {{ cutoff|hours }}</em>. All listed times are UTC. The check script runs on a regular basis and polls for the <tt>lastsync</tt> file in the root of @@ -15,12 +19,8 @@ has synced recently. This page contains several pieces of information about each mirror.</p> <ul> - <li><em>Mirror URL:</em> Mirrors are checked on a per-URL basis. If - both FTP and HTTP access are provided, both will be listed here.</li> - <li><em>Last Sync:</em> The timestamp retrieved from the - <tt>lastsync</tt> file on the mirror. If this file could not be - retrieved or contained data we didn't recognize, this column will show - 'unknown'.</li> + <li><em>Mirror URL:</em> Mirrors are checked on a per-URL basis. All + available URLs and protocols for each known mirror are listed.</li> <li><em>Completion %:</em> The number of mirror checks that have successfully connected and disconnected from the given URL. If this is below 100%, the mirror may be unreliable.</li> @@ -36,8 +36,9 @@ retrieval time. A high standard deviation can indicate an unstable or overloaded mirror.</li> <li><em>Mirror Score:</em> A very rough calculation for ranking - mirrors. It is currently calculated as <tt>hours delay + average - duration + standard deviation</tt>. Lower is better.</li> + mirrors. It is currently calculated as <tt>(hours delay + average + duration + standard deviation) / completion percentage</tt>. Lower + is better.</li> </ul> <p>The final table on this page is an error log, which shows any errors that occurred while contacting mirrors. This only shows errors that @@ -49,93 +50,43 @@ </ul> <p>The last mirror check ran at {{ last_check|date:'Y-m-d H:i' }} UTC. - Checks have ran {{ num_checks }} times in the last {{ cutoff|hours }} at an average - interval of {{ check_frequency|duration }} (hh:mm).</p> + Checks have ran {{ num_checks }} times in the last {{ cutoff|hours }} at + an average interval of {{ check_frequency|duration }} (hh:mm).</p> + + <p>This data is also available in <a href="json/">JSON format</a>. The + units of all time/duration values are in seconds; date/time values are + UTC.</p> <a name="outofsync" id="outofsync"></a> <h3>Out of Sync Mirrors</h3> - {% with bad_urls as urls %} - {% with 'outofsync_mirrors' as table_id %} - {% include "mirrors/status_table.html" %} - {% endwith %} + {% with urls=bad_urls table_id='outofsync_mirrors' %} + {% include "mirrors/status_table.html.jinja" %} {% endwith %} <a name="successful" id="successful"></a> <h3>Successfully Syncing Mirrors</h3> - {% with good_urls as urls %} - {% with 'successful_mirrors' as table_id %} - {% include "mirrors/status_table.html" %} - {% endwith %} + {% with urls=good_urls table_id='successful_mirrors' %} + {% include "mirrors/status_table.html.jinja" %} {% endwith %} <a name="errorlog" id="errorlog"></a> <h3>Mirror Syncing Error Log</h3> - <table id="errorlog_mirrors" class="results"> - <thead> - <tr> - <th>Mirror URL</th> - <th>Protocol</th> - <th>Country</th> - <th>Error Message</th> - <th>Last Occurred</th> - <th>Occurrences (last {{ cutoff|hours }})</th> - </tr> - </thead> - <tbody> - {% for log in error_logs %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ log.url__url }}</td> - <td>{{ log.url__protocol__protocol }}</td> - <td>{{ log.url__mirror__country }}</td> - <td>{{ log.error }}</td> - <td>{{ log.last_occurred|date:'Y-m-d H:i' }}</td> - <td>{{ log.error_count }}</td> - </tr> - {% endfor %} - </tbody> - </table> - + {% include "mirrors/error_table.html.jinja" %} </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> -$.tablesorter.addParser({ - /* sorts numeric, but put '', 'unknown', and '∞' last. */ - id: 'mostlydigit', - is: function(s,table) { - var special = ['', 'unknown', '∞']; - var c = table.config; - return ($.inArray(s, special) > -1) || $.tablesorter.isDigit(s,c); - }, - format: function(s) { - var special = ['', 'unknown', '∞']; - if($.inArray(s, special) > -1) return Number.MAX_VALUE; - return $.tablesorter.formatFloat(s); - }, - type: 'numeric' -}); -$.tablesorter.addParser({ - /* sorts duration; put '', 'unknown', and '∞' last. */ - id: 'duration', - is: function(s,table) { - var special = ['', 'unknown', '∞']; - return ($.inArray(s, special) > -1) || /^[0-9]+:[0-5][0-9]$/.test(s); - }, - format: function(s) { - var special = ['', 'unknown', '∞']; - if($.inArray(s, special) > -1) return Number.MAX_VALUE; - matches = /^([0-9]+):([0-5][0-9])$/.exec(s); - return matches[1] * 60 + matches[2]; - }, - type: 'numeric' -}); $(document).ready(function() { + var headers = { 4: { sorter: 'duration' }, 5: { sorter: 'mostlydigit' }, + 6: { sorter: 'mostlydigit' }, 7: { sorter: 'mostlydigit' }, + 8: { sorter: false } }; $("#outofsync_mirrors:has(tbody tr)").tablesorter( - {widgets: ['zebra'], sortList: [[3,1]], - headers: { 6: { sorter: 'mostlydigit' }, 7: { sorter: 'mostlydigit' }, 8: { sorter: 'mostlydigit' } } }); + {widgets: ['zebra'], sortList: [[4,0]], headers: headers }); $("#successful_mirrors:has(tbody tr)").tablesorter( - {widgets: ['zebra'], sortList: [[8,0]], - headers: { 6: { sorter: 'mostlydigit' }, 7: { sorter: 'mostlydigit' }, 8: { sorter: 'mostlydigit' } } }); + {widgets: ['zebra'], sortList: [[7,0]], headers: headers }); $("#errorlog_mirrors:has(tbody tr)").tablesorter( {widgets: ['zebra'], sortList: [[4,1], [5,1]]}); }); diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html deleted file mode 100644 index 240a5452..00000000 --- a/templates/mirrors/status_table.html +++ /dev/null @@ -1,31 +0,0 @@ -{% load mirror_status %} -<table id="{{ table_id }}" class="results"> - <thead> - <tr> - <th>Mirror URL</th> - <th>Protocol</th> - <th>Country</th> - <th>Last Sync</th> - <th>Completion %</th> - <th>μ Delay (hh:mm)</th> - <th>μ Duration (secs)</th> - <th>σ Duration (secs)</th> - <th>Mirror Score</th> - </tr> - </thead> - <tbody> - {% for m_url in urls %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ m_url.url }}</td> - <td>{{ m_url.protocol }}</td> - <td>{{ m_url.mirror.country }}</td> - <td>{{ m_url.last_sync|date:'Y-m-d H:i'|default:'unknown' }}</td> - <td>{{ m_url.completion_pct|percentage:1 }}</td> - <td>{{ m_url.delay|duration|default:'unknown' }}</td> - <td>{{ m_url.duration_avg|floatformat:2 }}</td> - <td>{{ m_url.duration_stddev|floatformat:2 }}</td> - <td>{{ m_url.score|floatformat:1|default:'∞' }}</td> - </tr> - {% endfor %} - </tbody> -</table> diff --git a/templates/mirrors/status_table.html.jinja b/templates/mirrors/status_table.html.jinja new file mode 100644 index 00000000..598a1af0 --- /dev/null +++ b/templates/mirrors/status_table.html.jinja @@ -0,0 +1,28 @@ +<table id="{{ table_id }}" class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>Completion %</th> + <th>μ Delay (hh:mm)</th> + <th>μ Duration (s)</th> + <th>σ Duration (s)</th> + <th>Mirror Score</th> + <th></th> + </tr> + </thead> + <tbody> + {% for m_url in urls %}<tr class="{{ loop.cycle('odd', 'even') }}"> + <td>{{ m_url.url }}</td> + <td>{{ m_url.protocol }}</td> + <td class="country">{{ country_flag(m_url.country) }}{{ m_url.country.name }}</td> + <td>{{ m_url.completion_pct|percentage(1) }}</td> + <td>{{ m_url.delay|duration|default('unknown') }}</td> + <td>{{ m_url.duration_avg|floatvalue(2) }}</td> + <td>{{ m_url.duration_stddev|floatvalue(2) }}</td> + <td>{{ m_url.score|floatvalue(1)|default('∞') }}</td> + <td><a href="{{ m_url.get_absolute_url() }}">details</a></td> + </tr>{% endfor %} + </tbody> +</table> diff --git a/templates/mirrors/url_details.html b/templates/mirrors/url_details.html new file mode 100644 index 00000000..96fcc49d --- /dev/null +++ b/templates/mirrors/url_details.html @@ -0,0 +1,74 @@ +{% extends "base.html" %} +{% load static from staticfiles %} +{% load mirror_status %} +{% load flags %} + +{% block title %}{{ BRANDING_DISTRONAME }} - {{ url.url }} - URL Details{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} + +{% block content %} +<div class="box"> + <h2>URL Details: {{ url.url }}</h2> + + <table class="compact"> + <tr> + <th>URL:</th> + <td>{% if url.protocol.is_download %}<a href="{{ url.url }}">{{ url.url }}</a>{% else %}{{ url.url }}{% endif %}</td> + </tr> + <tr> + <th>Mirror:</th> + <td><a href="../">{{ url.mirror.name }}</a></td> + </tr> + <tr> + <th>Protocol:</th> + <td>{{ url.protocol }}</td> + </tr> + <tr> + <th>Country:</th> + <td class="country">{% country_flag url.country %}{{ url.country.name }}</td> + </tr> + <tr> + <th>IPv4:</th> + <td>{{ url.has_ipv4|yesno|capfirst }}</td> + </tr> + <tr> + <th>IPv6:</th> + <td>{{ url.has_ipv6|yesno|capfirst }}</td> + </tr> + {% if user.is_authenticated %} + <tr> + <th>Active:</th> + <td>{{ url.active|yesno|capfirst }}</td> + </tr> + <tr> + <th>Created:</th> + <td>{{ url.created }}</td> + </tr> + <tr> + <th>First Check:</th> + <td>{{ url.logs.earliest.check_time }}</td> + </tr> + <tr> + <th>Last Check:</th> + <td>{{ url.logs.latest.check_time }}</td> + </tr> + {% endif %} + </table> + + <h3>Check Logs</h3> + {% include "mirrors/url_details_logs.html.jinja" %} +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $("#check_logs:has(tbody tr)").tablesorter( + {widgets: ['zebra'], sortList: [[0,1]], + headers: { 5: { sorter: 'mostlydigit' } } }); +}); +</script> +{% endblock %} diff --git a/templates/mirrors/url_details_logs.html.jinja b/templates/mirrors/url_details_logs.html.jinja new file mode 100644 index 00000000..51f54931 --- /dev/null +++ b/templates/mirrors/url_details_logs.html.jinja @@ -0,0 +1,26 @@ +<table id="check_logs" class="results"> + <thead> + <tr> + <th>Check Time</th> + <th>Check Location</th> + <th>Check IP</th> + <th>Last Sync</th> + <th>Delay (hh:mm)</th> + <th>Duration (s)</th> + <th>Success?</th> + <th>Error Message</th> + </tr> + </thead> + <tbody> + {% for log in logs %}<tr class="{{ loop.cycle('odd', 'even') }}"> + <td>{{ log.check_time|date('Y-m-d H:i') }}</td> + <td class="country">{% if log.location %}{{ country_flag(log.location.country) }}{{ log.location.country.name }}{% else %}Unknown{% endif %}</td> + <td>{% if log.location %}{{ log.location.source_ip }}{% else %}Unknown{% endif %}</td> + <td>{{ log.last_sync|date('Y-m-d H:i') }}</td> + <td>{{ log.delay|duration }}</td> + <td>{{ log.duration|floatvalue }}</td> + <td>{{ log.is_success|yesno|capfirst }}</td> + <td class="wrap">{{ log.error|linebreaksbr }}</td> + </tr>{% endfor %} + </tbody> +</table> diff --git a/templates/news/add.html b/templates/news/add.html index 48b013f0..a09366dc 100644 --- a/templates/news/add.html +++ b/templates/news/add.html @@ -1,5 +1,6 @@ {% extends "base.html" %} -{% block title %}Arch Linux - News: {% if form.instance.id %}Edit{% else %}Add{% endif %} Article{% endblock %} +{% load static from staticfiles %} +{% block title %}{{ BRANDING_DISTRONAME }} - News: {% if form.instance.id %}Edit{% else %}Add{% endif %} Article{% endblock %} {% block content %} <div id="news-add-article" class="box"> @@ -23,29 +24,18 @@ <p> <label></label> <input title="Save changes" type="submit" value="Save" /> - <input id="previewbtn" title="Preview" type="button" value="Preview" /> + <input id="news-preview-button" title="Preview" type="button" value="Preview" /> </p> </form> </div> -<div class="news-article box" style="display:none;"> - <h2>News Preview: <span id="previewtitle"></span></h2> - <div id="previewdata" class="article-content"></div> +<div id="news-preview" class="news-article box" style="display:none;"> + <h2>News Preview: <span id="news-preview-title"></span></h2> + <div id="news-preview-data" class="article-content"></div> </div> {% load cdn %}{% jquery %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> -function enablePreview() { - $('#previewbtn').click(function(event) { - event.preventDefault(); - $.post('/news/preview/', - { data: $('#id_content').val() }, - function(data) { - $('#previewdata').html(data); - $('.news-article').show(); - }); - $('#previewtitle').html($('#id_title').val()); - }); -} $(document).ready(enablePreview); </script> {% endblock %} diff --git a/templates/news/delete.html b/templates/news/delete.html index 191c6929..d8f71bd5 100644 --- a/templates/news/delete.html +++ b/templates/news/delete.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Delete News{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Delete News{% endblock %} {% block content %} <div id="news-delete-entry" class="box"> diff --git a/templates/news/list.html b/templates/news/list.html index a72a2dda..8662a91b 100644 --- a/templates/news/list.html +++ b/templates/news/list.html @@ -1,10 +1,16 @@ {% extends "base.html" %} -{% block title %}Arch Linux - News{% endblock %} +{% load cycle from future %} + +{% block title %}{{ BRANDING_DISTRONAME }} - News{% endblock %} + +{% block head %} +<link rel="alternate" type="application/rss+xml" title="{{BRANDING_DISTRONAME}} News Updates" href="/feeds/news/" /> +{% endblock %} {% block content %} <div id="news-article-list" class="box"> - <h2>News Archives</h2> + <h2>{{ BRANDING_DISTRONAME }} News Archives</h2> {% if perms.news.add_news %} <ul class="admin-actions"> @@ -48,6 +54,5 @@ </table> {% include "news/paginator.html" %} - </div> {% endblock %} diff --git a/templates/news/paginator.html b/templates/news/paginator.html index fbd0546b..57fbeb15 100644 --- a/templates/news/paginator.html +++ b/templates/news/paginator.html @@ -1,20 +1,20 @@ {% if is_paginated %} <div class="pagination"> - <p>{{paginator.count}} news items, viewing page {{page_obj.number}} of {{paginator.num_pages}}.</p> + <p>{{ paginator.count }} news items, viewing page {{ page_obj.number }} of {{ paginator.num_pages }}.</p> <p class="news-nav"> {% if page_obj.has_previous %} - <a class="prev" href="?page={{page_obj.previous_page_number}}" + <a class="prev" href="?page={{ page_obj.previous_page_number }}" title="Go to previous page">< Prev</a> {% endif %} {% for num in paginator.page_range %} {% ifequal num page_obj.number %} - <span>{{num}}</span> + <span>{{ num }}</span> {% else %} - <a href="?page={{num}}" title="Go to page {{num}}">{{num}}</a> + <a href="?page={{ num }}" title="Go to page {{ num }}">{{ num }}</a> {% endifequal %} {% endfor %} {% if page_obj.has_next %} - <a class="next" href="?page={{page_obj.next_page_number}}" + <a class="next" href="?page={{ page_obj.next_page_number }}" title="Go to next page">Next ></a> {% endif %} </p> diff --git a/templates/news/view.html b/templates/news/view.html index 7788dece..93cf32d4 100644 --- a/templates/news/view.html +++ b/templates/news/view.html @@ -1,11 +1,20 @@ {% extends "base.html" %} -{% load markup %} -{% block title %}Arch Linux - News: {{ news.title }}{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - News: {{ news.title }}{% endblock %} {% block content %} -<div class="news-article box"> - - <h2>News: {{ news.title }}</h2> +<div itemscope itemtype="http://schema.org/Article" class="news-article box"> + <h2 itemprop="headline">{{ news.title }}</h2> + <meta itemprop="dateCreated" content="{{ news.postdate|date:"Y-m-d" }}"/> + <meta itemprop="datePublished" content="{{ news.postdate|date:"Y-m-d" }}"/> + <meta itemprop="dateModified" content="{{ news.last_modified|date:"Y-m-d" }}"/> + <meta itemprop="inLanguage" content="en"/> + <meta itemprop="wordCount" content="{{ news.content|wordcount }}"/> + <div style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person"> + <meta itemprop="name" content="{{ news.author.get_full_name|escape }}"/> + </div> + <div style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization"> + <meta itemprop="name" content="{{ BRANDING_DISTRONAME }}"/> + </div> {% if perms.news.change_news %} <ul class="admin-actions"> @@ -18,7 +27,6 @@ <p class="article-info">{{ news.postdate|date }} - {{ news.author.get_full_name }}</p> - <div class="article-content">{{ news.content|markdown }}</div> - + <div class="article-content" itemprop="articleBody">{{ news.html }}</div> </div> {% endblock %} diff --git a/templates/packages/details.html b/templates/packages/details.html index f84b85ef..82f2c604 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -1,226 +1,22 @@ {% extends "base.html" %} -{% load cache %} +{% load static from staticfiles %} -{% block title %}Arch Linux - {{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }} - Package Details{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - {{ pkg.pkgname }} {{ pkg.full_version }} ({{ pkg.arch.name }}){% endblock %} {% block navbarclass %}anb-packages{% endblock %} -{% load package_extras %} {% block content %} -<div id="pkgdetails" class="box"> - - <h2>Package Details: {{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }}</h2> - - <div id="detailslinks" class="listing"> - - <div id="actionlist"> - <h4>Package Actions</h4> - <ul class="small"> - <li><a href="{{ pkg.get_arch_svn_link }}" title="View SVN entries in the {{pkg.repo|lower}}-{{pkg.arch}} branch">SVN Entries ({{pkg.repo|lower}}-{{pkg.arch}})</a></li> - <li><a href="{{ pkg.get_trunk_svn_link }}" title="View SVN entries on trunk">SVN Entries (trunk)</a></li> - <li><a href="{{ pkg.get_bugs_link }}" title="View existing bug tickets for {{ pkg.pkgname }}">Bug Reports</a></li> - {% if pkg.flag_date %} - <li><span class="flagged">Package has been flagged out-of-date</span></li> - {% with pkg.in_testing as tp %}{% if tp %} - <li><span class="flagged">Version - <a href="{{ tp.get_absolute_url }}" - title="Testing package details for {{ tp.pkgname }}">{{ tp.pkgver }}-{{ tp.pkgrel }}</a> - in testing</span></li> - {% endif %}{% endwith %} - {% if user.is_authenticated %} - <li><a href="unflag/" title="Unflag this package">Click here to unflag</a></li> - {% endif %} - {% else %} - <li><a href="flag/" title="Flag {{ pkg.pkgname }} as out-of-date">Flag Package Out-of-Date</a> - <a href="/packages/flaghelp/" - title="Get help on package flagging" - onclick="return !window.open('/packages/flaghelp/','FlagHelp', - 'height=350,width=450,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=no');">(?)</a></li> - {% endif %} - <li><a href="download/" title="Download {{ pkg.pkgname }} from mirror">Download From Mirror</a></li> - </ul> - - {% if user.is_authenticated %} - <form id="pkg-action" method="post" action="/packages/update/">{% csrf_token %} - <div><input type="hidden" name="pkgid" value="{{ pkg.id }}" /></div> - <p>{% if user in pkg.maintainers %} - <input title="Orphan this package" type="submit" name="disown" value="Disown"/> - {% else %} - <input title="Adopt this package" type="submit" name="adopt" value="Adopt"/> - {% endif %}</p> - </form> - {% endif %} - </div> - - {% with pkg.elsewhere as others %}{% if others %} - <div id="elsewhere" class="widget"> - <h4>Versions Elsewhere</h4> - <ul> - {% for o in others %} - <li><a href="{{ o.get_absolute_url }}" - title="Package details for {{ o.pkgname }}">{{ o.pkgname }} {{ o.pkgver }}-{{ o.pkgrel }} [{{ o.repo.name|lower }}] ({{ o.arch.name }})</a></li> - {% endfor %} - </ul> - </div> - {% endif %}{% endwith %} - - </div><!-- #actionlist --> - - {% cache 300 package-details-pkginfo pkg.id %} - <table id="pkginfo"> - <tr> - <th>Architecture:</th> - <td><a href="/packages/?arch={{ pkg.arch.name }}" - title="Browse packages for {{ pkg.arch.name }} architecture">{{ pkg.arch.name }}</a></td> - </tr><tr> - <th>Repository:</th> - <td><a href="/packages/?repo={{ pkg.repo.name|capfirst }}" - title="Browse the {{ pkg.repo.name|capfirst }} repository">{{ pkg.repo.name|capfirst }}</a></td> - </tr> - {% ifequal pkg.pkgname pkg.pkgbase %} - {% with pkg.split_packages as splits %}{% if splits %} - <tr> - <th>Split Packages:</th> - <td> - {% for s in splits %} - <a href="{{ s.get_absolute_url }}" - title="Package details for {{ s.pkgname }}">{{ s.pkgname }}</a><br/> - {% endfor %} - </td> - </tr> - {% endif %}{% endwith %} - {% else %} - <tr> - <th>Base Package:</th> - {% if pkg.base_package %} - <td><a href="{{ pkg.base_package.get_absolute_url }}" - title="Package details for {{ pkg.base_package.pkgname }}">{{ pkg.pkgbase }}</a></td> - {% else %} - <td>{{ pkg.pkgbase }}</td> - {% endif %} - </tr> - {% endifequal %} - <tr> - <th>Description:</th> - <td class="wrap">{% if pkg.pkgdesc %}{{ pkg.pkgdesc }}{% endif %}</td> - </tr><tr> - <th>Upstream URL:</th> - <td>{% if pkg.url %}<a href="{{ pkg.url }}" - title="Visit the website for {{ pkg.pkgname }}">{{ pkg.url }}</a>{% endif %}</td> - </tr><tr> - <th>License:</th> - <td>{{ pkg.license }}</td> - </tr><tr> - <th>Groups:</th> - {% with pkg.packagegroup_set.all as groups %} - <td>{% if groups %} - {% for g in groups %} - <a href="/groups/{{ pkg.arch.name }}/{{ g.name }}/" - title="Group details for {{ g.name }}">{{ g.name }}</a><br/> - {% endfor %} - {% else %}None{% endif %} - </td> - {% endwith %} - </tr><tr> - <th>Maintainers:</th> - {% with pkg.maintainers as maints %} - <td>{% if maints %} - {% for m in maints %} - {% userpkgs m %}<br/> - {% endfor %} - {% else %}Orphan{% endif %} - </td> - {% endwith %} - </tr><tr> - <th>Package Size:</th> - <td>{{ pkg.compressed_size|filesizeformat }}</td> - </tr><tr> - <th>Installed Size:</th> - <td>{{ pkg.installed_size|filesizeformat }}</td> - </tr><tr> - <th>Last Packager:</th> - <td>{% with pkg.packager as pkgr %}{% if pkgr %}{% userpkgs pkgr %}{% else %}{{ pkg.packager_str }}{% endif %}{% endwith %}</td> - </tr><tr> - <th>Build Date:</th> - <td>{{ pkg.build_date }} UTC</td> - </tr><tr> - <th>Last Updated:</th> - <td>{{ pkg.last_update|date }}</td> - </tr> - </table> - - <div id="metadata"> - - {% with pkg.get_depends as deps %} - <div id="pkgdeps" class="listing"> - - <h3 title="{{ pkg.pkgname }} has the following dependencies"> - Dependencies ({{deps|length}})</h3> - - {% if deps %} - <ul> - {% for depend in deps %} - {% ifequal depend.pkg None %} - <li>{{ depend.dep.depname }} (virtual)</li> - {% else %} - <li><a href="{{ depend.pkg.get_absolute_url }}" - title="View package details for {{ depend.dep.depname }}">{{ depend.dep.depname }}</a> - {{ depend.dep.depvcmp }}{% if depend.pkg.repo.testing %} - <span class="testing-dep">(testing)</span>{% endif %}</li> - {% endifequal %} - {% endfor %} - </ul> - {% endif %} - - </div><!-- #pkgdeps --> - {% endwith %} - - {% with pkg.get_requiredby as rqdby %} - <div id="pkgreqs" class="listing"> - - <h3 title="Packages that require {{ pkg.pkgname }}"> - Required By ({{rqdby|length}})</h3> - - {% if rqdby %} - <ul> - {% for req in rqdby %} - <li><a href="{{req.get_absolute_url}}" - title="View package details for {{ req.pkgname }}">{{ req.pkgname }}</a> - {% if req.repo.testing %} (testing){% endif %}</li> - {% endfor %} - </ul> - {% endif %} - - </div><!-- #pkgreqs --> - {% endwith %} - - <div id="pkgfiles" class="listing"> - - <h3 title="Complete list of files contained within this package"> - Package Contents</h3> - - <div id="pkgfilelist"> - <p><a id="filelink" href="files/" - title="Click to view the complete file list for {{ pkg.pkgname }}"> - View the file list for {{ pkg.pkgname }}</a></p> - </div> - - </div><!-- #pkgfiles --> - - </div><!-- #metadata --> - {% endcache %} - -</div><!-- #pkgdetails --> +{% include "packages/details.html.jinja" %} +{% endblock %} +{% block script_block %} {% load cdn %}{% jquery %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> -function ajaxifyFiles() { - $('#filelink').click(function(event) { - event.preventDefault(); - $.get(this.href, function(data) { - $('#pkgfilelist').html(data); - }); - }); -} -$(document).ready(ajaxifyFiles); +$(document).ready(function() { + ajaxifyFiles(); + collapseDependsList("#pkgdepslist"); + collapseDependsList("#pkgreqslist"); + collapseRelatedTo(".relatedto"); +}); </script> {% endblock %} diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja new file mode 100644 index 00000000..80508392 --- /dev/null +++ b/templates/packages/details.html.jinja @@ -0,0 +1,230 @@ +{% import 'packages/details_link.html.jinja' as details %} +<div id="pkgdetails" class="box"> + <h2>{{ pkg.pkgname }} {{ pkg.full_version }}</h2> + + <div id="detailslinks" class="listing"> + <div id="actionlist"> + <h4>Package Actions</h4> + <ul class="small"> + <li> + <a href="{{ scm_link(pkg, 'tree') }}" title="View source files for {{ pkg.pkgname }}">Source Files</a> / + <a href="{{ scm_link(pkg, 'log') }}" title="View changes for {{ pkg.pkgname }}">View Changes</a> + </li> + <li> + <a href="{{ bugs_list(pkg) }}" title="View existing bug tickets for {{ pkg.pkgname }}">Bug Reports</a> / + <a href="{{ bug_report(pkg) }}" title="Report new bug for {{ pkg.pkgname }}">Add New Bug</a> + / <a href="{{ flag_unfree(pkg) }}" title="Report {{ pkg.pkgname }} as unfree">Report as unfree</a> + </li> + <li><a href="{{ wiki_link(pkg) }}" title="Search wiki for {{ pkg.pkgname }}">Search Wiki</a></li> + {% if pkg.flag_date %} + <li><span class="flagged">Flagged out-of-date on {{ pkg.flag_date|date }}</span></li> + {% with tp = pkg.in_testing() %}{% if tp %} + <li><span class="flagged">Version + <a href="{{ tp.get_absolute_url() }}" + title="Testing package details for {{ tp.pkgname }}">{{ tp.full_version }}</a> + in testing</span></li> + {% endif %}{% endwith %} + {% if perms.main.change_package %} + <li><a href="unflag/" title="Unflag this package">Click here to unflag</a></li> + <li><a href="unflag/all/" title="Unflag all matching pkgbase">Click here to unflag all split packages</a></li> + {% endif %} + {% else %} + {% if pkg.repo.name != "Core" and pkg.repo.name != "Extra" and pkg.repo.name != "Testing" and pkg.repo.name != "Community" and pkg.repo.name != "Community-Testing" and pkg.repo.name != "Multilib" and pkg.repo.name != "Multilib-testing" or pkg.arch.name == "mips64el" %} + <li><a href="flag/" title="Flag {{ pkg.pkgname }} as out-of-date">Flag Package Out-of-Date</a> + <a href="/packages/flaghelp/" + title="Get help on package flagging" + onclick="return !window.open('/packages/flaghelp/','FlagHelp', + 'height=350,width=450,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=no');">(?)</a></li> + {% elif pkg.arch.name == "i686" or pkg.arch.name == "x86_64" %} + <li>This package comes from Arch</li> + {% elif pkg.arch.name == "armv7h" %} + <li>This package comes from Arch ARM</li> + {% endif %} + {% endif %} + <li><a href="download/" rel="nofollow" title="Download {{ pkg.pkgname }} from mirror">Download From Mirror</a></li> + </ul> + + {% if perms.main.change_package %} + <form id="pkg-action" method="post" action="/packages/update/">{% csrf_token %} + <div><input type="hidden" name="pkgid" value="{{ pkg.id }}" /></div> + <p>{% if user in pkg.maintainers %} + <input title="Orphan this package" type="submit" name="disown" value="Disown"/> + {% else %} + <input title="Adopt this package" type="submit" name="adopt" value="Adopt"/> + {% endif %}</p> + </form> + {% endif %} + </div> + + {% with others = pkg.elsewhere() %}{% if others %} + <div id="elsewhere" class="widget"> + <h4>Versions Elsewhere</h4> + <ul> + {% for o in others %} + <li><a href="{{ o.get_absolute_url() }}" + title="Package details for {{ o.pkgname }}">{{ o.pkgname }} {{ o.full_version }} [{{ o.repo.name|lower }}] ({{ o.arch.name }})</a></li> + {% endfor %} + </ul> + </div> + {% endif %}{% endwith %} + </div> + + <div itemscope itemtype="http://schema.org/SoftwareApplication"> + <meta itemprop="name" content="{{ pkg.pkgname|escape }}"/> + <meta itemprop="version" content="{{ pkg.full_version|escape }}"/> + <meta itemprop="softwareVersion" content="{{ pkg.full_version|escape }}"/> + <meta itemprop="fileSize" content="{{ pkg.compressed_size }}"/> + <meta itemprop="dateCreated" content="{{ pkg.build_date|date("Y-m-d") }}"/> + <meta itemprop="datePublished" content="{{ pkg.last_update|date("Y-m-d") }}"/> + <meta itemprop="operatingSystem" content="{{ BRANDING_DISTRONAME }}"/> + {% if pkg.packager %}<div style="display:none" itemprop="provider" itemscope itemtype="http://schema.org/Person"> + <meta itemprop="name" content="{{ pkg.packager.get_full_name()|escape }}"/> + </div>{% endif %} + <table id="pkginfo"> + <tr> + <th>Architecture:</th> + <td><a href="/packages/?arch={{ pkg.arch.name }}" + title="Browse packages for {{ pkg.arch.name }} architecture">{{ pkg.arch.name }}</a></td> + </tr><tr> + <th>Repository:</th> + <td><a href="/packages/?repo={{ pkg.repo.name|capfirst }}" + title="Browse the {{ pkg.repo.name|capfirst }} repository">{{ pkg.repo.name|capfirst }}</a></td> + </tr> + {% if pkg.pkgname == pkg.pkgbase %} + {% with splits = pkg.split_packages() %}{% if splits %} + <tr> + <th>Split Packages:</th> + <td class="wrap relatedto">{% for s in splits %}<span class="related">{{ details.details_link(s) }}{% if not loop.last %}, {% endif %}</span>{% endfor %}</td> + </tr> + {% endif %}{% endwith %} + {% else %} + <tr> + <th>Base Package:</th> + {% with base = pkg.base_package() %}{% if base %} + <td>{{ details.details_link(base) }}</td> + {% else %} + <td><a href="../{{ pkg.pkgbase }}/" + title="Split package details for {{ pkg.pkgbase }}">{{ pkg.pkgbase }}</a></td> + {% endif %}{% endwith %} + </tr> + {% endif %} + <tr> + <th>Description:</th> + <td class="wrap" itemprop="description">{{ pkg.pkgdesc|default("", true) }}</td> + </tr><tr> + <th>Upstream URL:</th> + <td>{% if pkg.url %}<a itemprop="url" href="{{ pkg.url }}" + title="Visit the website for {{ pkg.pkgname }}">{{ pkg.url|url_unquote }}</a>{% endif %}</td> + </tr><tr> + <th>License(s):</th> + <td class="wrap">{{ pkg.licenses.all()|join(", ") }}</td> + </tr> + {% with groups = pkg.groups.all() %}{% if groups %} + <tr> + <th>Groups:</th> + <td class="wrap">{% for g in groups %} + <a href="/groups/{{ pkg.arch.name }}/{{ g.name }}/" + title="Group details for {{ g.name }}">{{ g.name }}</a>{% if not loop.last %}, {% endif %}{% endfor %} + </td> + </tr> + {% endif %}{% endwith %} + {% with all_related = pkg.provides.all() %}{% if all_related %} + <tr> + <th>Provides:</th> + <td class="wrap relatedto">{% include "packages/details_relatedto.html.jinja" %}</td> + </tr> + {% endif %}{% endwith %} + {% with all_related = pkg.replaces.all() %}{% if all_related %} + <tr> + <th>Replaces:</th> + <td class="wrap relatedto">{% include "packages/details_relatedto.html.jinja" %}</td> + </tr> + {% endif %}{% endwith %} + {% with all_related = pkg.conflicts.all() %}{% if all_related %} + <tr> + <th>Conflicts:</th> + <td class="wrap relatedto">{% include "packages/details_relatedto.html.jinja" %}</td> + </tr> + {% endif %}{% endwith %} + {% with rev_conflicts = pkg.reverse_conflicts() %}{% if rev_conflicts %} + <tr> + <th>Reverse Conflicts:</th> + <td class="wrap relatedto">{% for conflict in rev_conflicts %} + <span class="related">{{ details.details_link(conflict) }}{% if not loop.last %}, {% endif %}</span>{% endfor %}</td> + </tr> + {% endif %}{% endwith %} + <tr> + <th>Maintainers:</th> + {% with maints = pkg.maintainers %} + <td>{% if maints %}{% for m in maints %} + <a href="/packages/?maintainer={{ m.username }}" + title="View packages maintained by {{ m.get_full_name() }}">{{ m.get_full_name() }}</a><br/> + {% endfor %}{% else %}Orphan{% endif %} + </td> + {% endwith %} + </tr><tr> + <th>Package Size:</th> + <td>{{ pkg.compressed_size|filesizeformat }}</td> + </tr><tr> + <th>Installed Size:</th> + <td>{{ pkg.installed_size|filesizeformat }}</td> + </tr><tr> + <th>Last Packager:</th> + <td>{% with pkgr = pkg.packager %}{% if pkgr %} + <a href="/packages/?packager={{ pkgr.username }}" + title="View packages packaged by {{ pkgr.get_full_name() }}">{{ pkgr.get_full_name() }}</a> + {% else %}{{ pkg.packager_str }}{% endif %}{% endwith %}</td> + </tr><tr> + <th>Build Date:</th> + <td>{{ pkg.build_date|date("DATETIME_FORMAT") }} UTC</td> + </tr>{% if pkg.signature %}<tr> + <th>Signed By:</th> + <td>{% with signer = pkg.signer %}{% if signer %}{{ pgp_key_link(pkg.signature.key_id, signer.get_full_name())|safe }}{% else %}Unknown ({{ pgp_key_link(pkg.signature.key_id)|safe }}){% endif %}{% endwith %}</td> + </tr><tr> + <th>Signature Date:</th> + <td>{{ pkg.signature.creation_time|date("DATETIME_FORMAT") }} UTC</td> + </tr>{% else %}<tr> + <th>Signed By:</th> + <td>Unsigned</td> + </tr>{% endif %}<tr> + <th>Last Updated:</th> + <td>{{ pkg.last_update|date("DATETIME_FORMAT") }} UTC</td> + </tr> + {% if user.is_authenticated() %}{% with flag_request = pkg.flag_request() %}{% if flag_request %}<tr> + <th>Last Flag Request:</th> + <td class="wrap">From {{ flag_request.who() }} on {{ flag_request.created|date }}:<br/> + <div class="userdata">{{ flag_request.message|linebreaksbr|default("{no message}", true) }}</div></td> + </tr>{% endif %}{% endwith %}{% endif %} + </table> + </div> + + <div id="metadata"> + {% with deps = pkg.get_depends() %} + <div id="pkgdeps" class="listing"> + <h3 title="{{ pkg.pkgname }} has the following dependencies"> + Dependencies ({{deps|length}})</h3> + {% if deps %}<ul id="pkgdepslist"> + {% for depend in deps %}{% include "packages/details_depend.html.jinja" %}{% endfor %} + </ul>{% endif %} + </div> + {% endwith %} + {% with rqdby = pkg.get_requiredby() %} + <div id="pkgreqs" class="listing"> + <h3 title="Packages that require {{ pkg.pkgname }}"> + Required By ({{rqdby|length}})</h3> + {% if rqdby %}<ul id="pkgreqslist"> + {% for req in rqdby %}{% include "packages/details_requiredby.html.jinja" %}{% endfor %} + </ul>{% endif %} + </div> + {% endwith %} + <div id="pkgfiles" class="listing"> + <h3 title="Complete list of files contained within this package"> + Package Contents</h3> + <div id="pkgfilelist"> + <p><a id="filelink" href="files/" + title="Click to view the complete file list for {{ pkg.pkgname }}"> + View the file list for {{ pkg.pkgname }}</a></p> + </div> + </div> + </div> +</div> diff --git a/templates/packages/details_depend.html.jinja b/templates/packages/details_depend.html.jinja new file mode 100644 index 00000000..a2d3a010 --- /dev/null +++ b/templates/packages/details_depend.html.jinja @@ -0,0 +1,13 @@ +{% import 'packages/details_link.html.jinja' as details %}<li>{% if depend.pkg == None %} +{% if depend.providers %}{{ depend.dep.name }}{{ depend.dep.comparison|default("", true) }}{{ depend.dep.version|default("", true) }} <span class="virtual-dep">({% for pkg in depend.providers %}{{ details.details_link(pkg) }}{% if not loop.last %}, {% endif %}{% endfor %})</span> +{% else %}{{ depend.dep.name }}{{ depend.dep.comparison|default("", true) }}{{ depend.dep.version|default("", true) }} <span class="virtual-dep">(virtual)</span> +{% endif %}{% else %} +{{ details.details_link(depend.pkg) }}{{ depend.dep.comparison|default("", true) }}{{ depend.dep.version|default("", true) }} +{% if depend.pkg.repo.testing %} <span class="testing-dep"> (testing)</span> +{% endif %}{% if depend.pkg.repo.staging %} <span class="staging-dep"> (staging)</span> +{% endif %}{% endif %} +{% if depend.dep.deptype == 'O' %} <span class="opt-dep"> (optional)</span> +{% endif %}{% if depend.dep.deptype == 'M' %} <span class="make-dep"> (make)</span> +{% endif %}{% if depend.dep.deptype == 'C' %} <span class="check-dep"> (check)</span> +{% endif %}{% if depend.dep.description %} - <span class="dep-desc">{{ depend.dep.description }}</span> +{% endif %}</li> diff --git a/templates/packages/details_link.html.jinja b/templates/packages/details_link.html.jinja new file mode 100644 index 00000000..b7e75fe5 --- /dev/null +++ b/templates/packages/details_link.html.jinja @@ -0,0 +1 @@ +{% macro details_link(pkg) %}<a href="{{ pkg.get_absolute_url() }}" title="View package details for {{ pkg.pkgname }}">{{ pkg.pkgname }}</a>{% endmacro %} diff --git a/templates/packages/details_relatedto.html.jinja b/templates/packages/details_relatedto.html.jinja new file mode 100644 index 00000000..818224de --- /dev/null +++ b/templates/packages/details_relatedto.html.jinja @@ -0,0 +1,3 @@ +{% import 'packages/details_link.html.jinja' as details %}{% for related in all_related %}{% with best_satisfier = related.get_best_satisfier() %} +<span class="related">{% if best_satisfier == None %}{{ related.name }}{% else %}{{ details.details_link(best_satisfier) }}{% endif %}{{ related.comparison|default('', true) }}{{ related.version|default('', true) }}{% if not loop.last %}, {% endif %}</span> +{% endwith %}{% endfor %} diff --git a/templates/packages/details_requiredby.html.jinja b/templates/packages/details_requiredby.html.jinja new file mode 100644 index 00000000..b083a7fc --- /dev/null +++ b/templates/packages/details_requiredby.html.jinja @@ -0,0 +1,8 @@ +{% import 'packages/details_link.html.jinja' as details %}<li>{{ details.details_link(req.pkg) }} +{% if req.name != pkg.pkgname %}<span class="virtual-dep"> (requires {{ req.name }})</span> +{% endif %}{% if req.pkg.repo.testing %}<span class="testing-dep"> (testing)</span> +{% endif %}{% if req.pkg.repo.staging %}<span class="staging-dep"> (staging)</span> +{% endif %}{% if req.deptype == 'O' %}<span class="opt-dep"> (optional)</span> +{% endif %}{% if req.deptype == 'M' %}<span class="make-dep"> (make)</span> +{% endif %}{% if req.deptype == 'C' %}<span class="check-dep"> (check)</span> +{% endif %}</li> diff --git a/templates/packages/differences.html b/templates/packages/differences.html index 2c1460ea..6220392c 100644 --- a/templates/packages/differences.html +++ b/templates/packages/differences.html @@ -1,34 +1,66 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Package Differences by Architecture{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Differences Reports{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} -{% if differences %} -<div id="differences-filter" class="box filter-criteria"> +<div class="box"> <h2>Package Differences by Architecture</h2> - <h3>Filter Differences View</h3> - <form id="diff_filter" method="post" action="."> - <fieldset> - <legend>Select filter criteria</legend> - <div><label for="id_archonly" title="Limit packages to selected architecture">Architecture Limitation</label> - <select name="archonly" id="id_archonly"> - <option value="all">Show All</option> - <option value="both">Only In Both</option> - <option value="{{ arch_a.name }}">In {{ arch_a.name }} Only</option> - <option value="{{ arch_b.name }}">In {{ arch_b.name }} Only</option> - </select> - </div> - <div><label for="id_multilib" title="Show multilib packages"><tt>[multilib]</tt> Visible</label> - <input type="checkbox" name="multilib" id="id_multilib" value="multilib"/></div> - <div><label for="id_minor" title="Show minor version mismatches">Minor Version Mismatches</label> - <input type="checkbox" checked="checked" name="minor" id="id_minor" value="minor"/></div> - <div ><label> </label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div> - </fieldset> - </form> -</div> + <div class="filter-criteria"> + <h3>Select architectures</h3> + <form id="arch_selector" method="get" action="."> + <fieldset> + <legend>Select arches</legend> + <div><label for="arch_a" title="Architecture A">Architecture A</label> + <select name="arch_a" id="arch_a"> + {% for arch in arches %} + <option + {% if arch == arch_a %} + selected="selected" + {% endif %} + >{{ arch }}</option> + {% endfor %} + </select> + </div> + <div><label for="arch_b" title="Architecture B">Architecture B</label> + <select name="arch_b" id="arch_b"> + {% for arch in arches %} + <option + {% if arch == arch_b %} + selected="selected" + {% endif %} + >{{ arch }}</option> + {% endfor %} + </select> + </div> + <div><label> </label><input type="submit" title="Show difference between selected architectures"></div> + </fieldset> + </form> + <h3>Filter Differences View</h3> + <form id="diff_filter" method="post" action="."> + <fieldset> + <legend>Select filter criteria</legend> + <div><label for="id_archonly" title="Limit packages to selected architecture">Architecture Limitation</label> + <select name="archonly" id="id_archonly"> + <option value="all">Show All</option> + <option value="both" selected="selected">Only In Both</option> + <option value="{{ arch_a.name }}">In {{ arch_a.name }} Only</option> + <option value="{{ arch_b.name }}">In {{ arch_b.name }} Only</option> + </select> + </div> + <div><label for="id_multilib" title="Show multilib packages"><tt>[multilib]</tt> Visible</label> + <input type="checkbox" name="multilib" id="id_multilib" value="multilib"/></div> + <div><label for="id_minor" title="Show minor version mismatches">Minor Version Mismatches</label> + <input type="checkbox" name="minor" id="id_minor" value="minor"/></div> + <div ><label> </label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div> + </fieldset> + </form> + </div> -<div class="box"> - <table class="results"> + <table id="table_differences" class="results"> <thead> <tr> <th>Package Name</th> @@ -37,77 +69,70 @@ <th>{{ arch_b.name }} Version</th> </tr> </thead> - <tbody> + <tbody id="tbody_differences"> {% for diff in differences %} <tr class="{% cycle 'odd' 'even' %} {{ diff.classes }}"> <td>{{ diff.pkgname }}</td> <td>{{ diff.repo.name }}</td> {% if diff.pkg_a %} - <td><a href="{{ diff.pkg_a.get_absolute_url }}" - title="View package details for {{ diff.pkg_a.pkgname }}"> - <span{% if diff.pkg_a.flag_date %} class="flagged"{% endif %}>{{ diff.pkg_a.pkgver }}-{{ diff.pkg_a.pkgrel }}</span></a></td> + <td>{% pkg_details_link diff.pkg_a diff.pkg_a.full_version True %}</td> {% else %}<td>-</td>{% endif %} {% if diff.pkg_b %} - <td><a href="{{ diff.pkg_b.get_absolute_url }}" - title="View package details for {{ diff.pkg_b.pkgname }}"> - <span{% if diff.pkg_b.flag_date %} class="flagged"{% endif %}>{{ diff.pkg_b.pkgver }}-{{ diff.pkg_b.pkgrel }}</span></a></td> + <td>{% pkg_details_link diff.pkg_b diff.pkg_b.full_version True %}</td> {% else %}<td>-</td>{% endif %} </tr> {% endfor %} </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> + +<div class="box"> + <h2>Multilib Differences to Main Packages</h2> + + <table id="table_multilib_differences" class="results"> + <thead> + <tr> + <th>Multilib Name</th> + <th>Multilib Version</th> + <th>i686 Version</th> + <th>i686 Name</th> + <th>i686 Repo</th> + <th>Multilib Last Updated</th> + <th>i686 Last Updated</th> + </tr> + </thead> + <tbody> + {% for pkg1, pkg2 in multilib_differences %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{% pkg_details_link pkg1 %}</td> + <td><span{% if pkg1.flag_date %} class="flagged"{% endif %}>{{ pkg1.full_version }}</span></td> + <td><span{% if pkg2.flag_date %} class="flagged"{% endif %}>{{ pkg2.full_version }}</span></td> + <td>{% pkg_details_link pkg2 %}</td> + <td>{{ pkg2.repo }}</td> + <td>{{ pkg1.last_update|date }}</td> + <td>{{ pkg2.last_update|date }}</td> + </tr> + {% endfor %} + </tbody> + </table> + +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> -filter_packages = function() { - // start with all rows, and then remove ones we shouldn't show - var rows = $(".results tbody tr"); - if(!$('#id_multilib').is(':checked')) { - rows = rows.not(".multilib"); - } - var arch = $("#id_archonly").val(); - if(arch !== "all") { - rows = rows.filter("." + arch); - } - if(!$('#id_minor').is(':checked')) { - // this check is done last because it is the most expensive - rows = rows.filter(function(index) { - // all this just to get the split version out of the table cell - var pat = /(.*)-(.+)/; - var ver_a = $('td:eq(2) span', this).text().match(pat); - var ver_b = $('td:eq(3) span', this).text().match(pat); - // did we match at all? - if(!ver_a || !ver_b) return true; - // first check pkgver - if(ver_a[1] !== ver_b[1]) return true; - // pkgver matched, so see if rounded pkgrel matches - if(Math.floor(parseFloat(ver_a[2])) == - Math.floor(parseFloat(ver_b[2]))) return false; - // pkgrel didn't match, so keep the row - return true; - }); - } - // hide all rows, then show the set we care about - $('.results tbody tr').hide(); - rows.show(); - // make sure we update the odd/even styling from sorting - $('.results').trigger("applyWidgets"); -}; -filter_reset = function() { - $('#id_archonly').val("all"); - $('#id_multilib').removeAttr("checked"); - $('#id_minor').attr("checked", "checked"); - filter_packages(); -}; $(document).ready(function() { - $('.results').tablesorter({widgets: ['zebra'], sortList: [[1,0], [0,0]]}); + $('#table_differences').tablesorter({widgets: ['zebra'], sortList: [[1,0], [0,0]]}); + $('#table_multilib_differences').tablesorter({widgets: ['zebra'], sortList: [[5, 0]]}); +}); +$(document).ready(function() { $('#diff_filter select').change(filter_packages); $('#diff_filter input').change(filter_packages); - $('#criteria_reset').click(filter_reset); + $('#criteria_reset').click(filter_packages_reset); // fire function on page load to ensure the current form selections take effect filter_packages(); }); </script> -{% endif %} {% endblock %} diff --git a/templates/packages/files-list.html b/templates/packages/files-list.html deleted file mode 100644 index c45e0f10..00000000 --- a/templates/packages/files-list.html +++ /dev/null @@ -1,9 +0,0 @@ -{% if files.count %} -<ul> - {% for file in files %} - <li>{{ file.path }}</li> - {% endfor %} -</ul> -{% else %} -<p>No file list available.</p> -{% endif %} diff --git a/templates/packages/files.html b/templates/packages/files.html index ebdfb9cf..667a77cb 100644 --- a/templates/packages/files.html +++ b/templates/packages/files.html @@ -1,17 +1,16 @@ {% extends "base.html" %} -{% block title %}Arch Linux - {{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }} - Package File List{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - {{ pkg.pkgname }} {{ pkg.full_version }} ({{ pkg.arch.name }}) - File List{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} <div id="pkgdetails" class="box"> - <h2>Package File List: {{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }}</h2> + <h2>{{ pkg.pkgname }} {{ pkg.full_version }} File List</h2> + <p>Package has {{ files_count }} file{{ files_count|pluralize }} and {{ dir_count }} director{{ dir_count|pluralize:"y,ies" }}.</p> <p><a href="{{ pkg.get_absolute_url }}">Back to Package</a></p> - - <div id="metadata"> - {% include "packages/files-list.html" %} - </div> + <div id="metadata"><div id="pkgfilelist"> + {% include "packages/files_list.html.jinja" %} + </div></div> </div> {% endblock %} - diff --git a/templates/packages/files_list.html.jinja b/templates/packages/files_list.html.jinja new file mode 100644 index 00000000..ab3e1210 --- /dev/null +++ b/templates/packages/files_list.html.jinja @@ -0,0 +1,16 @@ +{% if pkg.last_update > pkg.files_last_update %} +<p class="message">Note: This file list was generated from a previous version +of the package; it may be out of date.</p> +{% endif %} +{% if pkg.files_last_update %} +{% if files|length %} +<ul> +{% for file in files %} +<li class="{% if file.is_directory %}d{% else %}f{% endif %}">{{ file.directory }}{{ file.filename|default('', true) }}</li>{% endfor %} +</ul> +{% else %} +<p class="message">Package has no files.</p> +{% endif %} +{% else %} +<p class="message">No file list available.</p> +{% endif %} diff --git a/templates/packages/flag.html b/templates/packages/flag.html index f08b758b..ecf2fc78 100644 --- a/templates/packages/flag.html +++ b/templates/packages/flag.html @@ -1,42 +1,44 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Flag Package - {{ pkg.pkgname }}{% endblock %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Flag Package - {{ package.pkgname }} {{ package.full_version }} ({{ package.arch.name }}){% endblock %} +{% block head %}<meta name="robots" content="noindex"/>{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} <div id="pkg-flag" class="box"> -{% if confirmed %} - <h2>Package Flagged</h2> - - <p>Thank you, the maintainers have been notified about <strong>{{ pkg.pkgname }}</strong>.</p> + <h2>Flag Package: {{ package.pkgname }} {{ package.full_version }} ({{ package.arch.name }})</h2> - <p>You can return to the package details page for - <a href="{{ pkg.get_absolute_url }}" title="Package details for {{pkg.pkgname}}">{{pkg.pkgname}}</a>.</p> -{% else %} - <h2>Flag Package: {{ pkg.pkgname }}</h2> - - <p>If you notice a package is out of date (i.e., there is a newer + <p>If you notice a package is out-of-date (i.e., there is a newer <strong>stable</strong> release available), then please notify us using - the form below.</p> + the form below. Do <em>not</em> report bugs via this form!</p> + + <p>Note that the following {{ packages|length }} package{{ packages|pluralize }} will be marked out of date:</p> + <ul> + {% for pkg in packages %} + <li>{% pkg_details_link pkg %} {{ pkg.full_version }} [{{ pkg.repo.name|lower }}] ({{ pkg.arch.name }})</li> + {% endfor %} + </ul> - <p>The message box portion of the flag utility is optional, and meant + <p>The message box portion is meant for short messages only. If you need more than 200 characters for your message, then file a bug report, email the maintainer directly, or send - an email to the <a href="http://mailman.archlinux.org/mailman/listinfo/arch-general" - title="Visit the arch-general mailing list">arch-general mailing list</a> + an email to the <a href="{{ MAILMAN_BASE_URL }}/mailman/listinfo/dev" + title="Visit the dev mailing list">dev mailing list</a> with your additional text.</p> - <p><strong>Note:</strong> Please do <em>not</em> use this facility if the - package is broken! Use the <a href="https://bugs.archlinux.org" - title="Arch Linux Bugtracker">bug tracker</a> instead.</p> + <p><strong>Note:</strong> Do <em>not</em> use this facility if the + package is broken! The package will be unflagged and the report will be ignored! + <a href="{{ BUGTRACKER_URL }}" title="{{ BRANDING_DISTRONAME }} Bugtracker">Use the + bugtracker to file a bug</a> instead.</p> - <p>Please confirm your flag request for {{pkg.pkgname}}:</p> + <p>Please confirm your flag request for {{package.pkgname}}:</p> <form id="flag-pkg-form" method="post">{% csrf_token %} <fieldset> {{ form.as_p }} </fieldset> - <p><label></label> <input title="Flag {{ pkg.pkgname }} as out-of-date" type="submit" value="Flag Package" /></p> + <p><label></label> <input title="Flag {{ package.pkgname }} as out-of-date" type="submit" value="Flag Package" /></p> </form> -{% endif %} </div> {% endblock %} diff --git a/templates/packages/flag_confirmed.html b/templates/packages/flag_confirmed.html new file mode 100644 index 00000000..a4c4db2a --- /dev/null +++ b/templates/packages/flag_confirmed.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Flagged - {{ package.pkgname }} {{ package.full_version }} ({{ package.arch.name }}){% endblock %} +{% block head %}<meta name="robots" content="noindex"/>{% endblock %} +{% block navbarclass %}anb-packages{% endblock %} + +{% block content %} +<div id="pkg-flag" class="box"> + <h2>Package Flagged - {{ package.pkgname }}</h2> + + <p>Thank you, the maintainers have been notified the following + {{ packages|length }} package{{ packages|pluralize }} are out-of-date:</p> + <ul> + {% for pkg in packages %} + <li>{% pkg_details_link pkg %} {{ pkg.full_version }} [{{ pkg.repo.name|lower }}] ({{ pkg.arch.name }})</li> + {% endfor %} + </ul> + + <p>You can return to the package details page for {% pkg_details_link package %}.</p> +</div> +{% endblock %} diff --git a/templates/packages/flagged.html b/templates/packages/flagged.html index 3a39d178..4b12ca8f 100644 --- a/templates/packages/flagged.html +++ b/templates/packages/flagged.html @@ -1,16 +1,16 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Flag Package - {{ pkg.pkgname }}{% endblock %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Flag Package - {{ pkg.pkgname }} {{ pkg.full_version }} ({{ pkg.arch.name }}){% endblock %} +{% block head %}<meta name="robots" content="noindex"/>{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} <div id="pkg-flagged-error" class="box"> - - <h2>Error: Package already flagged</h2> + <h2>Package {{ pkg.pkgname }} {{ pkg.full_version }} ({{ pkg.arch.name }}) already flagged</h2> <p><strong>{{pkg.pkgname}}</strong> has already been flagged out-of-date.</p> - <p>You can return to the package details page for - <a href="{{ pkg.get_absolute_url }}" title="Package details for {{pkg.pkgname}}">{{pkg.pkgname}}</a>.</p> - + <p>You can return to the package details page for {% pkg_details_link pkg %}.</p> </div> {% endblock %} diff --git a/templates/packages/flaghelp.html b/templates/packages/flaghelp.html index 2b5092d2..d84dc11c 100644 --- a/templates/packages/flaghelp.html +++ b/templates/packages/flaghelp.html @@ -1,37 +1,35 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +{% load static from staticfiles %}<!DOCTYPE html> +<html lang="en"> <head> <title>Flagging Packages</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <style type="text/css" media="screen, projection"> - <!-- - body { background: #eef; color: #444; font-family: sans-serif; } - a { color: #07b; text-decoration: none; } - a:hover { text-decoration: underline; } - --> + <link rel="icon" type="image/x-icon" href="{% static "favicon.ico" %}" /> + <link rel="shortcut icon" type="image/x-icon" href="{% static "favicon.ico" %}" /> + <style type="text/css" media="screen, projection"> + body { background: #f6f9fc; color: #222; font-family: sans-serif; } + a:link { text-decoration: none; color: #07b; } + a:visited { color: #666; } + a:hover { text-decoration: underline; color: #666; } </style> </head> <body> - <h3>Flagging Packages</h3> - <p>If you notice that a package is out-of-date (i.e., there is a newer <strong>stable</strong> release available), then please notify us by using the <strong>Flag</strong> button in the <em>Package Details</em> screen. This will notify the maintainer(s) responsible for that - package so they can update it.</p> + package so they can update it. If the package is unmaintained, the + notification will be sent to a developer mailing list.</p> - <p>The message box portion of the flag utility is optional, and meant + <p>The message box portion of the flag utility is meant for short messages only. If you need more than 200 characters for your message, then file a bug report, email the maintainer directly, or send - an email to the <a target="_blank" href="http://mailman.archlinux.org/mailman/listinfo/arch-general" - title="Visit the arch-general mailing list">arch-general mailing list</a> + an email to the <a target="_blank" href="{{ MAILMAN_BASE_URL }}/mailman/listinfo/dev" + title="Visit the dev mailing list">dev mailing list</a> with your additional text.</p> <p><strong>Note:</strong> Please do <em>not</em> use this facility if the - package is broken! Use the <a target="_blank" href="https://bugs.archlinux.org" - title="Arch Linux Bugtracker">bugtracker</a> instead.</p> - + package is broken! Use the <a target="_blank" href="{{ BUGTRACKER_URL }}" + title="{{ BRANDING_DISTRONAME }} Bugtracker">bugtracker</a> instead.</p> </body> </html> diff --git a/templates/packages/groups.html b/templates/packages/groups.html index 8a96b7e3..39a13389 100644 --- a/templates/packages/groups.html +++ b/templates/packages/groups.html @@ -1,10 +1,13 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Package Groups{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Groups{% if arch %} - {{ arch }}{% endif %}{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} <div class="box"> - <h2>Package Groups Overview</h2> + <h2>Package Groups Overview{% if arch %} - {{ arch }}{% endif %}</h2> <table class="results"> <thead> <tr> @@ -27,8 +30,11 @@ </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> $(document).ready(function() { $(".results").tablesorter({widgets: ['zebra'], sortList: [[1,0], [0,0]]}); diff --git a/templates/packages/opensearch.xml b/templates/packages/opensearch.xml index 711b36a2..0004b996 100644 --- a/templates/packages/opensearch.xml +++ b/templates/packages/opensearch.xml @@ -1,13 +1,18 @@ -<?xml version="1.0" encoding="UTF-8"?> +{% load static from staticfiles %}<?xml version="1.0" encoding="UTF-8"?> <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> - <ShortName>Arch Linux Packages</ShortName> - <Description>Search the Arch Linux package repositories.</Description> - <Tags>linux archlinux package software</Tags> - <Image height="16" width="16" type="image/x-icon">{{domain}}/media/favicon.ico</Image> + <ShortName>{{BRANDING_SHORTNAME}} Packages</ShortName> + <LongName>{{BRANDING_DISTRONAME}} Package Repository Search</LongName> + <Description>Search the {{BRANDING_DISTRONAME}} package repositories by keyword in package names and descriptions.</Description> + <Tags>{{BRANDING_OSEARCH_TAGS}}</Tags> + <Image height="16" width="16" type="image/x-icon">{{ domain }}{% static "favicon.ico" %}</Image> + <Image height="64" width="64" type="image/png">{{ domain }}{% static "logos/icon-transparent-64x64.png" %}</Image> <Language>en-us</Language> <InputEncoding>UTF-8</InputEncoding> <OutputEncoding>UTF-8</OutputEncoding> <Query role="example" searchTerms="initscripts"/> - <Url type="text/html" template="{{domain}}/packages/?q={searchTerms}"/> - <Url rel="self" type="application/opensearchdescription+xml" template="{{domain}}/opensearch/packages/"/> + <Url type="text/html" template="{{ domain }}/packages/?q={searchTerms}"/> + <Url rel="suggestions" type="application/x-suggestions+json" + template="{{ domain }}/opensearch/packages/suggest?q={searchTerms}"/> + <Url rel="self" type="application/opensearchdescription+xml" + template="{{ domain }}/opensearch/packages/"/> </OpenSearchDescription> diff --git a/templates/packages/outofdate.txt b/templates/packages/outofdate.txt index 80da23d6..4876c316 100644 --- a/templates/packages/outofdate.txt +++ b/templates/packages/outofdate.txt @@ -1,11 +1,7 @@ -{% autoescape off %}* Note: this is an automated message +{% autoescape off %}{{ email }} wants to notify you that the following packages may be out-of-date: -{{ email }} wants to notify you that the following package may be out of date: - - Package Name: {{ pkg.pkgname }} - Architecture: {{ pkg.arch.name }} - Repository: {{ pkg.repo.name }} - ({{ weburl }}) +{% for p in packages %} +* {{ p.pkgname }} {{ p.full_version }} [{{ p.repo.name|lower }}] ({{ p.arch.name }}): {{ p.get_full_url }}{% endfor %} {% if message %} The user provided the following additional text: diff --git a/templates/packages/group_details.html b/templates/packages/packages_list.html index df9c5e96..9736d36c 100644 --- a/templates/packages/group_details.html +++ b/templates/packages/packages_list.html @@ -1,10 +1,15 @@ {% extends "base.html" %} -{% block title %}Arch Linux - {{ groupname }} - Group Details{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - {{ name }} ({{ arch.name }}) - {{ list_title }}{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} <div class="box"> - <h2>Details for group {{ groupname }} - {{ arch.name }}</h2> + <h2>{{ list_title }} - {{ name }} ({{ arch.name }})</h2> + <p>{{ packages|length }} package{{ packages|pluralize }} found.</p> <table class="results"> <thead> <tr> @@ -14,6 +19,7 @@ <th>Version</th> <th>Description</th> <th>Last Updated</th> + <th>Flag Date</th> </tr> </thead> <tbody> @@ -21,22 +27,25 @@ <tr class="{% cycle 'odd' 'even' %}"> <td>{{ pkg.arch.name }}</td> <td>{{ pkg.repo.name|capfirst }}</td> - <td><a href="{{ pkg.get_absolute_url }}" - title="Package details for {{ pkg.pkgname }}">{{ pkg.pkgname }}</a></td> + <td>{% pkg_details_link pkg %}</td> {% if pkg.flag_date %} - <td><span class="flagged">{{ pkg.pkgver }}-{{ pkg.pkgrel }}</span></td> + <td><span class="flagged">{{ pkg.full_version }}</span></td> {% else %} - <td>{{ pkg.pkgver }}-{{ pkg.pkgrel }}</td> + <td>{{ pkg.full_version }}</td> {% endif %} <td class="wrap">{{ pkg.pkgdesc }}</td> <td>{{ pkg.last_update|date }}</td> + <td>{{ pkg.flag_date|date }}</td> </tr> {% endfor %} </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> $(document).ready(function() { $(".results").tablesorter({widgets: ['zebra'], sortList: [[2,0]]}); diff --git a/templates/packages/removed.html b/templates/packages/removed.html new file mode 100644 index 00000000..7f6600ee --- /dev/null +++ b/templates/packages/removed.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Not Available - {{ name }} {{ version }} ({{ arch.name }}){% endblock %} +{% block navbarclass %}anb-packages{% endblock %} + +{% block content %} +<div id="pkg-gone" class="box"> + <h2>{{ name }} {{ version }} is no longer available</h2> + + <p>{{ name }} {{ version }} has been removed from the [{{ repo.name|lower }}] repository.</p> + + {% if elsewhere %} + <p>However, this package or replacements are available elsewhere:</p> + <ul> + {% for pkg in elsewhere %} + <li>{% pkg_details_link pkg %} {{ pkg.full_version }} [{{ pkg.repo.name|lower }}] ({{ pkg.arch.name }})</li> + {% endfor %} + </ul> + {% else %} + <p>Unfortunately, this package cannot be found in any other repositories.</p> + {% endif %} +</div> +{% endblock %} diff --git a/templates/packages/search.html b/templates/packages/search.html index 2aa82af1..41e36193 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -1,166 +1,147 @@ {% extends "base.html" %} +{% load cycle from future %} {% load package_extras %} -{% block title %}Arch Linux - Package Database{% endblock %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Search{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block head %} -<link rel="stylesheet" type="text/css" href="/media/admin_media/css/widgets.css" /> +{% if is_paginated and page_obj.number > 1 %}<meta name="robots" content="noindex, nofollow"/>{% endif %} +<link rel="alternate" type="application/rss+xml" title="{{BRANDING_DISTRONAME}} Package Updates" href="/feeds/packages/" /> {% endblock %} {% block content %} <div id="pkglist-search" class="box filter-criteria"> + <h2>Package Search</h2> + + <form id="pkg-search" method="get" action="/packages/"> + <p>{{ search_form.sort }}</p> + {{ search_form.non_field_errors }} + <fieldset> + <legend>Enter search criteria</legend> + <div>{{ search_form.arch.errors }} + <label for="id_arch" title="Limit results a specific CPU architecture"> + Arch</label>{{ search_form.arch }}</div> + <div>{{ search_form.repo.errors }} + <label for="id_repo" title="Limit results to a specific respository"> + Repository</label>{{ search_form.repo }}</div> + <div>{{ search_form.q.errors }} + <label for="id_q" title="Enter keywords as desired"> + Keywords</label>{{ search_form.q }}</div> + <div>{{ search_form.maintainer.errors }} + <label for="id_maintainer" title="Limit results to a specific maintainer"> + Maintainer</label>{{ search_form.maintainer}}</div> + <div>{{ search_form.flagged.errors }} + <label for="id_flagged" title="Limit results based on out-of-date status"> + Flagged</label>{{ search_form.flagged }}</div> + <div ><label> </label><input title="Search for packages using this criteria" + type="submit" value="Search" /></div> + </fieldset> + </form> +</div> - <h2>Package Database</h2> - - <h3>Package Search</h3> - - <form id="pkg-search" method="get" action="/packages/"> - <p><input type="hidden" name="sort" value='{{sort}}' /></p> - <fieldset> - <legend>Enter search criteria</legend> - <div><label for="id_arch" title="Limit results a specific CPU architecture"> - Arch</label>{{ search_form.arch }}</div> - <div><label for="id_repo" title="Limit results to a specific respository"> - Repository</label>{{ search_form.repo }}</div> - <div><label for="id_q" title="Enter keywords as desired"> - Keywords</label>{{ search_form.q }}</div> - <div><label for="id_maintainer" title="Limit results to a specific maintainer"> - Maintainer</label>{{ search_form.maintainer}}</div> - <div><label for="id_last_update" title="Limit results to a date after the date entered"> - Last Updated After</label>{{ search_form.last_update }}</div> - <div><label for="id_flagged" title="Limit results based on out-of-date status"> - Flagged</label>{{ search_form.flagged }}</div> - <div><label for="id_limit" title="Select the number of results to display per page"> - Per Page</label>{{ search_form.limit }}</div> - <div ><label> </label><input title="Search for packages using this criteria" - type="submit" value="Search" /></div> - </fieldset> - </form> - -</div><!-- #pkglist-search --> - -{% if package_list %} -<div id="pkglist-results" class="box"> - - {% if paginator %} - <div id="pkglist-stats-top"> - - <p>{{paginator.count}} packages found. - Page {{page_obj.number}} of {{paginator.num_pages}}.</p> - - <p class="pkglist-nav"> - {% if page_obj.has_previous %} - <a class="prev" href="/packages/{{page_obj.previous_page_number}}/{{current_query}}" - title="Go to previous page">< Prev</a> - {% else %} - <span class="prev">< Prev</span> - {% endif %} - {% if page_obj.has_next %} - <a class="next" href="/packages/{{page_obj.next_page_number}}/{{current_query}}" - title="Go to next page">Next ></a> - {% else %} - <span class="next">Next ></span> - {% endif %} - </p> - +{% if not is_paginated or page_obj.number == 1 %}{% with search_form.exact_matches as exact_matches %}{% if exact_matches %} +<div id="exact-matches" class="box"> + <div class="pkglist-stats"> + <p>{{ exact_matches|length }} exact match{{ exact_matches|pluralize:"es" }} found.</p> </div> - {% endif %} + <table class="results"> + <thead> + <tr> + <th>Arch</th> + <th>Repo</th> + <th>Name</th> + <th>Version</th> + <th>Description</th> + <th>Last Updated</th> + <th>Flag Date</th> + </tr> + </thead> + <tbody> + {% for pkg in exact_matches %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.repo.name|capfirst }}</td> + <td>{% pkg_details_link pkg %}</td> + {% if pkg.flag_date %} + <td><span class="flagged">{{ pkg.full_version }}</span></td> + {% else %} + <td>{{ pkg.full_version }}</td> + {% endif %} + <td class="wrap">{{ pkg.pkgdesc }}</td> + <td>{{ pkg.last_update|date }}</td> + <td>{{ pkg.flag_date|date }}</td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endif %}{% endwith %}{% endif %} +<div id="pkglist-results" class="box"> + {% include "packages/search_paginator.html" %} <form id="pkglist-results-form" method="post" action="/packages/update/">{% csrf_token %} - <table class="results"> <thead> <tr> - {% if user.is_authenticated %} + {% if perms.main.change_package %} <th> </th> {% endif %} - <th><a href="/packages/{% buildsortqs "arch" %}" + <th><a href="/packages/?{% buildsortqs "arch" %}" title="Sort packages by architecture">Arch</a></th> - <th><a href="/packages/{% buildsortqs "repo" %}" + <th><a href="/packages/?{% buildsortqs "repo" %}" title="Sort packages by repository">Repo</a></th> - <th><a href="/packages/{% buildsortqs "pkgname" %}" + <th><a href="/packages/?{% buildsortqs "pkgname" %}" title="Sort packages by package name">Name</a></th> <th>Version</th> <th>Description</th> - <th><a href="/packages/{% buildsortqs "-last_update" %}" + <th><a href="/packages/?{% buildsortqs "-last_update" %}" title="Sort packages by last update">Last Updated</a></th> + <th><a href="/packages/?{% buildsortqs "-flag_date" %}" + title="Sort packages by when marked-out of-date">Flag Date</a></th> </tr> </thead> <tbody> - {% for pkg in package_list %} + {% for pkg in package_list %} <tr class="{% cycle 'odd' 'even' %}"> - {% if user.is_authenticated %} + {% if perms.main.change_package %} <td><input type="checkbox" name="pkgid" value="{{ pkg.id }}" /></td> {% endif %} <td>{{ pkg.arch.name }}</td> <td>{{ pkg.repo.name|capfirst }}</td> - <td><a href="{{ pkg.get_absolute_url }}" - title="Package details for {{ pkg.pkgname }}">{{ pkg.pkgname }}</a></td> + <td>{% pkg_details_link pkg %}</td> {% if pkg.flag_date %} - <td><span class="flagged">{{ pkg.pkgver }}-{{ pkg.pkgrel }}</span></td> + <td><span class="flagged">{{ pkg.full_version }}</span></td> {% else %} - <td>{{ pkg.pkgver }}-{{ pkg.pkgrel }}</td> + <td>{{ pkg.full_version }}</td> {% endif %} <td class="wrap">{{ pkg.pkgdesc }}</td> <td>{{ pkg.last_update|date }}</td> + <td>{{ pkg.flag_date|date }}</td> </tr> - {% endfor %} + {% empty %} + <tr class="empty"><td colspan="{% if perms.main.change_package %}9{% else %}8{% endif %}"><em>No matching packages found</em></td></tr> + {% endfor %} </tbody> </table> + {% include "packages/search_paginator.html" %} - {% if paginator %} - <div id="pkglist-stats-bottom"> - - <p>{{paginator.count}} packages found. Page {{page_obj.number}} of {{paginator.num_pages}}.</p> - - <p class="pkglist-nav"> - {% if page_obj.has_previous %} - <a class="prev" href="/packages/{{page_obj.previous_page_number}}/{{current_query}}" - title="Go to previous page">< Prev</a> - {% else %} - <span class="prev">< Prev</span> - {% endif %} - {% if page_obj.has_next %} - <a class="next" href="/packages/{{page_obj.next_page_number}}/{{current_query}}" - title="Go to next page">Next ></a> - {% else %} - <span class="next">Next ></span> - {% endif %} - </p> - - </div> - {% endif %} - - {% if user.is_authenticated %} + {% if perms.main.change_package %} <p><input title="Adopt selected packages" type="submit" id="adopt-btn" name="adopt" value="Adopt Packages" /> <input title="Orphan selected packages" type="submit" id="disown-btn" name="disown" value="Disown Packages" /></p> {% endif %} - </form> - -</div><!-- #pkglist-results --> -{% else %} -<div class="box"> - <p>We couldn't find any packages matching your query. Try searching again - using different criteria, or try - {% if search_form.q.data %} - <a href="http://aur.archlinux.org/packages.php?K={{ search_form.q.data }}">searching the AUR</a> - {% else %}searching the AUR{% endif %} - to see if the package can be found there.</p> </div> -{% endif %} - <div id="pkglist-about" class="box"> - <p>You are browsing the Arch Linux package database. From here you can find + <p>Can't find what you are looking for? Try searching again + using different criteria.</p> + + <p>You are browsing the {{ BRANDING_DISTRONAME }} package database. From here you can find detailed information about packages located in the official supported repositories. - For unsupported packages, browse the <a href="http://aur.archlinux.org/" - title="AUR package database">Arch User Repository (AUR).</a></p> + If you need the sourceball from where a package is built, you can look at our <a + href="https://repo.parabola.nu/sources/packages" + title="Sourceballed packages">sources repo</a>.</p> </div> - -<script type="text/javascript" src="/jsi18n/"></script> -{% load adminmedia %}<script type="text/javascript" src="{% admin_media_prefix %}js/core.js"></script> -<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";</script> -{{search_form.media}} {% endblock %} diff --git a/templates/packages/search_paginator.html b/templates/packages/search_paginator.html new file mode 100644 index 00000000..a748d26b --- /dev/null +++ b/templates/packages/search_paginator.html @@ -0,0 +1,27 @@ +<div class="pkglist-stats"> + {% if is_paginated %} + <p>{{ paginator.count }} matching packages found. + Page {{ page_obj.number }} of {{ paginator.num_pages }}.</p> + + <div class="pkglist-nav"> + <span class="prev"> + {% if page_obj.has_previous %} + <a href="?page={{ page_obj.previous_page_number }}&{{ current_query }}" + title="Go to previous page">< Prev</a> + {% else %} + < Prev + {% endif %} + </span> + <span class="next"> + {% if page_obj.has_next %} + <a href="?page={{ page_obj.next_page_number }}&{{ current_query }}" + title="Go to next page">Next ></a> + {% else %} + Next > + {% endif %} + </span> + </div> + {% else %} + <p>{{ package_list|length }} matching package{{ package_list|pluralize }} found.</p> + {% endif %} +</div> diff --git a/templates/packages/signoff_cell.html b/templates/packages/signoff_cell.html new file mode 100644 index 00000000..7d9e1972 --- /dev/null +++ b/templates/packages/signoff_cell.html @@ -0,0 +1,23 @@ +{% if group.signoffs %} +<ul class="signoff-list"> + {% for signoff in group.signoffs %} + <li class="signed-username" title="Signed off by {{ signoff.user }}">{{ signoff.user }}{% if signoff.revoked %} (revoked){% endif %}</li> + {% endfor %} +</ul> +{% endif %} +{% if group.user_signed_off %} +<div> + <a class="signoff-link" href="{{ group.package.get_absolute_url }}signoff/revoke/" + title="Revoke signoff {{ group.pkgbase }} for {{ group.arch }}">Revoke Signoff</a></div> +{% else %} +{% if not group.specification.known_bad and group.specification.enabled %} +<div> + <a class="signoff-link" href="{{ group.package.get_absolute_url }}signoff/" + title="Signoff {{ group.pkgbase }} for {{ group.arch }}">Signoff</a></div> +{% endif %} +{% endif %} +{% if user == group.packager or user in group.maintainers %} +<div> + <a class="signoff-options" href="{{ group.package.get_absolute_url }}signoff/options/">Signoff Options</a> +</div> +{% endif %} diff --git a/templates/packages/signoff_options.html b/templates/packages/signoff_options.html new file mode 100644 index 00000000..40b7cac7 --- /dev/null +++ b/templates/packages/signoff_options.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Signoff Options - {{ package.pkgbase }} {{ package.full_version }} ({{ package.arch.name }}){% endblock %} +{% block head %}<meta name="robots" content="noindex"/>{% endblock %} +{% block navbarclass %}anb-packages{% endblock %} + +{% block content %} +<div id="signoff-options" class="box"> + <h2>Package Signoff Options: {{ package.pkgbase }} {{ package.full_version }} ({{ package.arch.name }})</h2> + <form id="signoff-options-form" method="post">{% csrf_token %} + <fieldset> + {{ form.as_p }} + </fieldset> + <p><label></label> <input title="Set Signoff Options" type="submit" value="Set Signoff Options" /></p> + </form> + +</div> +{% endblock %} diff --git a/templates/packages/signoff_report.txt b/templates/packages/signoff_report.txt new file mode 100644 index 00000000..046c2f1e --- /dev/null +++ b/templates/packages/signoff_report.txt @@ -0,0 +1,41 @@ +=== {% autoescape off %}Signoff report for [{{ repo|lower }}] === +{{ signoffs_url }} + +There are currently: +* {{ new|length }} new package{{ new|length|pluralize }} in last {{ new_hours }} hours +* {{ bad|length }} known bad package{{ bad|length|pluralize }} +* {{ disabled|length }} package{{ disabled|length|pluralize }} not accepting signoffs +* {{ complete|length }} fully signed off package{{ complete|length|pluralize }} +* {{ incomplete|length }} package{{ incomplete|length|pluralize }} missing signoffs +* {{ old|length }} package{{ old|length|pluralize }} older than {{ old_days }} days + +(Note: the word 'package' as used here refers to packages as grouped by +pkgbase, architecture, and repository; e.g., one PKGBUILD produces one +package per architecture, even if it is a split package.) + + +{% if new %}== New packages in [{{ repo|lower}}] in last {{ new_hours }} hours ({{ new|length }} total) == +{% for group in new %} +* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}){% endfor %} + +{% endif %}{% regroup incomplete by target_repo as by_repo %}{% for target_repo in by_repo %} +== Incomplete signoffs for [{{ target_repo.grouper|lower }}] ({{ target_repo.list|length }} total) == +{% for group in target_repo.list %} +* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}) + {{ group.completed }}/{{ group.required }} signoffs{% endfor %} +{% endfor %} + +{% if complete %}== Completed signoffs ({{ complete|length }} total) == +{% for group in complete %} +* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}){% endfor %} + + +{% endif %}{% if old %}== All packages in [{{ repo|lower }}] for more than {{ old_days }} days ({{ old|length }} total) == +{% for group in old %} +* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}), since {{ group.last_update|date }}{% endfor %} + + +{% endif %}== Top five in signoffs in last {{ new_hours }} hours == +{% for leader in leaders %} +{{ forloop.counter }}. {{ leader.user }} - {{ leader.count }} signoffs{% endfor %} +{% endautoescape %} diff --git a/templates/packages/signoffs.html b/templates/packages/signoffs.html index 8d78c8a1..06766935 100644 --- a/templates/packages/signoffs.html +++ b/templates/packages/signoffs.html @@ -1,58 +1,103 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Package Signoffs{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load package_extras %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Package Signoffs{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block content %} -{% if packages %} <div id="dev-signoffs" class="box"> <h2>Package Signoffs</h2> + <p>{{ signoff_groups|length }} total signoff group{{ signoff_groups|pluralize }} found. + A "signoff group" consists of packages grouped by pkgbase, architecture, and repository.</p> + + <div class="box filter-criteria"> + <h3>Filter Displayed Signoffs</h3> + <form id="signoffs_filter" method="post" action="."> + <fieldset> + <legend>Select filter criteria</legend> + {% for arch in arches %} + <div><label for="id_arch_{{ arch.name }}" title="Architecture {{ arch.name }}">Arch {{ arch.name }}</label> + <input type="checkbox" name="arch_{{ arch.name }}" id="id_arch_{{ arch.name }}" class="arch_filter" value="{{ arch.name }}" checked="checked"/></div> + {% endfor %} + {% for repo_name in repo_names %} + <div><label for="id_repo_{{ repo_name|lower }}" title="Target Repository {{ repo_name }}">[{{ repo_name|lower }}]</label> + <input type="checkbox" name="repo_{{ repo_name|lower }}" id="id_repo_{{ repo_name|lower }}" class="repo_filter" value="{{ repo_name|lower }}" checked="checked"/></div> + {% endfor %} + <div><label for="id_pending" title="Packages with not enough signoffs">Only Pending Approval</label> + <input type="checkbox" name="pending" id="id_pending" value="pending"/></div> + <div><label> </label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div> + <div class="clear"></div> + <div id="filter-info"><span id="filter-count">{{ signoff_groups|length }}</span> signoff groups displayed.</div> + </fieldset> + </form> + </div> + <table id="signoffs" class="results"> <thead> <tr> + <th>Package Base/Version</th> <th>Arch</th> - <th>Package</th> - <th>Version</th> - <th>Last Updated</th> <th>Target Repo</th> + <th>Packager</th> + <th># of Packages</th> + <th>Last Updated</th> <th>Approved</th> - <th>Signoff</th> + <th>Signoffs</th> + <th>Notes</th> </tr> </thead> - <tbody> - {% for pkg,target in packages %} - <tr class="{% cycle 'odd' 'even' %}"> - <td>{{ pkg.arch.name }}</td> - <td><a href="{{ pkg.get_absolute_url }}" - title="View package details for {{ pkg.pkgname }}">{{ pkg.pkgname }}</a></td> - <td>{{ pkg.pkgver }}-{{ pkg.pkgrel }}</td> - <td>{{ pkg.last_update }}</td> - <td>{{ target }}</td> - <td class="signoff-{{pkg.approved_for_signoff|yesno}}"> - {{ pkg.approved_for_signoff|yesno:"Yes,No" }}</td> - <td> - <ul> - <li><a href="/packages/signoff_package/{{pkg.arch}}/{{pkg.pkgname}}/" - title="Signoff {{pkg.pkgname}} for {{pkg.arch}}">Signoff</a> - </li> - {% for signoff in pkg.signoffs %} - <li class="signed-username" title="Signed off by {{signoff.packager}}"> - {{signoff.packager}}</li> - {% endfor %} - </ul> - </td> - </tr> - {% endfor %} + <tbody id="tbody_signoffs"> + {% for group in signoff_groups %}<tr class="{% cycle 'odd' 'even' %} {{ group.arch.name }} {{ group.target_repo|lower }}"> + <td>{% pkg_details_link group.package %} {{ group.version }}</td> + <td>{{ group.arch.name }}</td> + <td>{{ group.target_repo }}</td> + <td>{{ group.packager|default:"Unknown" }}</td> + <td>{{ group.packages|length }}</td> + <td class="epoch-{{ group.last_update|date:'U' }}">{{ group.last_update|date }}</td> + {% if group.specification.known_bad %} + <td class="approval signoff-bad">Bad</td> + {% else %} + {% if not group.specification.enabled %} + <td class="approval signoff-disabled">Disabled</td> + {% else %} + <td class="approval signoff-{{ group.approved|yesno }}">{{ group.approved|yesno|capfirst }}</td> + {% endif %} + {% endif %} + <td>{% include "packages/signoff_cell.html" %}</td> + <td class="wrap note">{% if not group.default_spec %}{% with group.specification as spec %}{% comment %} + {% endcomment %}{% if spec.required != spec.arch.required_signoffs %}Required signoffs: {{ spec.required }}<br/>{% endif %}{% comment %} + {% endcomment %}{% if not spec.enabled %}Signoffs are not currently enabled<br/>{% endif %}{% comment %} + {% endcomment %}{% if spec.known_bad %}Package is known to be bad<br/>{% endif %}{% comment %} + {% endcomment %}{{ spec.comments|default:""|linebreaksbr }} + {% endwith %}{% endif %}</td> + </tr>{% endfor %} </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> $(document).ready(function() { - $(".results").tablesorter({widgets: ['zebra'], sortList: [[1,0]]}); + $('.results').tablesorter({widgets: ['zebra'], sortList: [[0,0]], + headers: { 5: { sorter: 'epochdate' }, 7: { sorter: false }, 8: {sorter: false } } }); +}); +$(document).ready(function() { + $('a.signoff-link').click(signoff_package); + $('#signoffs_filter input').change(filter_signoffs); + $('#criteria_reset').click(filter_signoffs_reset); + // fire function on page load to ensure the current form selections take effect + filter_signoffs_load(); + filter_signoffs(); +}); +$(document).ready(function() { + collapseNotes('.note'); }); </script> -{% endif %} {% endblock %} diff --git a/templates/packages/stale_relations.html b/templates/packages/stale_relations.html new file mode 100644 index 00000000..949b563e --- /dev/null +++ b/templates/packages/stale_relations.html @@ -0,0 +1,129 @@ +{% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Stale Package Relations{% endblock %} +{% block navbarclass %}anb-packages{% endblock %} + +{% block content %} +<div class="box"> + <h2>Stale Package Relations</h2> + + <form id="stale-relations-form" method="post" action="update/">{% csrf_token %} + <h3>Inactive User Relations ({{ inactive_user|length }})</h3> + + <table class="results" id="inactive-user"> + <thead> + <tr> + <th> </th> + <th>Package Base</th> + <th>Packages</th> + <th>User</th> + <th>Type</th> + <th>Created</th> + </tr> + </thead> + <tbody> + {% for relation in inactive_user %} + <tr class="{% cycle 'odd' 'even' %}"> + <td><input type="checkbox" class="relation-checkbox" name="relation_id" value="{{ relation.id }}" /></td> + <td>{{ relation.pkgbase }}</td> + <td class="wrap">{% for pkg in relation.get_associated_packages %} + <a href="{{ pkg.get_absolute_url }}" + title="View package details for {{ pkg.pkgname }}">{{ pkg.repo|lower }}/{{ pkg.pkgname }} ({{ pkg.arch }})</a>{% if not forloop.last %}, {% endif %} + {% endfor %}</td> + <td>{{ relation.user.get_full_name }}</td> + <td>{{ relation.get_type_display }}</td> + <td>{{ relation.created }}</td> + </tr> + {% empty %} + <tr class="empty"><td colspan="6"><em>No inactive user relations.</em></td></tr> + {% endfor %} + </tbody> + </table> + + <h3>Relations with Non-existent <tt>pkgbase</tt> ({{ missing_pkgbase|length }})</h3> + + <table class="results" id="missing-pkgbase"> + <thead> + <tr> + <th> </th> + <th>Package Base</th> + <th>User</th> + <th>Type</th> + <th>Created</th> + <th>Latest Update</th> + </tr> + </thead> + <tbody> + {% for relation in missing_pkgbase %} + <tr class="{% cycle 'odd' 'even' %}"> + <td><input type="checkbox" class="relation-checkbox" name="relation_id" value="{{ relation.id }}" /></td> + <td>{{ relation.pkgbase }}</td> + <td>{{ relation.user.get_full_name }}</td> + <td>{{ relation.get_type_display }}</td> + <td>{{ relation.created }}</td> + <td>{{ relation.last_update.created }}</td> + </tr> + {% empty %} + <tr class="empty"><td colspan="6"><em>No non-existent pkgbase relations.</em></td></tr> + {% endfor %} + </tbody> + </table> + + <h3>Maintainers with Wrong Permissions ({{ wrong_permissions|length }})</h3> + + <table class="results" id="wrong-permissions"> + <thead> + <tr> + <th> </th> + <th>Package Base</th> + <th>Packages</th> + <th>User</th> + <th>Created</th> + <th>Allowed Repos</th> + <th>Currently in Repos</th> + </tr> + </thead> + <tbody> + {% for relation in wrong_permissions %} + <tr class="{% cycle 'odd' 'even' %}"> + <td><input type="checkbox" class="relation-checkbox" name="relation_id" value="{{ relation.id }}" /></td> + <td>{{ relation.pkgbase }}</td> + <td class="wrap">{% for pkg in relation.get_associated_packages %} + <a href="{{ pkg.get_absolute_url }}" + title="View package details for {{ pkg.pkgname }}">{{ pkg.repo|lower }}/{{ pkg.pkgname }} ({{ pkg.arch }})</a>{% if not forloop.last %}, {% endif %} + {% endfor %}</td> + <td>{{ relation.user.get_full_name }}</td> + <td>{{ relation.created }}</td> + <td class="wrap">{{ relation.user.userprofile.allowed_repos.all|join:", " }}</td> + <td class="wrap">{{ relation.repositories|join:", " }}</td> + </tr> + {% empty %} + <tr class="empty"><td colspan="7"><em>No relations with wrong permissions.</em></td></tr> + {% endfor %} + </tbody> + </table> + + <p><input title="Delete selected relations" type="submit" id="delete-relations" + name="delete" value="Delete Selected Relations" /> + </form> + +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $('#inactive-user:not(:has(tbody tr.empty))').tablesorter({widgets: ['zebra'], headers: { 0: { sorter: false }, 2: { sorter: false } }, sortList: [[1,0]]}); + $('#missing-pkgbase:not(:has(tbody tr.empty))').tablesorter({widgets: ['zebra'], headers: { 0: { sorter: false } }, sortList: [[1,0]]}); + $('#wrong-permissions:not(:has(tbody tr.empty))').tablesorter({widgets: ['zebra'], headers: { 0: { sorter: false }, 2: { sorter: false } }, sortList: [[1,0]]}); + $('table.results').bind('sortEnd', function() { + $('input.relation-checkbox').enableCheckboxRangeSelection(); + }); + $('input.relation-checkbox').enableCheckboxRangeSelection(); +}); +</script> +{% endblock %} diff --git a/templates/public/about.html b/templates/public/about.html index 0e0601e8..903f0690 100644 --- a/templates/public/about.html +++ b/templates/public/about.html @@ -1,57 +1,62 @@ {% extends "base.html" %} -{% block title %}Arch Linux - About{% endblock %} +{% load wiki %} +{% block title %}{{ BRANDING_DISTRONAME }} - About{% endblock %} {% block content %} <div class="box"> - <h2 class="title">About Arch Linux</h2> - <p> -Arch Linux is an independently developed, i686/x86-64 general purpose GNU/Linux -distribution versatile enough to suit any role. Development focuses on -simplicity, minimalism, and code elegance. Arch is installed as a -minimal base system, configured by the user upon which their own ideal -environment is assembled by installing only what is required or desired -for their unique purposes. GUI configuration utilities are not officially -provided, and most system configuration is performed from the shell by editing -simple text files. Arch strives to stay bleeding edge, and typically offers -the latest stable versions of most software. -</p> -<p> -Arch Linux uses its own Pacman package manager, which couples simple binary -packages with an easy-to-use package build system. This allows users to -easily manage and customize packages ranging from official Arch software to the -user's own personal packages to packages from 3rd party sources. The repository -system also allows users to easily build and maintain their own custom build -scripts, packages, and repositories, encouraging community growth and -contribution. -</p> -<p> -The minimal Arch base package set resides in the streamlined [core] repository. -In addition, the official [extra], [community], and [testing] repositories -provide several thousand high-quality, packages to meet your software demands. -Arch also offers an [unsupported] section in the Arch Linux User Repository -(AUR), which contains over 9,000 build scripts, for compiling installable -packages from source using the Arch Linux makepkg application. -</p> -<p> -Arch Linux uses a "rolling release" system which allows one-time installation -and perpetual software upgrades. It is not generally necessary to reinstall -or upgrade your Arch Linux system from one "version" to the next. -By issuing one command, an Arch system is kept up-to-date and on the bleeding -edge. -</p> -<p> -Arch strives to keep its packages as close to the original upstream software as -possible. Patches are applied only when necessary to ensure an application -compiles and runs correctly with the other packages installed on an up-to-date -Arch system. -</p> -<p> -To summarize: Arch Linux is a versatile, and simple distribution designed to -fit the needs of the competent Linux® user. It is both powerful and easy -to manage, making it an ideal distro for servers and workstations. Take it in -any direction you like. If you share this vision of what a GNU/Linux -distribution should be, then you are welcomed and encouraged to use it freely, -get involved, and contribute to the community. Welcome to Arch! -</p> + <h2 class="title">Parabola Presentation</h2> + + <p>In 2009 we started a project to offer the Free Software + community the chance of using an Arch system completely + freed from non-Free software.</p> + + <p>Today we have repositories and installable images of this wonderful + GNU/Linux distribution from which we have eliminated the non-Free software + contained in its official repositories and which we have replaced with Free + alternatives whenever we could.</p> + + <p>The first example is Linux-libre, the kernel without blobs nor non-Free + firmware. Followed by GNU IceCat, the Free fork of Mozilla Firefox that + doesn't recommend non-Free addons, and that in our case neither recommends + services that spy on you like the Google search engine.</p> + + <h3>Why you should use Parabola GNU/Linux-libre</h3> + + <p>Parabola GNU/Linux-libre equals software freedom plus all power to the users. GNU plus + ArchWay. With a continuosly updated system, simple to manage, simple to + package, you can build your own operating system in the way you want and + learn a lot along the way.</p> + + <h3>Free the GNU/Linux distribution of Arch</h3> + + <p>Following the minimalist, KISS, spirit of Arch, we have managed to + achieve its freedom in a simple way. To Free your Arch installation, + just install our Free repositories list and update your system.</p> + + <p>No reinstallation needed.</p> + + <h3>Participate</h3> + + <p>Boring tasks are always available. We want to start new projects. We want + to help people have servers of their own, with services of their own, with + Parabola Social. We want people to remix their own Arch system and share it + with the rest of the world.</p> + + <p>We want Free Software with a social utility for a Free society.</p> + + <p>But we need your help. If all of us share a little of the boring work, + we'll have more time to do the really fun stuff.</p> + + <p>Remaining tasks:</p> + + <ul> + <li>Audit repositories. If you find a non-Free package, or a package + with non-Free parts, report it as a bug.</li> + + <li>Host repositories. Mirrors are not abundant.</li> + + <li>Take a look at our <a href="{% wiki_url 'TODO' %}" title="TODO">TODO list</a></li> + </ul> + </div> <br /><br /> {% endblock %} diff --git a/templates/public/art.html b/templates/public/art.html deleted file mode 100644 index 9b0bd62f..00000000 --- a/templates/public/art.html +++ /dev/null @@ -1,129 +0,0 @@ -{% extends "base.html" %} -{% block title %}Arch Linux - Artwork{% endblock %} - -{% block content %} -<div id="artwork" class="box"> - - <h2>Arch Linux Logos and Artwork</h2> - - <h3>Logos for Press Usage</h3> - - <p>The following Arch Linux logos are available for press and other use, subject to - the restrictions of our <a href="http://wiki.archlinux.org/index.php/DeveloperWiki:TrademarkPolicy" - title="Arch Linux Trademark Policy">trademark policy</a>.</p> - - <p><strong>Two-color standard version</strong><br /> - <em>Also available in print-quality - <a href="/media/logos/archlinux-logo-dark-1200dpi.png" - title="Download 1200dpi PNG format">PNG</a> and scalable - <a href="/media/logos/archlinux-logo-dark-scalable.svg" - title="Download scalable SVG format">SVG</a> formats.</em></p> - - <img src="/media/logos/archlinux-logo-dark-90dpi.png" - alt="Arch Linux PNG logo @ 90dpi" title="Arch Linux PNG logo @ 90dpi" /> - - <p><strong>Two-color inverted version</strong> (for dark backgrounds)<br /> - <em>Also available in print-quality - <a href="/media/logos/archlinux-logo-light-1200dpi.png" - title="Download 1200dpi PNG format">PNG</a> and scalable - <a href="/media/logos/archlinux-logo-light-scalable.svg" - title="Download scalable SVG format">SVG</a> formats.</em></p> - - <img src="/media/logos/archlinux-logo-light-90dpi.png" - alt="Arch Linux PNG logo @ 90dpi" title="Arch Linux PNG logo @ 90dpi" class="inverted" /> - - <p><strong>One-color standard version</strong><br /> - <em>Also available in print-quality - <a href="/media/logos/archlinux-logo-black-1200dpi.png" - title="Download 1200dpi PNG format">PNG</a> and scalable - <a href="/media/logos/archlinux-logo-black-scalable.svg" - title="Download scalable SVG format">SVG</a> formats.</em></p> - - <img src="/media/logos/archlinux-logo-black-90dpi.png" - alt="Arch Linux PNG logo @ 90dpi" title="Arch Linux PNG logo @ 90dpi" /> - - <p><strong>One-colour inverted version</strong> (for dark backgrounds)<br /> - <em>Also available in print-quality - <a href="/media/logos/archlinux-logo-white-1200dpi.png" - title="Download 1200dpi PNG format">PNG</a> and scalable - <a href="/media/logos/archlinux-logo-white-scalable.svg" - title="Download scalable SVG format">SVG</a> formats.</em></p> - - <img src="/media/logos/archlinux-logo-white-90dpi.png" - alt="Arch Linux PNG logo @ 90dpi" title="Arch Linux PNG logo @ 90dpi" class="inverted" /> - - <h3>Logos and Artwork for the Community</h3> - - <p>Official logos and artwork are also available directly from the - repositories. Currently, these packages are:</p> - - <ul> - <li><strong>archlinux-artwork</strong> - official logos, icons and CD labels</li> - <li><strong>archlinux-wallpaper</strong> - a variety of desktop wallpapers - for standard and widescreen resolutions</li> - <li><strong>archlinux-themes-kde</strong> - KDE themes and icons</li> - <li><strong>archlinux-themes-kdm</strong> - KDM login themes</li> - <li><strong>archlinux-themes-slim</strong> - SLiM login themes</li> - </ul> - - <p>Alternatively, you can <a href="ftp://ftp.archlinux.org/other/artwork/" - title="Browse the FTP archives">download the source files via FTP</a>.</p> - - <h3>Former Logos</h3> - - <p>Arch has gone through a few generations of branding and what follows are - some of our past logos. Although these images are no longer used frequently, - they remain subject to license restrictions. Email - <strong>tradermarks@archlinux.org</strong> with any questions.</p> - - <h4>Original Ribbon Series</h4> - - <div class="imagelist"> - <img src="/media/logos/legacy/arch-legacy-ribbon1.png" alt="Arch Ribbon Logo 1"/> - <img src="/media/logos/legacy/arch-legacy-ribbon2.png" alt="Arch Ribbon Logo 2"/> - <img src="/media/logos/legacy/arch-legacy-ribbon5.png" alt="Arch Ribbon Logo 5"/> - </div> - - <div class="imagelist"> - <img src="/media/logos/legacy/arch-legacy-ribbon3.png" alt="Arch Ribbon Logo 3"/> - <img src="/media/logos/legacy/arch-legacy-ribbon4.png" alt="Arch Ribbon Logo 4"/> - <img src="/media/logos/legacy/arch-legacy-ribbon6.png" alt="Arch Ribbon Logo 6"/> - </div> - - <h4>"Arch Blue" Series</h4> - - <div class="imagelist"> - <a href="/media/logos/legacy/arch-legacy-blue1.svg" title="Arch Blue"> - <img src="/media/logos/legacy/arch-legacy-blue1.png" alt="Arch Blue"/></a> - <a href="/media/logos/legacy/arch-legacy-blue2.svg" title="Arch Blue Vertical"> - <img src="/media/logos/legacy/arch-legacy-blue2.png" alt="Arch Blue Vertical"/></a> - </div> - - <h4>"Arch Aqua" Series</h4> - - <div class="imagelist"> - <a href="/media/logos/legacy/arch-legacy-aqua.svg" title="Arch Aqua"> - <img src="/media/logos/legacy/arch-legacy-aqua.png" alt="Arch Aqua" /></a> - <a href="/media/logos/legacy/arch-legacy-aqua-blue.svg" title="Arch Aqua Blue"> - <img src="/media/logos/legacy/arch-legacy-aqua-blue.png" alt="Arch Aqua Blue" /></a> - <a href="/media/logos/legacy/arch-legacy-aqua-white.svg" title="Arch Aqua White"> - <img src="/media/logos/legacy/arch-legacy-aqua-white.png" alt="Arch Aqua White" /></a> - </div> - - <h4>Release-specific Series</h4> - - <div class="imagelist"> - <a href="/media/logos/legacy/arch-legacy-wombat-lg.png" title="Arch Wombat"> - <img src="/media/logos/legacy/arch-legacy-wombat.png" alt="Arch Wombat" /></a> - <a href="/media/logos/legacy/arch-legacy-noodle-blue.svg" title="Arch Noodle Blue"> - <img src="/media/logos/legacy/arch-legacy-noodle-blue.png" alt="Arch Noodle Blue" /></a> - <a href="/media/logos/legacy/arch-legacy-noodle-white.svg" title="Arch Noodle White"> - <img src="/media/logos/legacy/arch-legacy-noodle-white.png" alt="Arch Noodle White" /></a> - <a href="/media/logos/legacy/arch-legacy-noodle-box.svg" title="Arch Box of Noodles"> - <img src="/media/logos/legacy/arch-legacy-noodle-box.png" alt="Arch Box of Noodles" /></a> - <a href="/media/logos/legacy/arch-legacy-noodle-cup.svg" title="Arch Cup of Noodles"> - <img src="/media/logos/legacy/arch-legacy-noodle-cup.png" alt="Arch Cup of Noodles" /></a> - </div> - -</div><!-- #artwork --> -{% endblock %} diff --git a/templates/public/blank.html b/templates/public/blank.html index 2a8c83f4..3bf2cb2b 100644 --- a/templates/public/blank.html +++ b/templates/public/blank.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Sample Page Title{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Sample Page Title{% endblock %} {% block content %} <div id="sample-page-id" class="box"> diff --git a/templates/public/developer_list.html b/templates/public/developer_list.html index 61a612c6..041780d7 100644 --- a/templates/public/developer_list.html +++ b/templates/public/developer_list.html @@ -1,30 +1,36 @@ -<div id="arch-bio-toc"> +{% load flags %} +{% load pgp %} +<div id="arch-bio-toc"> <p> {% for dev in dev_list %} <a href="#{{ dev.username }}" title="Jump to profile for {{ dev.get_full_name }}"> - {{ dev.first_name }}{{ dev.last_name.0|capfirst}}</a> + {{ dev.first_name }} {{ dev.last_name }}</a> {% endfor %} </p> - </div> <table class="arch-bio-entry"> {% for dev in dev_list %} - {% with dev.get_profile as prof %} - <tr> + {% with dev.userprofile as prof %} + <tr itemscope itemtype="http://schema.org/Person"> <td class="pic pic-{{ dev.username }}"> - <img src="{{ prof.picture.url }}" height="125" width="125" alt="Image for {{ prof.alias }}"/> + <img itemprop="image" src="{{ prof.picture.url }}" height="125" width="125" alt="Image for {{ prof.alias }}"/> </td> <td> - <a name="{{ dev.username }}"></a> - <table class="bio bio-{{ dev.username }}" cellspacing="0"> + <meta itemprop="name" content="{{ dev.get_full_name|escape }}"/> + <meta itemprop="givenName" content="{{ dev.first_name|escape }}"/> + <meta itemprop="familyName" content="{{ dev.last_name|escape }}"/> + <meta itemprop="jobTitle" content="{{ group.member_title|escape }}"/> + <div style="display:none" itemprop="memberOf" itemscope itemtype="http://schema.org/Organization"> + <meta itemprop="name" content="{{ BRANDING_DISTRONAME }}"/> + </div> + <h3>{{ dev.get_full_name }}{% if prof.latin_name %} ({{ prof.latin_name}}){% endif %} + <a class="headerlink" name="{{ dev.username }}" id="{{ dev.username }}" href="#{{ dev.username }}" title="Permalink">¶</a></h3> + <table class="bio bio-{{ dev.username }}"> <tr> - <th>Name:</th> - <td>{{ dev.get_full_name }}</td> - </tr><tr> <th>Alias:</th> - <td>{{ prof.alias }}</td> + <td itemprop="additionalName">{{ prof.alias }}</td> </tr><tr> <th>Email:</th> <td>{{ prof.public_email }}</td> @@ -32,23 +38,26 @@ <th>Other Contact:</th> <td>{{ prof.other_contact }}</td> </tr><tr> + <th>PGP Key:</th> + <td>{% pgp_key_link prof.pgp_key %}</td> + </tr><tr> <th>Roles:</th> <td>{{ prof.roles }}<br /> </td> </tr><tr> <th>Website:</th> - <td>{% if prof %}<a href="{{ prof.website }}" + <td>{% if prof.website %}<a itemprop="url" href="{{ prof.website }}" title="Visit the website for {{ dev.get_full_name }}"> {{ prof.website }}</a>{% endif %}</td> </tr><tr> <th>Occupation:</th> <td>{{ prof.occupation }}</td> </tr><tr> - <th>YOB:</th> - <td>{% if prof.yob %}{{ prof.yob }}{% endif %}</td> + <th>Birth Year:</th> + <td itemprop="birthDate">{% if prof.yob %}{{ prof.yob }}{% endif %}</td> </tr><tr> <th>Location:</th> - <td>{{ prof.location }}</td> + <td>{% country_flag dev.userprofile.country %}{{ prof.location }}</td> </tr><tr> <th>Languages:</th> <td>{{ prof.languages }}</td> diff --git a/templates/public/donate.html b/templates/public/donate.html deleted file mode 100644 index 3e4e50c9..00000000 --- a/templates/public/donate.html +++ /dev/null @@ -1,90 +0,0 @@ -{% extends "base.html" %} -{% load cache %} - -{% block title %}Arch Linux - Donate{% endblock %} - -{% block content %} -{% cache 600 donations %} -<div id="donations" class="box"> - - <h2>Donate to Arch Linux</h2> - - <p>Arch Linux survives because of the tireless efforts of many people in - the community and the core development circle. None of us are paid for - our work, and we don't have the personal funds to sustain server costs - ourselves.</p> - - <p>There are many ways to help support Arch Linux. If technical development, - documentation, or support aren't your strong points, you could certainly - help us by dropping a few bucks our way.</p> - - <p>Many thanks!</p> - - <h3>Monetary donations</h3> - - <p>Financial contributions are accepted via <a title="Click to donate now" - href="https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=aaronmgriffin@gmail.com&currency_code=USD">PayPal</a>. - Funds are used for server hardware upgrades, conventions, schwag giveaways and more.</p> - - <div id="paypal-button"> - <!-- paypal code --> - <form id="paypal-form" name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post"> - <p><input type="hidden" name="cmd" value="_xclick"/></p> - <p><input type="hidden" name="business" value="aaronmgriffin@gmail.com"/></p> - <p><input type="hidden" name="currency_code" value="USD"/></p> - <p><input type="hidden" name="tax" value="0"/></p> - <p><input type="hidden" name="lc" value="US"/></p> - <p><input type="hidden" name="bn" value="PP-DonationsBF"/></p> - <p><input type="hidden" name="item_name" value="Arch Linux Donation"/></p> - <p><input type="hidden" name="no_shipping" value="1"/></p> - <p><input type="hidden" name="cn" value="Suggestions/Comments"/></p> - <p><input type="hidden" name="no_note" value="1"/></p> - <p><input type="image" src="/media/donate.gif" name="submit" - title="Make a PayPal donation to the Arch Linux project" - alt="Make a PayPal donation to the Arch Linux project" - style="background:transparent;border:none;" /></p> - </form> - </div> - - <h3>Commercial sponsors and contributions</h3> - - <p>We'd like to thank <a href="http://www.velocitynetwork.net/?hosting_by=ArchLinux" - title="velocity network">Velocity Network</a> for contributing space - in a server rack, bandwidth, and electricity for our main server.</p> - - <a href="http://www.velocitynetwork.net/?hosting_by=ArchLinux" - title="velocity network"><img src="/media/vnet_button.png" class="sponsor-btn-vnet" - title="" alt="velocity network - it's about time" /></a> - - <p>We also wish to extend a special Thank You to <a - href="https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" - title="SevenL Networks - Dedicated Arch Linux servers">SevenL Networks</a> - for their generous and ongoing contribution of a dedicated Arch Linux - server . You too can have a dedicated Arch Linux server hosted by SevenL... - head over to their website for more details.</p> - - <a href="https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" - title="SevenL Networks - Dedicated Arch Linux servers"><img src="/media/sevenl_button.png" - class="sponsor-btn-sevenl" title="A big Thank You to SevenL Networks for their generous contribution" - alt="We would like to express our thanks to SevenL Networks for their generous contribution" /></a> - - <p>More thanks go to <a href="http://www.airvm.com/VirtualServers" - title="AirVM.com">AirVM.com</a> for contributing a VMWare-based Virtual Machine.</p> - - <a href="http://www.airvm.com/VirtualServers" - title="AirVM.com - Your Green Technology Partner"><img src="/media/airvm_button.jpg" - class="sponsor-btn-airvm" title="AirVM.com - Your Green Technology Partner" alt="AirVM.com - Your Green Technology Partner" /></a> - - <h3>Past donors</h3> - - <div id="donor-list"> - <ul> - {% for donor in donors %} - <li>{{ donor.name }}</li>{% endfor %} - </ul> - </div> - <div class="clear"></div> - <p>A huge thanks to you all for your contributions!</p> -</div> -{% endcache %} -{% endblock %} diff --git a/templates/public/download.html b/templates/public/download.html deleted file mode 100644 index d4a33db3..00000000 --- a/templates/public/download.html +++ /dev/null @@ -1,169 +0,0 @@ -{% extends "base.html" %} -{% load cache %} - -{% block title %}Arch Linux - Downloads{% endblock %} -{% block navbarclass %}anb-download{% endblock %} - -{% block content %} -<div id="arch-downloads" class="box"> - - <h2>Arch Linux Downloads</h2> - - {% with "2010.05" as version %} - <h3>Release Info</h3> - - <p>All available images can be burned to a CD, mounted as an ISO file, - or be directly written to a USB stick using a utility like `dd`. These - are intended for new installations only; an existing Arch Linux system - can always be updated with `pacman -Syu`.</p> - - <ul> - <li><strong>Current Release:</strong> {{ version }}</li> - <li><strong>Included Kernel:</strong> 2.6.33.4</li> - <li><strong>Resources:</strong> - <ul> - <li><a href="https://bugs.archlinux.org/index.php?project=6" - title="Arch Linux Bugtracker:Release Engineering">Bug Tracker</a></li> - <li><a href="http://www.archlinux.org/mailman/listinfo/arch-releng" - title="Arch Linux Release Engineering mailing list">Mailing List</a></li> - </ul> - </li> - </ul> - - <p><strong>Links and Instructions:</strong></p> - - <ul id="download-help"> - <li><a href="http://www.archlinux.org/iso/{{ version }}/README" - title="Official download instructions">Readme and Instructions</a></li> - <li><a href="http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" - title="Official Installation Guide">Arch Linux Install Guide</a></li> - </ul> - - <h3>Existing Arch Users</h3> - - <p>If you are an existing Arch user, there is no need to download a new ISO - to update your existing system. You may be looking for - <a href="{% url mirrorlist %}">an updated mirrorlist</a> instead.</p> - - <h3>BitTorrent Download (recommended)</h3> - - <p>If you can spare the bytes, please leave the client open after your - download is finished, so you can seed it back to others. - <em>A web-seed capable client is recommended for fastest download speeds.</em></p> - - <table id="download-torrents" class="pretty1"> - <thead> - <tr> - <th>Format</th> - <th class="cpu-arch">i686 CPU</th> - <th class="cpu-arch">x86-64 CPU</th> - <th class="cpu-arch">Dual Architecture</th> - <th>Description</th> - </tr> - </thead> - <tbody> - <tr> - <td> - Netinstall Image - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-netinstall-i686.iso.torrent" - title="Download for i686 architecture">Download</a> - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-netinstall-x86_64.iso.torrent" - title="Download for x86-64 architecture">Download</a> - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-netinstall-dual.iso.torrent" - title="Download for both architectures">Download</a> - </td><td class="wrap"> - Downloads and installs packages versions via FTP for absolute freshness. - </td> - </tr><tr> - <td> - Core Image - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-core-i686.iso.torrent" - title="Download for i686 architecture">Download</a> - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-core-x86_64.iso.torrent" - title="Download for x86-64 architecture">Download</a> - </td><td class="cpu-arch"> - <a href="http://www.archlinux.org/iso/{{version}}/archlinux-{{version}}-core-dual.iso.torrent" - title="Download for both architectures">Download</a> - </td><td class="wrap"> - Core packages are included on the media. Good for basic off-line installation. - </td> - </tr> - </tbody> - </table> - - <h3>Get Arch Linux on CD</h3> - - <p>The following suppliers donate a portion of their proceeds to the - Arch Linux project:</p> - - <ul id="cd-vendors-donate"> - <li><a href="http://www.osdisc.com/cgi-bin/view.cgi/products/linux/arch?affiliate=archlinux" - title="Purchase a CD from OSDisc">Purchase a CD from OSDisc</a></li> - <li><a href="http://www.shoplinuxonline.com/index.php?main_page=index&cPath=1_46&zenid=ecd15b48affe8976130bc575c1276ee4" - title="Purchase a CD from Shop Linux Online">Purchase a CD from Shop Linux Online</a></li> - </ul> - - <p>Arch Linux CDs are also available for purchase from these suppliers:</p> - - <ul id="cd-vendors"> - <li><a href="http://www.linuxcd.org/view_distro.php?id_distro=48" - title="Purchase a CD from LinuxCD">Purchase a CD from LinuxCD</a></li> - </ul> - - - <h3>HTTP/FTP Direct Downloads</h3> - - <p>In addition to the BitTorrent links above, install images can also be - downloaded via HTTP or FTP from the mirror sites listed below. Please - ensure the download image matches the checksum from the md5sums.txt or - sha1sums.txt file in the same directory as the image.</p> - - <h4>Checksums</h4> - - <p>File integrity checksums for the latest releases can be found below:</p> - - <ul> - <li><a href="http://www.archlinux.org/iso/{{version}}/sha1sums.txt" - title="Get the latest SHA1 checksums">SHA1 checksums</a></li> - <li><a href="http://www.archlinux.org/iso/{{version}}/md5sums.txt" - title="Get the latest MD5 checksums">MD5 checksums</a></li> - </ul> - {% endwith %} - - {% cache 600 download-mirrors %} - <table id="download-mirrors"> - <thead> - <tr> - <th><h4>Server Location</h4></th> - <th><h4>Download</h4></th> - </tr> - </thead> - <tbody> - <tr><td colspan="2"> - {% for mirror_url in mirror_url_list %} - {% ifchanged mirror_url.mirror.country %} - </td></tr> - <tr><td class="mirror-country" colspan="2"><strong>{{mirror_url.mirror.country}}</strong> - {% endifchanged %} - {% ifchanged mirror_url.mirror.name %} - </td></tr> - <tr><td class="mirror-server">{{mirror_url.mirror.name}}</td><td> - {% endifchanged %} - <a href="{{mirror_url.url}}iso/" - title="Download from {{mirror_url.url}}iso/">{{mirror_url.protocol.protocol|upper}}</a> - {% endfor %} - </td></tr> - </tbody> - </table> - {% endcache %} - - <p>If you want to become an Official Arch Linux Mirror please follow the - instructions listed <a href="http://wiki.archlinux.org/index.php/DeveloperWiki:NewMirrors">here</a>.</p> - -</div> -{% endblock %} diff --git a/templates/public/feeds.html b/templates/public/feeds.html index 3d457bb9..70d8eee6 100644 --- a/templates/public/feeds.html +++ b/templates/public/feeds.html @@ -1,29 +1,29 @@ -{% extends "base.html" %} -{% block title %}Arch Linux - RSS Feeds{% endblock %} +{% extends "base.html" %}{% load wiki %} +{% block title %}{{ BRANDING_DISTRONAME }} - RSS Feeds{% endblock %} {% block content %} <div id="rss-feeds" class="box"> <h2>RSS Feeds</h2> - <p>Several RSS feeds are available for consumption from the Arch website. + <p>Several RSS feeds are available for consumption from the {{ BRANDING_SHORTNAME }} website. The majority of these are package-related and allow feeds to be customized for the updates you care about.</p> <h3>News and Activity Feeds</h3> - <p>Grab the <a href="/feeds/news/" class="rss" title="Arch Linux News feed">news item feed</a> - to keep up-to-date with the latest news from the Arch Linux development staff.</p> + <p>Grab the <a href="/feeds/news/" class="rss" title="{{BRANDING_DISTRONAME}} news feed">news item feed</a> + to keep up-to-date with the latest news from the {{BRANDING_DISTRONAME}} development staff.</p> - <p>The <a href="http://wiki.archlinux.org/index.php?title=Special:RecentChanges&feed=rss" - title="ArchWiki Recent Changes feed" class="rss">Arch Wiki: Recent changes feed</a> - is also available to track document changes from the <a href="http://wiki.archlinux.org/" - title="Arch Wiki community documentation">Arch Wiki</a>.</p> + <p>The <a href="{% wiki_url 'Special:RecentChanges?feed=rss' %}" + title="{{ BRANDING_WIKINAME }} Recent Changes feed" class="rss">{{ BRANDING_WIKINAME }}: Recent changes feed</a> + is also available to track document changes from the <a href="{% wiki_url %}" + title="{{ BRANDING_WIKINAME }} community documentation">{{ BRANDING_WIKINAME }}</a>.</p> <h3>Package Feeds</h3> <p>If you are interested in <a href="/feeds/packages/" class="rss" - title="Arch Linux package updates feed">all package updates</a>, + title="{{ BRANDING_DISTRONAME }} package updates feed">all package updates</a>, then grab this feed. Note that when a package is updated for multiple architectures, you will see each individual update show up here. Alternatively, you can select a packages feed from the below table that is @@ -35,19 +35,26 @@ <table class="pretty2"> <thead> <tr> - <th>Architecture</th> - <th>All Repos</th> - {% for repo in repos %} - <th>{{ repo }}</th> + <th></th> + <th>All Arches</th> + {% for arch in arches %} + <th>{{ arch }}</th> {% endfor %} </tr> </thead> <tbody> - {% for arch in arches %} <tr> - <td><strong>{{ arch }}</strong></td> + <td><strong>All Repos</strong></td> + <td><a href="/feeds/packages/" class="rss">Feed</a></td> + {% for arch in arches %} <td><a href="/feeds/packages/{{ arch }}/" class="rss">Feed</a></td> - {% for repo in repos %} + {% endfor %} + </tr> + {% for repo in repos %} + <tr> + <td><strong>{{ repo }}</strong></td> + <td><a href="/feeds/packages/all/{{ repo|lower }}/" class="rss">Feed</a></td> + {% for arch in arches %} <td><a href="/feeds/packages/{{ arch }}/{{ repo|lower }}/" class="rss">Feed</a></td> {% endfor %} </tr> @@ -55,54 +62,71 @@ </tbody> </table> - <p>A <a href="http://aur.archlinux.org/rss.php" class="rss" title="AUR newest packages feed">newest packages feed</a> - is also available from the <a href="http://aur.archlinux.org/" title="AUR Homepage">Arch User Repository (AUR)</a>.</p> + <h3>Release Feed</h3> + + <p>Grab the <a href="/feeds/releases/" class="rss" title="{{BRANDING_DISTRONAME}} release feed">ISO release feed</a> + if you want to help seed the ISO release torrents as they come out.</p> <h3>Development Feeds</h3> <p>Subscribe to any of the following to track bug tickets and feature - requests from the <a href="https://bugs.archlinux.org/" title="Arch Linux Bugs">Arch Linux Bugtracker</a>:</p> + requests from the <a href="{{BUGTRACKER_URL}}" title="{{BRANDING_DISTRONAME}} Bugs">{{BRANDING_DISTRONAME}} Bugtracker</a>:</p> <table class="pretty2"> <thead> <tr> <th>Project</th> - <th>Recently Opened Tasks</th> - <th>Recently Edited Tasks</th> - <th>Recently Closed Tasks</th> + <th>Activity</th> + <th>Issues</th> + <th>News</th> </tr> </thead> <tbody> <tr> <td>All Projects</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=99" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=99" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=99" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/news.atom" class="rss">Feed</a></td> + </tr><tr> + <td>Art4Parabola</td> + <td><a href="https://labs.parabola.nu/projects/art4parabola/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/art4parabola/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/art4parabola/news.atom" class="rss">Feed</a></td> + </tr><tr> + <td>Documentation</td> + <td><a href="https://labs.parabola.nu/projects/documentation/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/documentation/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/documentation/news.atom" class="rss">Feed</a></td> + </tr><tr> + <td>Installation media (i686 and x86_64)</td> + <td><a href="https://labs.parabola.nu/projects/isos/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/isos/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/isos/news.atom" class="rss">Feed</a></td> </tr><tr> - <td>Arch Linux</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=1" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=1" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=1" class="rss">Feed</a></td> + <td>Libretools</td> + <td><a href="https://labs.parabola.nu/projects/libretools/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/libretools/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/libretools/news.atom" class="rss">Feed</a></td> </tr><tr> - <td>Release Engineering</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=6" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=6" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=6" class="rss">Feed</a></td> + <td>Packages (i686 and x86_64)</td> + <td><a href="https://labs.parabola.nu/projects/issue-tracker/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/issue-tracker/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/issue-tracker/news.atom" class="rss">Feed</a></td> </tr><tr> - <td>Pacman Development</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=3" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=3" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=3" class="rss">Feed</a></td> + <td>Ports</td> + <td><a href="https://labs.parabola.nu/projects/ports/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/ports/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/ports/news.atom" class="rss">Feed</a></td> </tr><tr> - <td>Community Packages</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=5" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=5" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=5" class="rss">Feed</a></td> + <td>Port: Loongson 2F (mips64el)</td> + <td><a href="https://labs.parabola.nu/projects/mips64el/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/mips64el/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/mips64el/news.atom" class="rss">Feed</a></td> </tr><tr> - <td>AUR</td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&project=2" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=edit&project=2" class="rss">Feed</a></td> - <td><a href="https://bugs.archlinux.org/feed.php?feed_type=rss2&topic=clo&project=2" class="rss">Feed</a></td> + <td>Servers</td> + <td><a href="https://labs.parabola.nu/projects/servers/activity.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/servers/issues.atom" class="rss">Feed</a></td> + <td><a href="https://labs.parabola.nu/projects/servers/news.atom" class="rss">Feed</a></td> </tr> </tbody> </table> diff --git a/templates/public/index.html b/templates/public/index.html index a9c7a85c..12c01fbc 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -1,212 +1,246 @@ {% extends "base.html" %} -{% load markup %} {% load cache %} +{% load static from staticfiles %} +{% load wiki %} {% block head %} -<link rel="alternate" type="application/rss+xml" title="Arch Linux News Updates" href="/feeds/news/" /> -<link rel="alternate" type="application/rss+xml" title="Arch Linux Package Updates" href="/feeds/packages/" /> +<link rel="alternate" type="application/rss+xml" title="{{ BRANDING_DISRONAME }} News Updates" href="/feeds/news/" /> +<link rel="alternate" type="application/rss+xml" title="{{ BRANDING_DISRONAME }} Package Updates" href="/feeds/packages/" /> {% endblock %} {% block content_left %} -{% cache 300 main-page-left %} +{% cache 62 main-page-left secure %} <div id="intro" class="box"> - - <h2>A simple, lightweight distribution</h2> - - <p>You've reached the website for <strong>Arch Linux</strong>, a - lightweight and flexible Linux® distribution that tries to Keep It - Simple.</p> - - <p>Currently we have official packages optimized for the i686 and - x86-64 architectures. We complement our official package sets with a - <a href="http://aur.archlinux.org" title="Arch User Repository (AUR)"> - community-operated package repository</a> that grows in size and - quality each and every day.</p> - - <p>Our strong community is diverse and helpful, and we pride ourselves - on the range of skillsets and uses for Arch that stem from it. Please - check out our <a href="https://bbs.archlinux.org" title="Arch Forums">forums</a> - and <a href="http://www.archlinux.org/mailman/listinfo/" title="Arch Mailing Lists">mailing lists</a> - to get your feet wet. Also glance through our <a href="http://wiki.archlinux.org" title="Arch Wiki">wiki</a> - if you want to learn more about Arch.</p> - - <p class="readmore"><a href="{% url page-about %}" - title="Learn more about Arch Linux">Learn more...</a></p> - -</div><!-- #intro --> + <h2>A fully free, simple, and lightweight operating system</h2> + + <p>You've reached the website of the Parabola GNU/Linux-libre operating + system. The Parabola project is a community driven effort to provide a + fully Free (as in + <a href="https://www.gnu.org/philosophy/free-sw">freedom</a>) operating + system that is simple and lightweight.</p> + + <p>Derived from Arch (the GNU/Linux distribution), Parabola provides packages from it that meet the + <a href="http://www.gnu.org/distros/free-system-distribution-guidelines.html">Free + System Distribution Guidelines (FSDG)</a> and replacements for the packages + that don't meet this requirement. Packages are provided for the i686, + x86_64, and armv7h architectures.</p> + + <p>Our community is friendly and helpful. Please hop on + <a href="irc://chat.freenode.net#parabola">IRC channel</a> and check out our + <a href="https://lists.parabola.nu/mailman/listinfo/">mailing + lists</a> to get your feet wet. Also glance through our + <a href="https://wiki.parabola.nu/">wiki</a> if you want to learn + more about Parabola.</p> + + <p class="readmore"><a href="{% url 'page-about' %}" + title="Learn more about {{ BRANDING_DISTRONAME }}">Learn more...</a></p> +</div> <div id="news"> - - <h3>Latest News <span class="more">(<a href="{% url news-list %}" - title="Browse the news archives">more</a>)</span></h3> - - <a href="/feeds/news/" title="Arch News RSS Feed" - class="rss-icon"><img src="/media/rss.png" alt="RSS Feed" /></a> - - {% for news in news_updates %} - <h4><a href="{{ news.get_absolute_url }}" - title="View full article: {{ news.title }}">{{ news.title }}</a></h4> + <h3> + <a href="{% url 'news-list' %}" title="Browse the news archives">Latest News</a> + <span class="arrow"></span> + </h3> + + <a href="/feeds/news/" title="{{ BRANDING_SHORTNAME }} News RSS Feed" + class="rss-icon"><img width="16" height="16" src="{% static "rss.png" %}" alt="RSS Feed" /></a> + + {% for news in news_updates %}{% if forloop.counter0 < 5 %} + <h4> + <a href="{{ news.get_absolute_url }}" + title="View full article: {{ news.title }}">{{ news.title }}</a> + </h4> <p class="timestamp">{{ news.postdate|date }}</p> - <div class="article-content">{{ news.content|markdown|truncatewords_html:75 }}</div> - {% endfor %} - -</div><!-- #news --> + <div class="article-content"> + {% if forloop.counter0 == 0 %}{{ news.html|truncatewords_html:300 }} + {% else %}{{ news.html|truncatewords_html:100 }}{% endif %} + </div> + {% else %}{% if forloop.counter0 == 5 %} + <h3> + <a href="{% url 'news-list' %}" + title="Browse the news archives">Older News</a> + <span class="arrow"></span> + </h3> + <dl class="newslist"> + {% endif %} + <dt>{{ news.postdate|date }}</dt> + <dd> + <a href="{{ news.get_absolute_url }}" + title="View full article: {{ news.title }}">{{ news.title }}</a> + </dd> + {% if forloop.last %}</dl>{% endif %} + {% endif %}{% endfor %} +</div> {% endcache %} {% endblock %} {% block content_right %} -{% cache 300 main-page-right %} +{% cache 59 main-page-updates user.is_authenticated %} <div id="pkgsearch" class="widget"> - <form id="pkgsearch-form" method="get" action="/packages/"> <fieldset> <label for="pkgsearch-field">Package Search:</label> <input id="pkgsearch-field" type="text" name="q" size="18" maxlength="200" /> </fieldset> </form> - </div> <div id="pkg-updates" class="widget box"> - <h3>Recent Updates <span class="more">(<a href="/packages/?sort=-last_update" title="Browse all of the latest packages">more</a>)</span></h3> - <a href="/feeds/packages/" title="Arch Package Updates RSS Feed" - class="rss-icon"><img src="/media/rss.png" alt="RSS Feed" /></a> + <a href="/feeds/packages/" title="{{ BRANDING_SHORTNAME }} Package Updates RSS Feed" + class="rss-icon"><img width="16" height="16" src="{% static "rss.png" %}" alt="RSS Feed" /></a> <table> {% for update in pkg_updates %} - {% with update|first as fpkg %} <tr> - <td class="pkg-name"><span class="{{ fpkg.repo.name|lower }}">{{ fpkg.pkgname }} {{ fpkg.pkgver }}-{{ fpkg.pkgrel }}</span></td> + <td class="pkg-name"><span class="{{ update.classes|join:' ' }}">{{ update.pkgbase }} {{ update.version }}</span></td> <td class="pkg-arch"> - {% for pkg in update %}<a href="{{ pkg.get_absolute_url }}" - title="View package details for {{ pkg.pkgname }}">{{ pkg.arch }}</a>{% if not forloop.last %}/{% endif %}{% endfor %} + {% for pkg in update.package_links %}<a href="{{ pkg.get_absolute_url }}" + title="Details for {{ pkg.pkgname }} [{{ pkg.repo|lower }}]">{{ pkg.arch }}</a>{% if not forloop.last %}/{% endif %}{% endfor %} </td> </tr> - {% endwith %} {% endfor %} </table> </div> +{% endcache %} +{% cache 115 main-page-right secure %} <div id="nav-sidebar" class="widget"> - <h4>Documentation</h4> - <ul> - <li><a href="http://wiki.archlinux.org/" + <li><a href="{% wiki_url %}" title="Community documentation">Wiki</a></li> - <li><a href="http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" - title="Official installation guide">Official Installation Guide</a></li> - <li><a href="http://wiki.archlinux.org/index.php/Beginners'_Guide" - title="A good place to start for beginners">Unofficial Beginners' Guide</a></li> + <li><a href="{% wiki_url "Beginners'_guide" %}" + title="A good place to start for beginners">Beginners' Guide</a></li> + <li><a href="{% wiki_url 'Installation_Guide' %}" + title="Installation guide">Installation Guide</a></li> + <li><a href="{% wiki_url 'ARM_Installation_Guide' %}" + title="ARM Installation guide">ARM Installation Guide</a></li> + <li><a href="{% wiki_url 'Migration_from_other_distributions' %}" + title="Free your distro installation">Migration from other distros</a></li> </ul> - <h4>Community</h4> + <h4>Free Culture</h4> + <ul> + <li><a href="{% wiki_url 'Multimedia' %}" + title="Watch and download multimedia files">Multimedia</a></li> + <li><a href="{% wiki_url 'Comics' %}" + title="Watch and download comics">Comics</a></li> + <li><a href="{% wiki_url 'Wallpapers' %}" + title="Download wallpapers">Wallpapers</a></li> + </ul> + <h4>Community</h4> <ul> - <li><a href="http://mailman.archlinux.org/mailman/listinfo/" + <li><a href="{{ MAILMAN_BASE_URL }}/mailman/listinfo/" title="Community and developer mailing lists">Mailing Lists</a></li> - <li><a href="http://wiki.archlinux.org/index.php/IRC_Channels" + <li><a href="{% wiki_url 'IRC_channels' %}" title="Official and regional IRC communities">IRC Channels</a></li> - <li><a href="http://planet.archlinux.org/" - title="Arch in the blogosphere">Planet Arch</a></li> - <li><a href="http://rollingrelease.com/" - title="Community online magazine">Rolling Release Ezine</a></li> - <li><a href="http://wiki.archlinux.org/index.php/International_Communities" - title="Arch communities in your native language">International Communities</a></li> - <li><a href="http://wiki.archlinux.org/index.php/Related_Projects" - title="Projects that are in some way related to Arch Linux">Related Projects</a></li> + <li><a href="https://gnusocial.net/group/parabola" + title="Parabola at gnusocial.net">GNU social group</a></li> + <li><a href="https://www.reddit.com/r/parabola/" + title="Parabola at reddit.com">Reddit forum</a></li> </ul> <h4>Support</h4> - <ul> - <li><a href="{% url page-donate %}" title="Help support Arch Linux">Donate</a></li> - <li><a href="http://schwag.archlinux.ca/" - title="USB keys, jewellery, case badges">Arch Schwag</a></li> - <li><a href="http://www.zazzle.com/archlinux*" - title="T-shirts, mugs, mouse pads, hoodies, posters, skateboards, shoes, etc.">Schwag via Zazzle</a></li> - <li><a href="http://www.freewear.org/?page=list_items&org=Archlinux" - title="T-shirts">Schwag via Freewear</a></li> + <li><a href="{% url 'page-donate' %}" + title="Help support {{ BRANDING_DISTRONAME }}">Donate</a></li> </ul> <h4>Tools</h4> - <ul> - <li><a href="{% url mirrorlist %}" + <li><a href="{% url 'mirrorlist' %}" title="Get a custom mirrorlist from our database">Mirrorlist Updater</a></li> - <li><a href="{% url mirror-status %}" + <li><a href="{% url 'mirror-list' %}" + title="See a listing of all available mirrors">Mirror List</a></li> + <li><a href="{% url 'mirror-status' %}" title="Check the status of all known mirrors">Mirror Status</a></li> - <li><a href="/packages/differences/" - title="See differences in packages between available architectures">Differences by Architecture</a></li> </ul> <h4>Development</h4> - <ul> - <li><a href="/packages/" - title="View/search the package repository database">Packages</a></li> + <li><a href="{{ PROJECTS_URL }}" + title="Official {{BRANDING_SHORTNAME}} projects (git)">Projects in Git</a></li> +{% comment %} + <li><a href="{% url 'page-svn' %}" + title="View SVN entries for packages">SVN Repositories</a></li> + <li><a href="{% wiki_url 'DeveloperWiki' %}" + title="Developer Wiki articles">Developer Wiki</a></li> +{% endcomment %} <li><a href="/groups/" title="View the available package groups">Package Groups</a></li> - <li><a href="https://bugs.archlinux.org/" - title="Report/track bugs or make feature requests">Bug Tracker</a></li> - <li><a href="{% url page-svn %}" - title="View SVN entries for packages">SVN Repositories</a></li> - <li><a href="http://projects.archlinux.org/" - title="Official Arch projects (git)">Projects in Git</a></li> - <li><a href="http://wiki.archlinux.org/index.php/DeveloperWiki" - title="Developer Wiki articles">DeveloperWiki</a></li> - <li><a href="/todolists/" - title="Developer Todo Lists">Todo Lists</a></li> + <li><a href="/todo/" + title="Hacker Todo Lists">Todo Lists</a></li> + <li><a href="{% url 'releng-release-list' %}" + title="Release Engineering ISO listing">ISO Release List</a></li> + <li><a href="{% url 'visualize-index' %}" + title="View visualizations">Visualizations</a></li> + <li><a href="{% url 'packages-differences' %}" + title="See differences in packages between available architectures">Differences Reports</a></li> </ul> - <h4>About</h4> + <h4>People</h4> + <ul> + {% for group in staff_groups %} + <li><a href="{% url 'people' group.slug %}" title="More info about {{ group.name }}">{{ group.name }}</a></li> + {% endfor %} + <li><a href="{% url 'page-keys' %}" + title="Package/Database signing master keys">Signing Master Keys</a></li> + </ul> + <h4>More Resources</h4> <ul> - <li><a href="http://wiki.archlinux.org/index.php/ArchLinux:About" - title="Learn more about Arch Linux">About Arch</a></li> - <li><a href="/download/" title="Get Arch Linux">Download Arch</a></li> - <li><a href="http://wiki.archlinux.org/index.php/Arch_Linux_Press_Review" - title="Arch Linux in the media">Press Coverage</a></li> - <li><a href="{% url page-art %}" title="Arch logos and other artwork for promotional use">Logos & Artwork</a></li> - <li><a href="{% url news-list %}" title="News Archives">News Archives</a></li> + <li><a href="{% wiki_url 'Media' %}" + title="{{ BRANDING_DISTRONAME }} in the media">Press Coverage</a></li> + <li><a href="{% url 'news-list' %}" title="News Archives">News Archives</a></li> <li><a href="/feeds/" title="Various RSS Feeds">RSS Feeds</a></li> - <li><a href="{% url page-devs %}" title="Active developers">Developer Profiles</a></li> - <li><a href="{% url page-tus %}" title="Active Trusted Users (TUs)">Trusted User Profiles</a></li> - <li><a href="{% url page-fellows %}" title="Retired Developers">Fellows Profiles</a></li> </ul> +</div> -</div><!-- #nav-sidebar --> - -<div id="home-paypal-button" class="widget"> - - <form id="paypal-form" name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post"> - <p><input type="hidden" name="cmd" value="_xclick"/></p> - <p><input type="hidden" name="business" value="aaronmgriffin@gmail.com"/></p> - <p><input type="hidden" name="currency_code" value="USD"/></p> - <p><input type="hidden" name="tax" value="0"/></p> - <p><input type="hidden" name="lc" value="US"/></p> - <p><input type="hidden" name="bn" value="PP-DonationsBF"/></p> - <p><input type="hidden" name="item_name" value="Arch Linux Donation"/></p> - <p><input type="hidden" name="no_shipping" value="1"/></p> - <p><input type="hidden" name="cn" value="Suggestions/Comments"/></p> - <p><input type="hidden" name="no_note" value="1"/></p> - <p><input type="image" src="/media/donate.gif" name="submit" - title="Make a PayPal donation to the Arch Linux project" - alt="Make a PayPal donation to the Arch Linux project" - style="background:transparent;border:none;" /></p> - </form> - +{% comment %} +<div id="home-donate-button" class="widget"> +donate button would go here </div> +{% endcomment %} <div id="arch-sponsors" class="widget"> - - <a href="http://www.velocitynetwork.net/?hosting_by=ArchLinux" title="Velocity Network"><img src="/media/vnet_button.png" alt="Velocity Network - It's about time" /></a> - <a href="https://www.sevenl.net/?utm_source=archlinux-org&utm_medium=sponsored-banner&utm_campaign=thanks-to-sevenl" title="SevenL Networks - Dedicated Arch Linux servers"><img src="/media/sevenl_button.png" title="A big Thank You to SevenL Networks for their generous contribution" alt="We would like to express our thanks to SevenL Networks for their generous contribution" /></a> - <a href="http://www.airvm.com/VirtualServers" title="AirVM.com - Your Green Technology Partner"><img src="/media/airvm_button.jpg" title="AirVM.com - Your Green Technology Partner" alt="AirVM.com - Your Green Technology Partner" /></a> - + <a href="https://ceata.org"> + <img src="{% static "ceata-parabola.png" %}" + alt="FundaÈ›ia Ceata - Parabola's fiscal sponsor" + title="FundaÈ›ia Ceata - Parabola's fiscal sponsor" /> + </a> + + <a href="https://www.gandi.net"> + <img src="{% static "gandi.png" %}" + alt="Gandi.net - Parabola's domain name sponsor" + title="Gandi.net - Parabola's domain name sponsor" /> + </a> + + <a href="https://1984.is"> + <img src="{% static "1984.png" %}" + alt="1984 - Parabola's server hosting sponsor" + title="1984 - Parabola's server hosting sponsor" /> + </a> + + <a href="https://www.robofun.ro"> + <img src="{% static "robofun.jpg" %}" + alt="Robofun - Parabola's ARM port sponsor" + title="Robofun - Parabola's ARM port sponsor" /> + </a> </div> {% endcache %} {% endblock %} + +{% block script_block %} +<div id="konami" style="display:none;"></div> + +{% load cdn %}{% jquery %} +<script type="text/javascript"> +$(document).ready(function() { + $.ajax({ url: "{% static "homepage.js" %}", cache: true, dataType: "script", success: function() { setupTypeahead(); setupKonami("{% static "vector_tux.png" %}"); } }); +}); +</script> +{% endblock %} diff --git a/templates/public/keys.html b/templates/public/keys.html new file mode 100644 index 00000000..f15ec1a9 --- /dev/null +++ b/templates/public/keys.html @@ -0,0 +1,156 @@ +{% extends "base.html" %} +{% load static from staticfiles %} +{% load pgp %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Master Signing Keys{% endblock %} + +{% block content %} +<div id="signing-keys" class="box"> + <h2>Master Signing Keys</h2> + + <p>This page lists the {{ BRANDING_DISTORNAME }} Master Keys. This is a distributed set of + keys that are seen as "official" signing keys of the distribution. Each key + is held by a different developer, and a revocation certificate for the key + is held by a different developer. Thus, no one developer has absolute hold + on any sort of absolute, root trust.</p> + <p>The {{ keys|length }} key{{ keys|pluralize }} listed below should be + regarded as the current set of master keys. They are available on public + keyservers and should be signed by the owner of the key.</p> + + <table class="pretty2"> + <thead> + <tr> + <th>Master Key</th> + <th>Full Fingerprint</th> + <th>Owner</th> + <th>Owner's Signing Key</th> + <th>Revoker</th> + <th>Revoker's Signing Key</th> + <th>Developer/TU Keys Signed</th> + </tr> + </thead> + <tbody> + {% for key in keys %} + <tr> + <td>{% pgp_key_link key.pgp_key %}</td> + <td><tt>{{ key.pgp_key|pgp_fingerprint }}</tt></td> + {% with key.owner.userprofile as owner_profile %} + <td><a href="{{ owner_profile.get_absolute_url }}">{{ key.owner.get_full_name }}</a></td> + <td>{% pgp_key_link owner_profile.pgp_key %}</td> + {% endwith %} + {% with key.revoker.userprofile as revoker_profile %} + <td><a href="{{ revoker_profile.get_absolute_url }}">{{ key.revoker.get_full_name }}</a></td> + <td>{% pgp_key_link revoker_profile.pgp_key %}</td> + {% endwith %} + <td>{{ key.signature_count }}</td> + </tr> + {% endfor %} + </tbody> + </table> + + <ul> + <li><a href="#master-sigs">Master Key Signatures</a></li> + <li><a href="#visualization">Visualization of PGP Master and Developer Keys</a></li> + <li><a href="#cross-sigs">Developer Cross-Signatures</a></li> + </ul> +</div> + +<div class="box"> + <h2 id="master-sigs">Master Key Signatures</h2> + + <p>The following table shows all active developers and trusted users along + with the status of their personal signing key. A 'Yes' indicates that the + personal key of the developer is signed by the given master key. A 'No' + indicates it has not been signed; however, this does not necessarily mean + the key should not be trusted.</p> + <p>All official {{ BRANDING_DISTRONAME }} developers and trusted users should have their + key signed by at least three master keys if they are responsible for + packaging software in the repositories. This is in accordance with the PGP + <em>web of trust</em> concept. If a user is willing to marginally trust all + of the master keys, three signatures from different master keys will + consider a given developer's key as valid. For more information on trust, + please consult the + <a href="http://www.gnupg.org/gph/en/manual.html">GNU Privacy Handbook</a> + and <a href="http://www.gnupg.org/gph/en/manual.html#AEN385">Using trust to + validate keys</a>.</p> + + <table class="pretty2" id="key-status"> + <thead> + <tr> + <th>Developer</th> + <th>PGP Key</th> + {% for key in keys %} + <th>{{ key.owner.get_full_name }}<br/> + {% pgp_key_link key.pgp_key %}</th> + {% endfor %} + </tr> + </thead> + <tbody> + {% for user in active_users %}{% with user_key=user.userprofile.pgp_key %} + <tr> + <th>{{ user.get_full_name }}</th> + <td>{% pgp_key_link user_key %}</td> + {% spaceless %}{% for key in keys %} + {% signature_exists signatures key.pgp_key user_key as signed %} + <td class="signed-{{ signed|yesno }}">{{ signed|yesno|capfirst }}</td> + {% endfor %}{% endspaceless %} + </tr> + {% endwith %}{% endfor %} + </tbody> + </table> +</div> + +<div class="box"> + <h2 id="visualization">Visualization of PGP Master and Developer Keys</h2> + + <div id="visualize-keys" class="visualize-chart"></div> +</div> + +<div class="box"> + <h2 id="cross-sigs">Developer Cross-Signatures</h2> + + <p>This table lists signatures directly between developer keys.</p> + + <table class="pretty2" id="cross-signatures"> + <thead> + <tr> + <th>Signer</th> + <th>Signee</th> + <th>Created</th> + <th>Expires</th> + </tr> + </thead> + <tbody> + {% for sig in cross_signatures %} + <tr> + <td>{% user_pgp_key_link developer_keys sig.signer %}</td> + <td>{% user_pgp_key_link developer_keys sig.signee %}</td> + <td>{{ sig.created }}</td> + <td>{{ sig.expires|default:"" }}</td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "d3-3.0.6.min.js" %}"></script> +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript" src="{% static "visualize.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $("#key-status").tablesorter({ + sortLocaleCompare: true, + headers: { 1: { sorter: false } } + }); + $("#cross-signatures").tablesorter({ + sortLocaleCompare: true + }); +}); +$(document).ready(function() { + developer_keys("#visualize-keys", "{% url 'pgp-keys-json' %}"); +}); +</script> +{% endblock %} diff --git a/templates/public/svn.html b/templates/public/svn.html deleted file mode 100644 index 1f900c2c..00000000 --- a/templates/public/svn.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "base.html" %} -{% block title %}Arch Linux - SVN{% endblock %} -{% block content %} -<div class="box"> - <h2 class="title">SVN Repositories</h2> - <p> - The PKGBUILD files can be fetched via the ABS utility. To learn more - about ABS, see <a href="http://wiki.archlinux.org/index.php/ABS">the ABS wiki page</a>. - </p> - <p> - You can view the history of all the PKGBUILD files from the Repository - <a href="http://repos.archlinux.org/">WebSVN</a> interface. - </p> - <p> - You can also get individual PKGBUILDs directly from SVN. This can be - especially useful if you need to compile an older version of a package. - <strong>DO NOT CHECK OUT THE ENTIRE SVN REPO</strong>. Your address may be - blocked. Use the following commands to check out a specific package: - </p> - <pre> - svn checkout --depth=empty svn://svn.archlinux.org/packages - cd packages - svn update <your-package-name> - </pre> - For the community repository, use the following commands instead: - <pre> - svn checkout --depth=empty svn://svn.archlinux.org/community - cd community - svn update <your-package-name> - </pre> - <p> - Visit <a href="http://wiki.archlinux.org/index.php?title=Getting_PKGBUILDS_From_SVN">the wiki</a> for more tips on checking out and updating svn PKGBUILDs. - </p> - -</div> -<br /><br /> -{% endblock %} - diff --git a/templates/public/userlist.html b/templates/public/userlist.html index c51215c3..d49a1539 100644 --- a/templates/public/userlist.html +++ b/templates/public/userlist.html @@ -1,20 +1,21 @@ {% extends "base.html" %} +{% load static from staticfiles %} {% load cache %} -{% block title %}Arch Linux - {{ user_type }}{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - {{ group.name }}{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} {% block content %} -{% cache 600 dev-tu-profiles user_type %} +{% cache 600 dev-tu-profiles group.name %} <div id="dev-tu-profiles" class="box"> + <h2>{{BRANDING_DISTRONAME}} {{ group.name }}</h2> - <h2>Arch Linux {{user_type}}</h2> - - <p>{{description}}</p> + <p>{{ group.description }}</p> {% with users as dev_list %} {% include 'public/developer_list.html' %} {% endwith %} - </div> {% endcache %} {% endblock %} diff --git a/templates/registration/login.html b/templates/registration/login.html index ad1ac1ea..ff360de3 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -1,22 +1,29 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Developer Login{% endblock %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Developer Login{% endblock %} {% block content %} <div id="dev-login" class="box"> - <h2>Developer Login</h2> - {% if form.has_errors %} - <p class="login-error">Your username and password didn't match. Please try again.</p> - {% endif %} - <form id="dev-login-form" method="post">{% csrf_token %} <fieldset> - <legend>Enter login credentials</legend> + <legend>Please enter your credentials to login.</legend> {{ form.as_p }} - <p><label></label> <input type="submit" value="Login" /></p> + <p><label></label><input type="submit" value="Login"/></p> </fieldset> </form> - </div> {% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> + modify_attributes({ + '#id_username': {autocorrect: 'off', autocapitalize: 'off'} + }); + $('#id_username').focus(); +</script> +{% endblock %} diff --git a/templates/registration/logout.html b/templates/registration/logout.html index f8e07621..5c296c5d 100644 --- a/templates/registration/logout.html +++ b/templates/registration/logout.html @@ -1,9 +1,12 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Logout successful{% endblock %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Logout successful{% endblock %} {% block content %} <div id="dev-logout" class="box"> - <p>Logout successful.<p> + <h2>Developer Logout</h2> + + <p>Logout was successful. + <a href='{% url 'login' %}'>Click here to login again.</a></p> </div> {% endblock %} - diff --git a/templates/releng/add.html b/templates/releng/add.html new file mode 100644 index 00000000..80afda80 --- /dev/null +++ b/templates/releng/add.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Test Result Entry{% endblock %} + +{% block content %} +<div class="box"> + <h2>{{ BRANDING_SHORTNAME }} Releng Testbuild Feedback Entry</h2> + + <p>This page allows you to submit feedback after testing an {{ BRANDING_SHORTNAME }} installation + using a release engineering testbuild. Mark all the options you used during the + installation; at the end you can specify whether everything went OK. Be + sure to only denote a successful install after having checked the + installation properly. Some options require you to check several things (such as + config files), this will be mentioned alongside the option.</p> + <p>There is also an overview of all feedback on the + <a href="{% url 'releng-test-overview' %}">results page</a>. Once we have + builds that are properly tested (enough successful feedback for all + important features of the ISO or a slightly earlier ISO), we can release new + official media.</p> + + <div id="releng-feedback"> <form action="" method="post">{% csrf_token %} + {{ form.as_p }} + <input type="submit" value="Submit" /> + </form> + </div> +</div> +{% endblock %} diff --git a/templates/releng/iso_overview.html b/templates/releng/iso_overview.html new file mode 100644 index 00000000..1a35ead4 --- /dev/null +++ b/templates/releng/iso_overview.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} +{% load static from staticfiles %} + +{% block content %} +<div class="box"> + <h2>Failures and Successes for Testing ISOs</h2> + + <p>This is an overview showing all current or tested release engineering + produced ISOs. Past but now unavailable ISOs are ommitted if there were + never any testing results submitted. To help improve ISO quality, you are + encouraged to <a href="{% url 'releng-test-submit' %}">give feedback</a> + if you have tested and used any ISOs. Both successful and failed results + are encouraged and welcome.</p> + <p><a href="{% url 'releng-test-overview' %}">Go back to testing results</a></p> + + <table id="releng-result" class="results"> + <thead> + <tr> + <th>ISO</th> + <th>Currently Available</th> + <th># Successes</th> + <th># Failures</th> + </tr> + </thead> + <tbody> + {% for iso in isos %} + <tr> + <td> + <a href="{{ iso.get_absolute_url }}">{{ iso.name }}</a> + </td> + <td>{{ iso.active|yesno|capfirst }}</td> + <td>{{ iso.successes }}</td> + <td>{{ iso.failures }}</td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $(".results:not(:has(tbody tr.empty))").tablesorter({widgets: ['zebra']}); +}); +</script> +{% endblock %} diff --git a/templates/releng/release_detail.html b/templates/releng/release_detail.html new file mode 100644 index 00000000..97017600 --- /dev/null +++ b/templates/releng/release_detail.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Release: {{ release.version }}{% endblock %} + +{% block content %} +<div class="release box"> + <h2>{{ release.version }}</h2> + + <ul> + <li><strong>Release Date:</strong> {{ release.release_date|date }}</li> + {% if release.kernel_version %}<li><strong>Kernel Version:</strong> {{ release.kernel_version }}</li>{% endif %} + <li><strong>Available:</strong> {{ release.available|yesno|capfirst }}</li> + {% if release.torrent_data %} + <li><a href="{% url 'releng-release-torrent' release.version %}" + title="Download torrent for {{ release.version }}"> + Download via Torrent <img width="12" height="12" src="{% static "download.png" %}" alt=""/></a></li> + <li><a href="{{ release.magnet_uri }}" + title="Get magnet link for {{ release.version }}"> + Download via Magnet URI <img width="12" height="12" src="{% static "magnet.png" %}" alt=""/></a></li> + {% endif %} + {% if release.md5_sum %}<li><strong>MD5:</strong> {{ release.md5_sum }}</li>{% endif %} + {% if release.sha1_sum %}<li><strong>SHA1:</strong> {{ release.sha1_sum }}</li>{% endif %} + </ul> + + {% if release.info %} + <h3>Release Notes</h3> + + <div class="article-content">{{ release.info_html }}</div> + {% endif %} + + {% if release.torrent_data %}{% with release.torrent as torrent %} + <h3>Torrent Information</h3> + + <ul> + <li><strong>Comment:</strong> {{ torrent.comment }}</li> + <li><strong>Creation Date:</strong> {{ torrent.creation_date|date:"DATETIME_FORMAT" }} UTC</li> + <li><strong>Created By:</strong> {{ torrent.created_by }}</li> + <li><strong>Announce URL:</strong> {{ torrent.announce }}</li> + <li><strong>File Name:</strong> {{ torrent.file_name }}</li> + <li><strong>File Length:</strong> {{ torrent.file_length|filesizeformat }}</li> + <li><strong>Piece Count:</strong> {{ torrent.piece_count }} pieces</li> + <li><strong>Piece Length:</strong> {{ torrent.piece_length|filesizeformat }}</li> + <li><strong>Info Hash:</strong> {{ torrent.info_hash }}</li> + <li><strong>URL List Length:</strong> {{ torrent.url_list|length }} URLs</li> + </ul> + {% endwith %}{% endif %} +</div> +{% endblock %} diff --git a/templates/releng/release_list.html b/templates/releng/release_list.html new file mode 100644 index 00000000..3f442d07 --- /dev/null +++ b/templates/releng/release_list.html @@ -0,0 +1,70 @@ +{% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Releases{% endblock %} + +{% block head %} +<link rel="alternate" type="application/rss+xml" title="{{BRANDING_DISTRONAME}} News Updates" href="/feeds/releases/" /> +{% endblock %} + +{% block content %} +<div id="release-list" class="box"> + <h2>Releases</h2> + + <p>This is a list of ISO releases made by the Arch Linux release + engineering team. These are typically done on a monthly cadence, containing + the latest kernel and base packages from the package repositories. Click + the version of each release to read any additional notes or details about + each release.</p> + <p>Torrents and magnet URIs are available to download the releases. + Releases listed as not available may still be seeded by peers, but are no + longer registered via the official Arch Linux torrent tracker. We always + recommend running the latest available release.</p> + + <table id="release-table" class="results"> + <thead> + <tr> + <th style="width: 30px;"></th> + <th>Release Date</th> + <th>Version</th> + <th>Kernel Version</th> + <th>Available?</th> + <th>Download Size</th> + </tr> + </thead> + <tbody> + {% for item in release_list %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{% if item.torrent_data %} + <a href="{% url 'releng-release-torrent' item.version %}" + title="Download torrent for {{ item.version }}"><img width="12" height="12" src="{% static "download.png" %}" alt="Torrent"/></a> + + <a href="{{ item.magnet_uri }}" + title="Get magnet link for {{ item.version }}"><img width="12" height="12" src="{% static "magnet.png" %}" alt="Magnet"/></a> + {% endif %}</td> + <td>{{ item.release_date|date }}</td> + <td><a href="{{ item.get_absolute_url }}" title="Release details for {{ item.version }}">{{ item.version }}</a></td> + <td>{{ item.kernel_version|default:"" }}</td> + <td class="available-{{ item.available|yesno }}">{{ item.available|yesno|capfirst }}</td> + <td>{% if item.torrent_data %}{{ item.torrent.file_length|filesizeformat }}{% endif %}</td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $(".results").tablesorter({ + widgets: ['zebra'], + sortList: [[0,1], [1,1]], + headers: { 0: { sorter: false } } + }); +}); +</script> +{% endblock %} diff --git a/templates/releng/result_list.html b/templates/releng/result_list.html new file mode 100644 index 00000000..281df083 --- /dev/null +++ b/templates/releng/result_list.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% load static from staticfiles %} + +{% block content %} +<div class="box"> + <h2>Results for: + {% if option %}{{ option.verbose_name|title }}: {{ value }}{% endif %} + {% if iso_name %}{{ iso_name|default:"" }}{% endif %} + </h2> + + <p><a href="{% url 'releng-test-overview' %}">Go back to testing results</a></p> + + <table id="releng-result" class="results"> + <thead> + <tr> + <th>ISO</th> + <th>Submitted By</th> + <th>Date Submitted</th> + <th>Architecture</th> + <th>Success</th> + </tr> + </thead> + <tbody> + {% for test in test_list %} + <tr> + <td>{{ test.iso.name }}</td> + <td>{{ test.user_name }}</td> + <td>{{ test.created|date }}</td> + <td>{{ test.architecture }}</td> + <td><span class="success-{{ test.success|yesno }}">{{ test.success|yesno|capfirst }}</span></td> + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $(".results:not(:has(tbody tr.empty))").tablesorter({widgets: ['zebra']}); +}); +</script> +{% endblock %} diff --git a/templates/releng/result_section.html b/templates/releng/result_section.html new file mode 100644 index 00000000..5e0b6f62 --- /dev/null +++ b/templates/releng/result_section.html @@ -0,0 +1,28 @@ +<tr> + <th>{% if option.is_rollback %}Rollback: {% endif %}{{ option.name|title }}</th> + <th>Last Success</th> + <th>Last Failure</th> +</tr> +{% for item in option.values %} +<tr> + <td> + <a href="{% url 'releng-results-for' option.field_name item.value.pk %}"> + {{ item.value.name|lower }} + </a> + </td> + <td> + {% if item.success %} + <a href="{% url 'releng-results-iso' item.success.pk %}"> + {{ item.success.name }} + </a> + {% else %}Never succeeded{% endif %} + </td> + <td> + {% if item.failure %} + <a href="{% url 'releng-results-iso' item.failure.pk %}"> + {{ item.failure.name }} + </a> + {% else %}Never failed{% endif %} + </td> +</tr> +{% endfor %} diff --git a/templates/releng/results.html b/templates/releng/results.html new file mode 100644 index 00000000..71a31fef --- /dev/null +++ b/templates/releng/results.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} +{% load wiki %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Release Engineering Testbuild Results{% endblock %} + +{% block content %} +<div class="box"> + <h2>Release Engineering Testbuild Results</h2> + + <p>This is an overview showing a test results matrix of release + engineering produced ISOs. Various options and configurations are shown + with last success and last failure results, if known. To help improve ISO + quality, you are encouraged to <a href="{% url 'releng-test-submit' %}">give feedback</a> + if you have tested and used any ISOs. Both successful and failed results + are encouraged and welcome.</p> + + <p>For a overview of which ISOs tested best, have a look at + the <a href="{% url 'releng-iso-overview' %}">overview</a>.</p> + + <p>For more information, see the <a + href="{% wiki_url 'DeveloperWiki:releng_testimages_feedback' %}">documentation + on the wiki</a>.</p> + + <p>All ISOs referenced on this page are available from + <a href="{{ iso_url }}">{{ iso_url }}</a>.</p> + + <table> + {% for option in options %} + {% include "releng/result_section.html" %} + {% endfor %} + </table> +</div> +{% endblock %} diff --git a/templates/releng/thanks.html b/templates/releng/thanks.html new file mode 100644 index 00000000..b772fad3 --- /dev/null +++ b/templates/releng/thanks.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Feedback - Thanks!{% endblock %} + +{% block content %} +<div class="box"> + <h2>Thanks!</h2> + <p>Thank you for taking the time to give us this information! + Your results have been succesfully added to our database.</p> + <p>You can now <a href="{% url 'releng-test-overview' %}">go back to the results</a>, + <a href="{% url 'releng-test-submit' %}">give more feedback</a>, or + have a look at the <a href="{% url 'releng-iso-overview' %}">look at + the ISO test overview</a>.</p> +</div> +{% endblock %} diff --git a/templates/sitemaps/news_sitemap.xml.jinja b/templates/sitemaps/news_sitemap.xml.jinja new file mode 100644 index 00000000..97dd17b5 --- /dev/null +++ b/templates/sitemaps/news_sitemap.xml.jinja @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"> +{% for url in urlset %}<url> +<loc>{{ url.location }}</loc> +{% if url.lastmod %}<lastmod>{{ url.lastmod|date("Y-m-d") }}</lastmod>{% endif %} +{% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %} +{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %} +<news:news> + <news:publication><news:name>Arch Linux News</news:name><news:language>en</news:language></news:publication> + {% if url.item.postdate %}<news:publication_date>{{ url.item.postdate|date("c") }}</news:publication_date>{% endif %} + {% if url.item.title %}<news:title>{{ url.item.title }}</news:title>{% endif %} +</news:news> +</url>{% endfor %} +</urlset> diff --git a/templates/sitemaps/sitemap.xml.jinja b/templates/sitemaps/sitemap.xml.jinja new file mode 100644 index 00000000..0808a7de --- /dev/null +++ b/templates/sitemaps/sitemap.xml.jinja @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> +{% for url in urlset %}<url> +<loc>{{ url.location }}</loc> +{% if url.lastmod %}<lastmod>{{ url.lastmod|date("Y-m-d") }}</lastmod>{% endif %} +{% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %} +{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %} +</url>{% endfor %} +</urlset> diff --git a/templates/todolists/email_notification.txt b/templates/todolists/email_notification.txt index abe1dbf3..e454ec79 100644 --- a/templates/todolists/email_notification.txt +++ b/templates/todolists/email_notification.txt @@ -1,15 +1,11 @@ -{% autoescape off %}* Note: this is an automated message +{% autoescape off %}The todo list "{{ todolist.name }}" has had the following packages added to it for which you are a maintainer: -The following package: +{% for tpkg in todo_packages %} +* {{ tpkg.repo.name|lower }}/{{ tpkg.pkgname }} ({{ tpkg.arch.name }}) - {{ tpkg.pkg.get_full_url }}{% endfor %} - Package Name: {{ pkg.pkgname }} - Architecture: {{ pkg.arch.name }} - Repository: {{ pkg.repo.name }} - ({{ weburl }}) - -has been added to this todo list: - -Creator: {{todolist.creator.get_full_name}} -Name: {{todolist.name}} +Todo list information: +Name: {{ todolist.name }} +URL: {{ todolist.get_full_url }} +Creator: {{ todolist.creator.get_full_name }} Description: -{{todolist.description|striptags|wordwrap:69}}{% endautoescape %} +{{ todolist.description|striptags|wordwrap:78 }}{% endautoescape %} diff --git a/templates/todolists/list.html b/templates/todolists/list.html index 2e75bdac..5cfd6a02 100644 --- a/templates/todolists/list.html +++ b/templates/todolists/list.html @@ -1,17 +1,25 @@ {% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} -{% block title %}Arch Linux - Todo Lists{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Todo Lists{% endblock %} {% block content %} <div id="dev-todo" class="box"> <h2>Package Todo Lists</h2> - {% if perms.main.add_todolist %} - <ul class="admin-actions"> + {% if perms.todolists.add_todolist %}<ul class="admin-actions"> <li><a href="/todo/add/" title="Add new todo list">Add Todo List</a></li> - </ul> - {% endif %} + </ul>{% endif %} + + <p>Todo lists are used by the developers when a rebuild of a set of + packages is needed. This is common when a library has a version bump, + during a toolchain rebuild, or a general cleanup of packages in the + repositories. The progress can be tracked here, and completed todo lists + can be browsed as well.</p> + + {% include "todolists/paginator.html" %} <table id="dev-todo-lists" class="results todo-table"> <thead> @@ -30,9 +38,9 @@ <tr class="{% cycle 'odd' 'even' %}"> <td><a href="{{ list.get_absolute_url }}" title="View todo list: {{ list.name }}">{{ list.name }}</a></td> - <td>{{ list.date_added }}</td> + <td>{{ list.created|date }}</td> <td>{{ list.creator.get_full_name }}</td> - <td class="wrap">{{ list.description|safe }}</td> + <td class="wrap">{{ list.description|urlize }}</td> <td>{{ list.pkg_count }}</td> <td>{{ list.incomplete_count }}</td> <td>{% ifequal list.incomplete_count 0 %}<span class="complete">Complete</span> @@ -41,14 +49,19 @@ {% endfor %} </tbody> </table> + + {% include "todolists/paginator.html" %} </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> <script type="text/javascript"> $(document).ready(function() { // I'm not sure why it didn't autodetect digit, but it has to be explicit // http://stackoverflow.com/questions/302749/jquery-tablesorter-problem - $(".results").tablesorter({widgets: ['zebra'], sortList: [[1,1]], + $(".results").tablesorter({widgets: ['zebra'], sortList: [[6, 1], [1, 1]], headers: { 4: { sorter: 'digit' }, 5: { sorter: 'digit' } } }); }); </script> diff --git a/templates/todolists/paginator.html b/templates/todolists/paginator.html new file mode 100644 index 00000000..3b077419 --- /dev/null +++ b/templates/todolists/paginator.html @@ -0,0 +1,22 @@ +{% if is_paginated %} +<div class="pagination"> + <p>{{ paginator.count }} todo lists, viewing page {{ page_obj.number }} of {{ paginator.num_pages }}.</p> + <p class="todolist-nav"> + {% if page_obj.has_previous %} + <a class="prev" href="?page={{ page_obj.previous_page_number }}" + title="Go to previous page">< Prev</a> + {% endif %} + {% for num in paginator.page_range %} + {% ifequal num page_obj.number %} + <span>{{ num }}</span> + {% else %} + <a href="?page={{ num }}" title="Go to page {{ num }}">{{ num }}</a> + {% endifequal %} + {% endfor %} + {% if page_obj.has_next %} + <a class="next" href="?page={{ page_obj.next_page_number }}" + title="Go to next page">Next ></a> + {% endif %} + </p> +</div> +{% endif %} diff --git a/templates/todolists/public_list.html b/templates/todolists/public_list.html deleted file mode 100644 index fe5ffb5d..00000000 --- a/templates/todolists/public_list.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Arch Linux - Todo Lists{% endblock %} - -{% block content %} -<div class="box"> - <h2>Developer Todo Lists</h2> - <div id="public_todo_lists"> - {% for list in todo_lists %} - <h4>{{list.name}}</h4> - <div class="todo_list"> - <p>{{list.description|safe|linebreaks}}</p> - <table "todo-pkglist-{{ list.id }}" class="results todo-table"> - <thead> - <tr> - <th>Name</th> - <th>Arch</th> - <th>Repo</th> - <th>Maintainer</th> - <th>Status</th> - </tr> - </thead> - <tbody> - {% for pkg in list.packages %} - <tr class="{% cycle 'odd' 'even' %}"> - <td><a href="{{ pkg.pkg.get_absolute_url }}" - title="View package details for {{ pkg.pkg.pkgname }}">{{ pkg.pkg.pkgname }}</a></td> - <td>{{ pkg.pkg.arch.name }}</td> - <td>{{ pkg.pkg.repo.name|capfirst }}</td> - <td>{{ pkg.pkg.maintainers|join:', ' }}</td> - <td> - {% if pkg.complete %} - <span class="complete">Complete</a> - {% else %} - <span class="incomplete">Incomplete</a> - {% endif %} - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - {% endfor %} - </div> -</div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> -<script type="text/javascript"> -$(document).ready(function() { - $(".results").tablesorter({widgets: ['zebra'], sortList: [[0,0], [1,0]]}); -}); - -</script> -{% endblock %} diff --git a/templates/todolists/todolist_confirm_delete.html b/templates/todolists/todolist_confirm_delete.html index 5545462f..6d7ec0ab 100644 --- a/templates/todolists/todolist_confirm_delete.html +++ b/templates/todolists/todolist_confirm_delete.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Delete Todo List: {{object.name}}{% endblock %} +{% block title %}{{ BRANDING_DISTRONAME }} - Delete Todo List: {{object.name}}{% endblock %} {% block content %} <div id="dev-todo-delete" class="box"> diff --git a/templates/todolists/view.html b/templates/todolists/view.html index 504c8cbb..4ae25fb0 100644 --- a/templates/todolists/view.html +++ b/templates/todolists/view.html @@ -1,5 +1,10 @@ {% extends "base.html" %} -{% block title %}Arch Linux - Todo: {{ list.name }}{% endblock %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load package_extras %} +{% load todolists %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Todo: {{ list.name }}{% endblock %} {% block content %} <div id="dev-todo-details" class="box"> @@ -7,82 +12,126 @@ <h2>Todo List: {{ list.name }}</h2> <ul class="admin-actions"> - {% if perms.main.delete_todolist %} - <li><a href="/todo/delete/{{list.id}}/" + {% if perms.todolists.delete_todolist %} + <li><a href="/todo/{{ list.slug }}/delete/" title="Delete this todo list">Delete Todo List</a></li> {% endif %} - {% if perms.main.change_todolist %} - <li><a href="/todo/edit/{{list.id}}/" + {% if perms.todolists.change_todolist %} + <li><a href="/todo/{{ list.slug }}/edit/" title="Edit this todo list">Edit Todo List</a></li> {% endif %} </ul> - <p>{{list.description|safe|linebreaks}}</p> + <div class="todo-info">{{ list.created|date }} - {{ list.creator.get_full_name }}</div> + + <div class="todo-description"> + {{list.stripped_description|default:'(no description)'|urlize|linebreaks}} + </div> + + <div class="todo-pkgbases"> + <p>Link to lists of pkgbase values:</p> + <ul>{% for svn_root in svn_roots %} + <li><a href="pkgbases/{{ svn_root }}/">{{ svn_root }}</a></li> + {% endfor %}</ul> + </div> + + <div class="box filter-criteria"> + <h3>Filter Todo List Packages</h3> + <form id="todolist_filter" method="post" action="."> + <fieldset> + <legend>Select filter criteria</legend> + {% for arch in arches %} + <div><label for="id_arch_{{ arch.name }}" title="Architecture {{ arch.name }}">Arch {{ arch.name }}</label> + <input type="checkbox" name="arch_{{ arch.name }}" id="id_arch_{{ arch.name }}" class="arch_filter" value="{{ arch.name }}" checked="checked"/></div> + {% endfor %} + {% for repo in repos %} + <div><label for="id_repo_{{ repo.name|lower }}" title="Target Repository {{ repo.name }}">[{{ repo.name|lower }}]</label> + <input type="checkbox" name="repo_{{ repo.name|lower }}" id="id_repo_{{ repo.name|lower }}" class="repo_filter" value="{{ repo.name|lower }}" checked="checked"/></div> + {% endfor %} + {% if user.is_authenticated %} + <div><label for="id_mine_only" title="Show only packages maintained by me">Only Mine</label> + <input type="checkbox" name="mine_only" id="id_mine_only" value="mine_only"/></div> + {% endif %} + <div><label for="id_incomplete" title="Packages not yet completed">Only Incomplete</label> + <input type="checkbox" name="incomplete" id="id_incomplete" value="incomplete"/></div> + <div ><label> </label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div> + <div class="clear"></div> + <div id="filter-info"> + <span id="filter-count">{{ list.packages|length }}</span> packages displayed out of + {{ list.packages|length }} total package{{ list.packages|pluralize }}. + </div> + </fieldset> + </form> + </div> <table id="dev-todo-pkglist" class="results todo-table"> <thead> <tr> - <th>Name</th> <th>Arch</th> - <th>Repo</th> - <th>Maintainer</th> + <th>Repository</th> + <th>Name</th> + <th>Current Version</th> + <th>Staging Version</th> + <th>Maintainers</th> <th>Status</th> + <th>Last Touched By</th> </tr> </thead> <tbody> {% for pkg in list.packages %} - <tr class="{% cycle 'odd' 'even' %}"> - <td><a href="{{ pkg.pkg.get_absolute_url }}" - title="View package details for {{ pkg.pkg.pkgname }}">{{ pkg.pkg.pkgname }}</a></td> - <td>{{ pkg.pkg.arch.name }}</td> - <td>{{ pkg.pkg.repo.name|capfirst }}</td> - <td>{{ pkg.pkg.maintainers|join:', ' }}</td> + <tr class="{% cycle 'odd' 'even' %}{% if user in pkg.maintainers %} mine{% endif %} {{ pkg.arch.name }} {{ pkg.repo.name|lower }}"> + <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.repo.name|capfirst }}</td> + <td>{% todopkg_details_link pkg %}</td> + {% if pkg.pkg.flag_date %} + <td><span class="flagged">{{ pkg.pkg.full_version }}</span></td> + {% elif pkg.pkg %} + <td>{{ pkg.pkg.full_version }}</td> + {% else %} + <td></td> + {% endif %} + {% with staging=pkg.staging %} + <td>{% if staging %}{% pkg_details_link staging staging.full_version %}{% endif %}</td> + {% endwith %} + <td>{{ pkg.maintainers|join:', ' }}</td> <td> - {% if pkg.complete %} - <a href="/todo/flag/{{ list.id }}/{{ pkg.id }}/" - class="complete" title="Toggle completion status">Complete</a> + {% if perms.todolists.change_todolistpackage %} + <a href="/todo/{{ list.slug }}/flag/{{ pkg.id }}/" + class="status-link {{ pkg.status_css_class }}" title="Toggle completion status">{{ pkg.get_status_display }}</a> {% else %} - <a href="/todo/flag/{{ list.id }}/{{ pkg.id }}/" - class="incomplete" title="Toggle completion status">Incomplete</a> + <span class="{{ pkg.status_css_class }}">{{ pkg.get_status_display }}</span> {% endif %} </td> + <td>{{ pkg.user|default:"" }}</td> </tr> {% endfor %} </tbody> </table> </div> -{% load cdn %}{% jquery %} -<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> -<script type="text/javascript"> - $(function() { - $('a[href*=todo/flag]').click(function() { - var link = this; - - $.getJSON(link.href, function(data) { - if (data.complete) { - $(link).text('Complete').addClass('complete').removeClass('incomplete'); - } else { - $(link).text('Incomplete').addClass('incomplete').removeClass('complete'); - } - }); +{% endblock %} - return false; - }); - }); -$.tablesorter.addParser({ - id: 'todostatus', - is: function(s) { return false; }, - format: function(s) { - return s.match(/incomplete/) ? 1 : 0; - }, - type: 'numeric' -}); +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> $(document).ready(function() { $(".results").tablesorter({ widgets: ['zebra'], - sortList: [[0,0], [1,0]], - headers: { 4: { sorter: 'todostatus' } } + sortList: [[2,0], [0,0]], + headers: { 6: { sorter: 'todostatus' } } }); }); +$(document).ready(function() { + $('a.status-link').click(todolist_flag); + var filter_func = function() { + filter_pkgs_list('#todolist_filter', '#dev-todo-pkglist tbody'); + filter_todolist_save({{ list.id }}); + }; + $('#todolist_filter input').change(filter_func); + $('#criteria_reset').click(function() { filter_pkgs_reset(filter_func); }); + // fire function on page load to ensure the current form selections take effect + filter_todolist_load({{ list.id }}); + filter_func(); +}); </script> {% endblock %} diff --git a/templates/visualize/index.html b/templates/visualize/index.html new file mode 100644 index 00000000..e091c761 --- /dev/null +++ b/templates/visualize/index.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} +{% load static from staticfiles %} + +{% block title %}{{ BRANDING_DISTRONAME }} - Visualizations{% endblock %} + +{% block content %} +<div class="box"> + <h2>Visualization of Package Data</h2> + + <div class="visualize-buttons"> + <div> + <span>Scale Using:</span> + <button id="visualize-archrepo-count" class="visualize-archrepo-scaleby active">Package Count</button> + <button id="visualize-archrepo-flagged" class="visualize-archrepo-scaleby">Flagged</button> + <button id="visualize-archrepo-csize" class="visualize-archrepo-scaleby">Compressed Size</button> + <button id="visualize-archrepo-isize" class="visualize-archrepo-scaleby">Installed Size</button> + </div> + <div> + <span>Group By:</span> + <button id="visualize-archrepo-repo" class="visualize-archrepo-groupby active">Repository</button> + <button id="visualize-archrepo-arch" class="visualize-archrepo-groupby">Architecture</button> + </div> + </div> + <div id="visualize-archrepo" class="visualize-chart"></div> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %} +<script type="text/javascript" src="{% static "d3-3.0.6.min.js" %}"></script> +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript" src="{% static "visualize.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + var orderings = { + "repo": { url: "{% url 'visualize-byrepo' %}", color_attr: "repo" }, + "arch": { url: "{% url 'visualize-byarch' %}", color_attr: "arch" }, + }; + packages_treemap("#visualize-archrepo", orderings, "repo"); +}); +</script> +{% endblock %} diff --git a/todolists/admin.py b/todolists/admin.py new file mode 100644 index 00000000..246a8bca --- /dev/null +++ b/todolists/admin.py @@ -0,0 +1,15 @@ +from django.contrib import admin + +from .models import Todolist + + +class TodolistAdmin(admin.ModelAdmin): + list_display = ('name', 'creator', 'created', 'description') + list_filter = ('created', 'creator') + search_fields = ('name', 'description') + date_hierarchy = 'created' + + +admin.site.register(Todolist, TodolistAdmin) + +# vim: set ts=4 sw=4 et: diff --git a/todolists/migrations/0001_initial.py b/todolists/migrations/0001_initial.py new file mode 100644 index 00000000..4ffbf838 --- /dev/null +++ b/todolists/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Todolist', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('slug', models.SlugField(unique=True, max_length=255)), + ('old_id', models.IntegerField(unique=True, null=True)), + ('name', models.CharField(max_length=255)), + ('description', models.TextField()), + ('created', models.DateTimeField(db_index=True)), + ('last_modified', models.DateTimeField(editable=False)), + ('raw', models.TextField(blank=True)), + ('creator', models.ForeignKey(related_name=b'created_todolists', on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='TodolistPackage', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pkgname', models.CharField(max_length=255)), + ('pkgbase', models.CharField(max_length=255)), + ('created', models.DateTimeField(editable=False)), + ('last_modified', models.DateTimeField(editable=False)), + ('removed', models.DateTimeField(null=True, blank=True)), + ('status', models.SmallIntegerField(default=0, choices=[(0, b'Incomplete'), (1, b'Complete'), (2, b'In-progress')])), + ('comments', models.TextField(null=True, blank=True)), + ('arch', models.ForeignKey(to='main.Arch')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='main.Package', null=True)), + ('repo', models.ForeignKey(to='main.Repo')), + ('todolist', models.ForeignKey(to='todolists.Todolist')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), + ], + options={ + 'get_latest_by': 'created', + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='todolistpackage', + unique_together=set([('todolist', 'pkgname', 'arch')]), + ), + ] diff --git a/todolists/migrations/__init__.py b/todolists/migrations/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/todolists/migrations/__init__.py diff --git a/todolists/models.py b/todolists/models.py new file mode 100644 index 00000000..92ca5839 --- /dev/null +++ b/todolists/models.py @@ -0,0 +1,99 @@ +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.db import models +from django.db.models import Q +from django.db.models.signals import pre_save + +from main.models import Arch, Repo, Package +from main.utils import set_created_field + + +class TodolistManager(models.Manager): + def incomplete(self): + not_done = ((Q(todolistpackage__status=TodolistPackage.INCOMPLETE) | + Q(todolistpackage__status=TodolistPackage.IN_PROGRESS)) & + Q(todolistpackage__removed__isnull=True)) + return self.order_by().filter(not_done).distinct() + + +class Todolist(models.Model): + slug = models.SlugField(max_length=255, unique=True) + old_id = models.IntegerField(null=True, unique=True) + name = models.CharField(max_length=255) + description = models.TextField() + creator = models.ForeignKey(User, on_delete=models.PROTECT, + related_name="created_todolists") + created = models.DateTimeField(db_index=True) + last_modified = models.DateTimeField(editable=False) + raw = models.TextField(blank=True) + + objects = TodolistManager() + + class Meta: + get_latest_by = 'created' + + def __unicode__(self): + return self.name + + @property + def stripped_description(self): + return self.description.strip() + + def get_absolute_url(self): + return '/todo/%s/' % self.slug + + def get_full_url(self, proto='https'): + '''get a URL suitable for things like email including the domain''' + domain = Site.objects.get_current().domain + return '%s://%s%s' % (proto, domain, self.get_absolute_url()) + + def packages(self): + if not hasattr(self, '_packages'): + self._packages = self.todolistpackage_set.filter( + removed__isnull=True).select_related( + 'pkg', 'repo', 'arch', 'user__username').order_by( + 'pkgname', 'arch') + return self._packages + + +class TodolistPackage(models.Model): + INCOMPLETE = 0 + COMPLETE = 1 + IN_PROGRESS = 2 + STATUS_CHOICES = ( + (INCOMPLETE, 'Incomplete'), + (COMPLETE, 'Complete'), + (IN_PROGRESS, 'In-progress'), + ) + + todolist = models.ForeignKey(Todolist) + pkg = models.ForeignKey(Package, null=True, on_delete=models.SET_NULL) + pkgname = models.CharField(max_length=255) + pkgbase = models.CharField(max_length=255) + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) + created = models.DateTimeField(editable=False) + last_modified = models.DateTimeField(editable=False) + removed = models.DateTimeField(null=True, blank=True) + status = models.SmallIntegerField(default=INCOMPLETE, + choices=STATUS_CHOICES) + user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) + comments = models.TextField(null=True, blank=True) + + class Meta: + unique_together = (('todolist', 'pkgname', 'arch'),) + get_latest_by = 'created' + + def __unicode__(self): + return self.pkgname + + def status_css_class(self): + return self.get_status_display().lower().replace('-', '') + + +pre_save.connect(set_created_field, sender=Todolist, + dispatch_uid="todolists.models") +pre_save.connect(set_created_field, sender=TodolistPackage, + dispatch_uid="todolists.models") + +# vim: set ts=4 sw=4 et: diff --git a/todolists/templatetags/__init__.py b/todolists/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/todolists/templatetags/__init__.py diff --git a/todolists/templatetags/todolists.py b/todolists/templatetags/todolists.py new file mode 100644 index 00000000..5f31dc1f --- /dev/null +++ b/todolists/templatetags/todolists.py @@ -0,0 +1,19 @@ +from django import template + +register = template.Library() + + +def pkg_absolute_url(repo, arch, pkgname): + return '/packages/%s/%s/%s/' % (repo.name.lower(), arch.name, pkgname) + + +@register.simple_tag +def todopkg_details_link(todopkg): + pkg = todopkg.pkg + if not pkg: + return todopkg.pkgname + link = '<a href="%s" title="View package details for %s">%s</a>' + url = pkg_absolute_url(todopkg.repo, todopkg.arch, pkg.pkgname) + return link % (url, pkg.pkgname, pkg.pkgname) + +# vim: set ts=4 sw=4 et: diff --git a/todolists/urls.py b/todolists/urls.py new file mode 100644 index 00000000..ed065f50 --- /dev/null +++ b/todolists/urls.py @@ -0,0 +1,26 @@ +from django.conf.urls import patterns +from django.contrib.auth.decorators import permission_required + +from .views import (view_redirect, view, add, edit, flag, + list_pkgbases, DeleteTodolist, TodolistListView) + +urlpatterns = patterns('', + (r'^$', TodolistListView.as_view(), {}, 'todolist-list'), + + # old todolists URLs, permanent redirect view so we don't break all links + (r'^(?P<old_id>\d+)/$', view_redirect), + + (r'^add/$', + permission_required('todolists.add_todolist')(add)), + (r'^(?P<slug>[-\w]+)/$', view), + (r'^(?P<slug>[-\w]+)/edit/$', + permission_required('todolists.change_todolist')(edit)), + (r'^(?P<slug>[-\w]+)/delete/$', + permission_required('todolists.delete_todolist')(DeleteTodolist.as_view())), + (r'^(?P<slug>[-\w]+)/flag/(?P<pkg_id>\d+)/$', + permission_required('todolists.change_todolistpackage')(flag)), + (r'^(?P<slug>[-\w]+)/pkgbases/(?P<svn_root>[a-z]+)/$', + list_pkgbases), +) + +# vim: set ts=4 sw=4 et: diff --git a/todolists/utils.py b/todolists/utils.py new file mode 100644 index 00000000..e04c2e5e --- /dev/null +++ b/todolists/utils.py @@ -0,0 +1,57 @@ +from django.db import connections, router + +from .models import Todolist, TodolistPackage +from packages.models import Package + + +def todo_counts(): + sql = """ +SELECT todolist_id, count(*), SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) + FROM todolists_todolistpackage + WHERE removed IS NULL + GROUP BY todolist_id + """ + database = router.db_for_write(TodolistPackage) + connection = connections[database] + cursor = connection.cursor() + cursor.execute(sql, [TodolistPackage.COMPLETE]) + results = cursor.fetchall() + return {row[0]: (row[1], row[2]) for row in results} + + +def get_annotated_todolists(incomplete_only=False): + lists = Todolist.objects.all().defer('raw').select_related( + 'creator').order_by('-created') + lookup = todo_counts() + + # tag each list with package counts + for todolist in lists: + counts = lookup.get(todolist.id, (0, 0)) + todolist.pkg_count = counts[0] + todolist.complete_count = counts[1] + todolist.incomplete_count = counts[0] - counts[1] + + if incomplete_only: + lists = [l for l in lists if l.incomplete_count > 0] + + return lists + + +def attach_staging(packages, list_id): + '''Look for any staging version of the packages provided and attach them + to the 'staging' attribute on each package if found.''' + pkgnames = TodolistPackage.objects.filter( + todolist_id=list_id).values('pkgname') + staging_pkgs = Package.objects.normal().filter(repo__staging=True, + pkgname__in=pkgnames) + # now build a lookup dict to attach to the correct package + lookup = {(p.pkgname, p.arch): p for p in staging_pkgs} + + annotated = [] + for package in packages: + in_staging = lookup.get((package.pkgname, package.arch), None) + package.staging = in_staging + + return annotated + +# vim: set ts=4 sw=4 et: diff --git a/todolists/views.py b/todolists/views.py index 25186243..a0b56e25 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -1,169 +1,240 @@ -from django import forms +import json +from operator import attrgetter +from django import forms from django.http import HttpResponse +from django.conf import settings from django.core.mail import send_mail -from django.shortcuts import get_object_or_404, redirect -from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import Count +from django.shortcuts import (get_list_or_404, get_object_or_404, + redirect, render) +from django.db import transaction from django.views.decorators.cache import never_cache -from django.views.generic.create_update import delete_object -from django.views.generic.simple import direct_to_template +from django.views.generic import DeleteView, ListView from django.template import Context, loader -from django.utils import simplejson +from django.utils.timezone import now -from main.models import Todolist, TodolistPkg, Package +from main.models import Package, Repo +from main.utils import find_unique_slug +from packages.utils import attach_maintainers +from .models import Todolist, TodolistPackage +from .utils import get_annotated_todolists, attach_staging -class TodoListForm(forms.Form): - name = forms.CharField(max_length=255, - widget=forms.TextInput(attrs={'size': '30'})) - description = forms.CharField(required=False, - widget=forms.Textarea(attrs={'rows': '4', 'cols': '60'})) - packages = forms.CharField(required=False, + +class TodoListForm(forms.ModelForm): + raw = forms.CharField(label='Packages', required=False, help_text='(one per line)', widget=forms.Textarea(attrs={'rows': '20', 'cols': '60'})) - def clean_packages(self): - package_names = [s.strip() for s in - self.cleaned_data['packages'].split("\n")] - package_names = set(package_names) - packages = Package.objects.filter( - pkgname__in=package_names).exclude( - repo__testing=True).order_by('arch') - return packages + def package_names(self): + return {s.strip() for s in self.cleaned_data['raw'].split("\n")} + + def packages(self): + return Package.objects.normal().filter( + pkgname__in=self.package_names(), + repo__testing=False, repo__staging=False).order_by('arch') + + class Meta: + model = Todolist + fields = ('name', 'description', 'raw') -@login_required @never_cache -def flag(request, listid, pkgid): - list = get_object_or_404(Todolist, id=listid) - pkg = get_object_or_404(TodolistPkg, id=pkgid) - pkg.complete = not pkg.complete - pkg.save() +def flag(request, slug, pkg_id): + todolist = get_object_or_404(Todolist, slug=slug) + tlpkg = get_object_or_404(TodolistPackage, id=pkg_id, removed__isnull=True) + # TODO: none of this; require absolute value on submit + if tlpkg.status == TodolistPackage.INCOMPLETE: + tlpkg.status = TodolistPackage.COMPLETE + else: + tlpkg.status = TodolistPackage.INCOMPLETE + tlpkg.user = request.user + tlpkg.save(update_fields=('status', 'user', 'last_modified')) if request.is_ajax(): - return HttpResponse( - simplejson.dumps({'complete': pkg.complete}), - mimetype='application/json') - return redirect(list) + data = { + 'status': tlpkg.get_status_display(), + 'css_class': tlpkg.status_css_class(), + } + return HttpResponse(json.dumps(data), content_type='application/json') + return redirect(todolist) + + +def view_redirect(request, old_id): + todolist = get_object_or_404(Todolist, old_id=old_id) + return redirect(todolist, permanent=True) + + +def view(request, slug): + todolist = get_object_or_404(Todolist, slug=slug) + svn_roots = Repo.objects.values_list( + 'svn_root', flat=True).order_by().distinct() + # we don't hold onto the result, but the objects are the same here, + # so accessing maintainers in the template is now cheap + attach_maintainers(todolist.packages()) + attach_staging(todolist.packages(), todolist.pk) + arches = {tp.arch for tp in todolist.packages()} + repos = {tp.repo for tp in todolist.packages()} + context = { + 'list': todolist, + 'svn_roots': svn_roots, + 'arches': sorted(arches), + 'repos': sorted(repos), + } + return render(request, 'todolists/view.html', context) + + +def list_pkgbases(request, slug, svn_root): + '''Used to make bulk moves of packages a lot easier.''' + todolist = get_object_or_404(Todolist, slug=slug) + repos = get_list_or_404(Repo, svn_root=svn_root) + pkgbases = TodolistPackage.objects.values_list( + 'pkgbase', flat=True).filter( + todolist=todolist, repo__in=repos, removed__isnull=True).order_by( + 'pkgbase').distinct() + return HttpResponse('\n'.join(pkgbases), content_type='text/plain') + + +class TodolistListView(ListView): + context_object_name = "lists" + template_name = "todolists/list.html" + paginate_by = 50 + + def get_queryset(self): + return get_annotated_todolists() -@login_required -@never_cache -def view(request, listid): - list = get_object_or_404(Todolist, id=listid) - return direct_to_template(request, 'todolists/view.html', {'list': list}) -@login_required -@never_cache -def list(request): - lists = Todolist.objects.select_related('creator').annotate( - pkg_count=Count('todolistpkg')).order_by('-date_added') - incomplete = Todolist.objects.filter(todolistpkg__complete=False).annotate( - Count('todolistpkg')).values_list('id', 'todolistpkg__count') - - # tag each list with an incomplete package count - lookup = {} - for k, v in incomplete: - lookup[k] = v - for l in lists: - l.incomplete_count = lookup.get(l.id, 0) - - return direct_to_template(request, 'todolists/list.html', {'lists': lists}) - -@permission_required('main.add_todolist') @never_cache def add(request): if request.POST: form = TodoListForm(request.POST) if form.is_valid(): - todo = Todolist.objects.create( - creator = request.user, - name = form.cleaned_data['name'], - description = form.cleaned_data['description']) - - for pkg in form.cleaned_data['packages']: - tpkg = TodolistPkg.objects.create(list = todo, pkg = pkg) - send_todolist_email(tpkg) - - return redirect('/todo/') + new_packages = create_todolist_packages(form, creator=request.user) + send_todolist_emails(form.instance, new_packages) + return redirect(form.instance) else: form = TodoListForm() page_dict = { 'title': 'Add Todo List', + 'description': '', 'form': form, 'submit_text': 'Create List' - } - return direct_to_template(request, 'general_form.html', page_dict) + } + return render(request, 'general_form.html', page_dict) -@permission_required('main.change_todolist') + +# TODO: this calls for transaction management and async emailing @never_cache -def edit(request, list_id): - todo_list = get_object_or_404(Todolist, id=list_id) +def edit(request, slug): + todo_list = get_object_or_404(Todolist, slug=slug) if request.POST: - form = TodoListForm(request.POST) + form = TodoListForm(request.POST, instance=todo_list) if form.is_valid(): - todo_list.name = form.cleaned_data['name'] - todo_list.description = form.cleaned_data['description'] - todo_list.save() - - packages = [p.pkg for p in todo_list.packages] - - # first delete any packages not in the new list - for p in todo_list.packages: - if p.pkg not in form.cleaned_data['packages']: - p.delete() - - # now add any packages not in the old list - for pkg in form.cleaned_data['packages']: - if pkg not in packages: - tpkg = TodolistPkg.objects.create( - list = todo_list, pkg = pkg) - send_todolist_email(tpkg) - + new_packages = create_todolist_packages(form) + send_todolist_emails(todo_list, new_packages) return redirect(todo_list) else: - form = TodoListForm(initial={ - 'name': todo_list.name, - 'description': todo_list.description, - 'packages': todo_list.package_names, - }) + form = TodoListForm(instance=todo_list, + initial={'packages': todo_list.raw}) + page_dict = { 'title': 'Edit Todo List: %s' % todo_list.name, + 'description': '', 'form': form, 'submit_text': 'Save List' - } - return direct_to_template(request, 'general_form.html', page_dict) - -@permission_required('main.delete_todolist') -@never_cache -def delete_todolist(request, object_id): - return delete_object(request, object_id=object_id, model=Todolist, - template_name="todolists/todolist_confirm_delete.html", - post_delete_redirect='/todo/') - -def send_todolist_email(todo): - '''Sends an e-mail to the maintainer of a package notifying them that the - package has been added to a todo list''' - maints = todo.pkg.maintainers - if not maints: - return - - page_dict = { - 'pkg': todo.pkg, - 'todolist': todo.list, - 'weburl': todo.pkg.get_full_url() } - t = loader.get_template('todolists/email_notification.txt') - c = Context(page_dict) - send_mail('arch: Package [%s] added to Todolist' % todo.pkg.pkgname, - t.render(c), - 'Arch Website Notification <nobody@archlinux.org>', - [m.email for m in maints], - fail_silently=True) - -def public_list(request): - todo_lists = Todolist.objects.incomplete() - return direct_to_template(request, "todolists/public_list.html", - {"todo_lists": todo_lists}) - + return render(request, 'general_form.html', page_dict) + + +class DeleteTodolist(DeleteView): + model = Todolist + # model in main == assumes name 'main/todolist_confirm_delete.html' + template_name = 'todolists/todolist_confirm_delete.html' + success_url = '/todo/' + + +@transaction.atomic +def create_todolist_packages(form, creator=None): + package_names = form.package_names() + packages = form.packages() + timestamp = now() + if creator: + # todo list is new, populate creator and slug fields + todolist = form.save(commit=False) + todolist.creator = creator + todolist.slug = find_unique_slug(Todolist, todolist.name) + todolist.save() + else: + # todo list already existed + form.save() + todolist = form.instance + + # first mark removed any packages not in the new list + to_remove = set() + for todo_pkg in todolist.packages(): + if todo_pkg.pkg and todo_pkg.pkg not in packages: + to_remove.add(todo_pkg.pk) + elif todo_pkg.pkgname not in package_names: + to_remove.add(todo_pkg.pk) + + TodolistPackage.objects.filter( + pk__in=to_remove).update(removed=timestamp) + + # Add (or mark unremoved) any packages in the new packages list + todo_pkgs = [] + for package in packages: + # ensure get_or_create uses the fields in our unique constraint + defaults = { + 'pkg': package, + 'pkgbase': package.pkgbase, + 'repo': package.repo, + } + todo_pkg, created = TodolistPackage.objects.get_or_create( + todolist=todolist, + pkgname=package.pkgname, + arch=package.arch, + defaults=defaults) + if created: + todo_pkgs.append(todo_pkg) + else: + save = False + if todo_pkg.removed is not None: + todo_pkg.removed = None + save = True + if todo_pkg.pkg != package: + todo_pkg.pkg = package + save = True + if save: + todo_pkg.save() + + return todo_pkgs + + +def send_todolist_emails(todo_list, new_packages): + '''Sends emails to package maintainers notifying them that packages have + been added to a todo list.''' + # start by flipping the incoming list on its head: we want a list of + # involved maintainers and the packages they need to be notified about. + orphan_packages = [] + maint_packages = {} + for todo_package in new_packages: + maints = todo_package.pkg.maintainers.values_list('email', flat=True) + if not maints: + orphan_packages.append(todo_package) + else: + for maint in maints: + maint_packages.setdefault(maint, []).append(todo_package) + + for maint, packages in maint_packages.iteritems(): + packages = sorted(packages, key=attrgetter('pkgname', 'arch')) + ctx = Context({ + 'todo_packages': packages, + 'todolist': todo_list, + }) + template = loader.get_template('todolists/email_notification.txt') + send_mail('Packages added to todo list \'%s\'' % todo_list.name, + template.render(ctx), + settings.BRANDING_EMAIL, + [maint], + fail_silently=True) # vim: set ts=4 sw=4 et: @@ -1,136 +1,131 @@ -from django.conf.urls.defaults import * -from django.conf import settings +from django.conf.urls import include, patterns, url from django.contrib import admin +from django.contrib.sitemaps import views as sitemap_views -from django.views.generic.simple import direct_to_template +from django.views.decorators.cache import cache_page +from django.views.generic import TemplateView, RedirectView -from main.models import Todolist -from feeds import PackageFeed, NewsFeed +from feeds import PackageFeed, NewsFeed, ReleaseFeed import sitemaps -sitemaps = { +our_sitemaps = { + 'base': sitemaps.BaseSitemap, 'news': sitemaps.NewsSitemap, 'packages': sitemaps.PackagesSitemap, 'package-files': sitemaps.PackageFilesSitemap, 'package-groups': sitemaps.PackageGroupsSitemap, + 'split-packages': sitemaps.SplitPackagesSitemap, + 'releases': sitemaps.ReleasesSitemap, + 'todolists': sitemaps.TodolistSitemap, } -admin.autodiscover() - -urlpatterns = patterns('', - (r'^packages/flaghelp/$', 'packages.views.flaghelp'), - (r'^packages/signoffs/$', 'packages.views.signoffs'), - (r'^packages/signoff_package/(?P<arch>[A-z0-9]+)/(?P<pkgname>[A-z0-9\-+.]+)/$', - 'packages.views.signoff_package'), - (r'^packages/update/$', 'packages.views.update'), - - # Preference is for the packages/ url below, but search is kept - # because other projects link to it - (r'^packages/search/$', 'packages.views.search'), - (r'^packages/search/(?P<page>\d+)/$', 'packages.views.search'), - (r'^packages/differences/$', 'packages.views.arch_differences'), - (r'^packages/$', 'packages.views.search'), - (r'^packages/(?P<page>\d+)/$', 'packages.views.search'), - - (r'^packages/(?P<name>[A-z0-9\-+.]+)/$', - 'packages.views.details'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<name>[A-z0-9\-+.]+)/$', - 'packages.views.details'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/$', - 'packages.views.details'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/files/$', - 'packages.views.files'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/maintainer/$', - 'packages.views.getmaintainer'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/flag/$', - 'packages.views.flag'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/unflag/$', - 'packages.views.unflag'), - (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/download/$', - 'packages.views.download'), - - (r'^groups/$', 'packages.views.groups'), - (r'^groups/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/$', - 'packages.views.group_details'), - - (r'^todo/(\d+)/$', 'todolists.views.view'), - (r'^todo/add/$', 'todolists.views.add'), - (r'^todo/edit/(?P<list_id>\d+)/$', 'todolists.views.edit'), - (r'^todo/flag/(\d+)/(\d+)/$', 'todolists.views.flag'), - (r'^todo/delete/(?P<object_id>\d+)/$', - 'todolists.views.delete_todolist'), - (r'^todo/$', 'todolists.views.list'), - (r'^todolists/$', 'todolists.views.public_list'), - - (r'^news/add/$', 'news.views.add'), - (r'^news/preview/$', 'news.views.preview'), - # old news URLs, permanent redirect view so we don't break all links - (r'^news/(?P<object_id>\d+)/$', 'news.views.view_redirect'), - (r'^news/(?P<slug>[-\w]+)/$', 'news.views.view'), - (r'^news/(?P<slug>[-\w]+)/edit/$', 'news.views.edit'), - (r'^news/(?P<slug>[-\w]+)/delete/$', 'news.views.delete'), - (r'^news/$', 'news.views.news_list', {}, 'news-list'), - - (r'^mirrors/$', 'mirrors.views.mirrors', {}, 'mirrors-list'), - (r'^mirrors/status/$', 'mirrors.views.status', {}, 'mirror-status'), - (r'^mirrors/(?P<name>[\.\-\w]+)/$', 'mirrors.views.mirror_details'), - - (r'^mirrorlist/$', 'mirrors.views.generate_mirrorlist', {}, 'mirrorlist'), - (r'^mirrorlist/all/$', 'mirrors.views.find_mirrors', {'countries': ['all']}), - (r'^mirrorlist/all/ftp/$', 'mirrors.views.find_mirrors', - {'countries': ['all'], 'protocols': ['ftp']}), - (r'^mirrorlist/all/http/$', 'mirrors.views.find_mirrors', - {'countries': ['all'], 'protocols': ['http']}), - - (r'^devel/$', 'devel.views.index'), - (r'^devel/notify/$', 'devel.views.change_notify'), - (r'^devel/profile/$', 'devel.views.change_profile'), - - (r'^devel/newuser/$', 'devel.views.new_user_form'), - -# Feeds and sitemaps - (r'^feeds/$', 'public.views.feeds', {}, 'feeds-list'), - (r'^feeds/news/$', NewsFeed()), - (r'^feeds/packages/$', PackageFeed()), - (r'^feeds/packages/(?P<arch>[A-z0-9]+)/$', - PackageFeed()), - (r'^feeds/packages/(?P<arch>[A-z0-9]+)/(?P<repo>[A-z0-9\-]+)/$', - PackageFeed()), - (r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', - {'sitemaps': sitemaps}), - (r'^sitemap-(?P<section>.+)\.xml$', 'django.contrib.sitemaps.views.sitemap', - {'sitemaps': sitemaps}), - -# Authentication / Admin - (r'^login/$', 'django.contrib.auth.views.login', { - 'template_name': 'registration/login.html'}), - (r'^accounts/login/$', 'django.contrib.auth.views.login', { - 'template_name': 'registration/login.html'}), - (r'^logout/$', 'django.contrib.auth.views.logout', { - 'template_name': 'registration/logout.html'}), - (r'^accounts/logout/$', 'django.contrib.auth.views.logout', { - 'template_name': 'registration/logout.html'}), - (r'^admin/', include(admin.site.urls)), - -# (mostly) Static Pages - (r'^$', 'public.views.index', {}, 'index'), - (r'^about/$', direct_to_template, {'template': 'public/about.html'}, 'page-about'), - (r'^art/$', direct_to_template, {'template': 'public/art.html'}, 'page-art'), - (r'^svn/$', direct_to_template, {'template': 'public/svn.html'}, 'page-svn'), - (r'^developers/$', 'public.views.userlist', { 'type':'Developers' }, 'page-devs'), - (r'^trustedusers/$', 'public.views.userlist', { 'type':'Trusted Users' }, 'page-tus'), - (r'^fellows/$', 'public.views.userlist', { 'type':'Fellows' }, 'page-fellows'), - (r'^donate/$', 'public.views.donate', {}, 'page-donate'), - (r'^download/$', 'public.views.download', {}, 'page-download'), - (r'^opensearch/packages/$', 'packages.views.opensearch', {}, 'opensearch-packages'), - -# Some django internals we use - (r'^jsi18n/$', 'django.views.i18n.null_javascript_catalog'), +news_sitemaps = { 'news': sitemaps.RecentNewsSitemap } + +urlpatterns = [] + +# Public pages +urlpatterns += patterns('public.views', + (r'^$', 'index', {}, 'index'), + (r'^about/$', TemplateView.as_view(template_name='public/about.html'), + {}, 'page-about'), + (r'^art/$', RedirectView.as_view(url='https://projects.parabola.nu/artwork.git/'), + {}, 'page-art'), + (r'^donate/$', RedirectView.as_view(url='https://wiki.parabola.nu/Donations'), + {}, 'page-donate'), + (r'^download/$', RedirectView.as_view(url='https://wiki.parabola.nu/Get_Parabola'), + {}, 'page-download'), + (r'^master-keys/$', 'keys', {}, 'page-keys'), + (r'^master-keys/json/$', 'keys_json', {}, 'pgp-keys-json'), + (r'^people/(?P<slug>[-\w]+)/$', 'people', {}, 'people'), ) -if settings.DEBUG == True: - urlpatterns += patterns('', - (r'^media/(.*)$', 'django.views.static.serve', - {'document_root': settings.DEPLOY_PATH+'/media'})) +# Feeds patterns, used below +feeds_patterns = patterns('', + (r'^$', 'public.views.feeds', {}, 'feeds-list'), + (r'^news/$', cache_page(311)(NewsFeed())), + (r'^packages/$', cache_page(313)(PackageFeed())), + (r'^packages/(?P<arch>[A-z0-9]+)/$', + cache_page(313)(PackageFeed())), + (r'^packages/all/(?P<repo>[A-z0-9\-]+)/$', + cache_page(313)(PackageFeed())), + (r'^packages/(?P<arch>[A-z0-9]+)/(?P<repo>[A-z0-9\-]+)/$', + cache_page(313)(PackageFeed())), + (r'^releases/$', cache_page(317)(ReleaseFeed())), +) + +# Includes and other remaining stuff +urlpatterns += patterns('', + (r'^admin/', include(admin.site.urls)), + (r'^devel/', include('devel.urls')), + (r'^feeds/', include(feeds_patterns)), + (r'^groups/', include('packages.urls_groups')), + (r'^mirrorlist/',include('mirrors.urls_mirrorlist')), + (r'^mirrors/', include('mirrors.urls')), + (r'^news/', include('news.urls')), + (r'^packages/', include('packages.urls')), + (r'^releng/', include('releng.urls')), + (r'^todo/', include('todolists.urls')), + (r'^visualize/', include('visualize.urls')), + (r'^opensearch/packages/$', 'packages.views.opensearch', + {}, 'opensearch-packages'), + (r'^opensearch/packages/suggest$', 'packages.views.opensearch_suggest', + {}, 'opensearch-packages-suggest'), +) + +# Sitemaps +urlpatterns += patterns('', + (r'^sitemap.xml$', + cache_page(1831)(sitemap_views.index), + {'sitemaps': our_sitemaps, 'sitemap_url_name': 'sitemaps'}), + (r'^sitemap-(?P<section>.+)\.xml$', + cache_page(1831)(sitemap_views.sitemap), + {'sitemaps': our_sitemaps, 'template_name': 'sitemaps/sitemap.xml.jinja'}, + 'sitemaps'), + (r'^news-sitemap\.xml$', + cache_page(1831)(sitemap_views.sitemap), + {'sitemaps': news_sitemaps, 'template_name': 'sitemaps/news_sitemap.xml.jinja'}, + 'news-sitemap'), +) + +# Authentication +urlpatterns += patterns('django.contrib.auth.views', + (r'^login/$', 'login', {'template_name': 'registration/login.html'}, 'login'), + (r'^logout/$', 'logout', {'template_name': 'registration/logout.html'}, 'logout'), +) + +# Redirects for older known pages we see in the logs +legacy_urls = ( + ('^about.php', '/about/'), + ('^changelog.php', '/packages/?sort=-last_update'), + ('^devs.php', '/people/hackers/'), + ('^donations.php', '/donate/'), + ('^download.php', '/download/'), + ('^index.php', '/'), + ('^logos.php', '/art/'), + ('^news.php', '/news/'), + ('^packages.php', '/packages/'), + ('^people.php', '/people/hackers/'), + ('^todolists/$', '/todo/'), + ('^hackers/$', '/people/hackers/'), + ('^developers/$', '/people/hackers/'), + ('^artists/$', '/people/artists/'), + ('^fellows/$', '/people/hacker-fellows/'), + ('^trustedusers/$', '/people/hackers/'), + + ('^docs/en/guide/install/arch-install-guide.html', + 'https://wiki.parabola.nu/Installation_Guide'), + ('^docs/en/', 'https://wiki.parabola.nu/'), + ('^docs/', 'https://wiki.parabola.nu/'), +) + +urlpatterns += [url(old_url, RedirectView.as_view(url=new_url)) + for old_url, new_url in legacy_urls] + + +def show_urls(urllist=urlpatterns, depth=0): + for entry in urllist: + print " " * depth, entry.regex.pattern + if hasattr(entry, 'url_patterns'): + show_urls(entry.url_patterns, depth + 1) # vim: set ts=4 sw=4 et: diff --git a/visualize/__init__.py b/visualize/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/visualize/__init__.py diff --git a/visualize/static/visualize.js b/visualize/static/visualize.js new file mode 100644 index 00000000..32e2a304 --- /dev/null +++ b/visualize/static/visualize.js @@ -0,0 +1,310 @@ +/* archweb.js + * Homepage: https://projects.archlinux.org/archweb.git/ + * Copyright: 2011-2013 The Archweb Team (Dan McGee) + * License: GPLv2 + * + * This file is part of Archweb. + * + * Archweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Archweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Archweb. If not, see <http://www.gnu.org/licenses/>. + */ + +function packages_treemap(chart_id, orderings, default_order) { + var jq_div = jQuery(chart_id), + color = d3.scale.category20(); + var key_func = function(d) { return d.key; }; + var value_package_count = function(d) { return d.count; }, + value_flagged_count = function(d) { return d.flagged; }, + value_compressed_size = function(d) { return d.csize; }, + value_installed_size = function(d) { return d.isize; }; + + /* tag the function so when we display, we can format filesizes */ + value_package_count.is_size = value_flagged_count.is_size = false; + value_compressed_size.is_size = value_installed_size.is_size = true; + + var treemap = d3.layout.treemap() + .size([jq_div.width(), jq_div.height()]) + /*.sticky(true)*/ + .value(value_package_count) + .sort(function(a, b) { return a.key < b.key; }) + .children(function(d) { return d.data; }); + + var cell_html = function(d) { + if (d.children) { + return ""; + } + var valuefunc = treemap.value(); + var value = valuefunc(d); + if (valuefunc.is_size && value !== undefined) { + value = format_filesize(value); + } + return "<span>" + d.name + ": " + value + "</span>"; + }; + + var d3_div = d3.select(jq_div.get(0)); + + var prop_px = function(prop, offset) { + return function(d) { + var dist = d[prop] + offset; + if (dist > 0) { + return dist + "px"; + } + else { + return "0px"; + } + }; + }; + + var cell = function() { + /* the -1 offset comes from the border width we use in the CSS */ + this.style("left", prop_px("x", 0)).style("top", prop_px("y", 0)) + .style("width", prop_px("dx", -1)).style("height", prop_px("dy", -1)); + }; + + var fetch_for_ordering = function(order) { + d3.json(order.url, function(json) { + var nodes = d3_div.data([json]).selectAll("div") + .data(treemap.nodes, key_func); + /* start out new nodes in the center of the picture area */ + var w_center = jq_div.width() / 2, + h_center = jq_div.height() / 2; + nodes.enter().append("div") + .attr("class", "treemap-cell") + .attr("title", function(d) { return d.name; }) + .style("left", w_center + "px").style("top", h_center + "px") + .style("width", "0px").style("height", "0px") + .style("display", function(d) { return d.children ? "none" : null; }) + .html(cell_html); + nodes.transition().duration(1500) + .style("background-color", function(d) { + return d.children ? null : color(d[order.color_attr]); + }) + .call(cell); + nodes.exit().transition().duration(1500).remove(); + }); + }; + + /* start the callback for the default order */ + fetch_for_ordering(orderings[default_order]); + + var make_scale_button = function(name, valuefunc) { + var button_id = chart_id + "-" + name; + /* upon button click, attach new value function and redraw all boxes + * accordingly */ + d3.select(button_id).on("click", function() { + d3_div.selectAll("div") + .data(treemap.value(valuefunc), key_func) + .html(cell_html) + .transition().duration(1500).call(cell); + + /* drop off the '#' sign to convert id to a class prefix */ + d3.selectAll("." + chart_id.substring(1) + "-scaleby") + .classed("active", false); + d3.select(button_id).classed("active", true); + }); + }; + + /* each scale button tweaks our value, e.g. net size function */ + make_scale_button("count", value_package_count); + make_scale_button("flagged", value_flagged_count); + make_scale_button("csize", value_compressed_size); + make_scale_button("isize", value_installed_size); + + var make_group_button = function(name, order) { + var button_id = chart_id + "-" + name; + d3.select(button_id).on("click", function() { + fetch_for_ordering(order); + + /* drop off the '#' sign to convert id to a class prefix */ + d3.selectAll("." + chart_id.substring(1) + "-groupby") + .classed("active", false); + d3.select(button_id).classed("active", true); + }); + }; + + jQuery.each(orderings, function(k, v) { + make_group_button(k, v); + }); + + /* adapt the chart size when the browser resizes */ + var resize_timeout = null; + var real_resize = function() { + resize_timeout = null; + d3_div.selectAll("div") + .data(treemap.size([jq_div.width(), jq_div.height()]), key_func) + .call(cell); + }; + jQuery(window).resize(function() { + if (resize_timeout) { + clearTimeout(resize_timeout); + } + resize_timeout = setTimeout(real_resize, 200); + }); +} + +function developer_keys(chart_id, data_url) { + var jq_div = jQuery(chart_id), + r = 10; + + var force = d3.layout.force() + .friction(0.5) + .gravity(0.1) + .charge(-500) + .size([jq_div.width(), jq_div.height()]); + + var svg = d3.select(chart_id) + .append("svg"); + + d3.json(data_url, function(json) { + var fill = d3.scale.category20(); + + var index_for_key = function(key) { + var i; + key = key.slice(-8); + for (i = 0; i < json.nodes.length; i++) { + var node_key = json.nodes[i].key; + if (node_key && node_key.slice(-8) === key) { + return i; + } + } + }; + + /* filter edges to only include those that we have two nodes for */ + var edges = jQuery.grep(json.edges, function(d, i) { + d.source = index_for_key(d.signer); + d.target = index_for_key(d.signee); + return d.source >= 0 && d.target >= 0; + }); + + jQuery.map(json.nodes, function(d, i) { d.master_sigs = 0; d.other_sigs = 0; }); + jQuery.map(edges, function(d, i) { + /* only the target gets credit in either case, as it is their key that was signed */ + if (json.nodes[d.source].group === "master") { + json.nodes[d.target].master_sigs += 1; + } else { + json.nodes[d.target].other_sigs += 1; + } + }); + jQuery.map(json.nodes, function(d, i) { + if (d.group === "packager") { + d.approved = d.master_sigs >= 3; + } else { + d.approved = null; + } + }); + + var link = svg.selectAll("line") + .data(edges) + .enter() + .append("line") + .style("stroke", "#888"); + + /* anyone with more than 7 - 1 == 6 signatures gets the top value */ + var stroke_color_scale = d3.scale.log().domain([1, 7]).range(["white", "green"]).clamp(true); + + var node = svg.selectAll("circle") + .data(json.nodes) + .enter().append("circle") + .attr("r", function(d) { + switch (d.group) { + case "master": + return r * 1.6 - 0.75; + case "cacert": + return r * 1.4 - 0.75; + case "packager": + default: + return r - 0.75; + } + }) + .style("fill", function(d) { return fill(d.group); }) + .style("stroke", function(d) { + if (d.approved === null) { + return d3.rgb(fill(d.group)).darker(); + } else if (d.approved) { + /* add 1 so we don't blow up the logarithm-based scale */ + return stroke_color_scale(d.other_sigs + 1); + } else { + return "red"; + } + }) + .style("stroke-width", "1.5px") + .call(force.drag); + node.append("title").text(function(d) { return d.name; }); + + var nodeover = function(d, i) { + d3.select(this).transition().duration(500).style("stroke-width", "3px"); + link.filter(function(d_link, i) { + return d_link.source === d || d_link.target === d; + }).transition().duration(500).style("stroke", "#800"); + }; + var nodeout = function(d, i) { + d3.select(this).transition().duration(500).style("stroke-width", "1.5px"); + link.transition().duration(500).style("stroke", "#888"); + }; + + node.on("mouseover", nodeover) + .on("mouseout", nodeout); + + var distance = function(d, i) { + /* place a long line between all master keys and other keys. + * however, other connected clusters should be close together. */ + if (d.source.group === "master" || d.target.group === "master" || + d.source.group === "cacert" || d.target.group === "cacert") { + return 200; + } else { + return 40; + } + }; + + var strength = function(d, i) { + if (d.source.group === "master" || d.target.group === "master" || + d.source.group === "cacert" || d.target.group === "cacert") { + return 0.2; + } else { + return 0.8; + } + }; + + var tick = function() { + var offset = r * 2, + w = jq_div.width(), + h = jq_div.height(); + node.attr("cx", function(d) { return (d.x = Math.max(offset, Math.min(w - offset, d.x))); }) + .attr("cy", function(d) { return (d.y = Math.max(offset, Math.min(h - offset, d.y))); }); + + link.attr("x1", function(d) { return d.source.x; }) + .attr("y1", function(d) { return d.source.y; }) + .attr("x2", function(d) { return d.target.x; }) + .attr("y2", function(d) { return d.target.y; }); + }; + + force.nodes(json.nodes) + .links(edges) + .linkDistance(distance) + .linkStrength(strength) + .on("tick", tick) + .start(); + }); + + /* adapt the chart size when the browser resizes */ + var resize_timeout = null; + var real_resize = function() { + resize_timeout = null; + force.size([jq_div.width(), jq_div.height()]); + }; + jQuery(window).resize(function() { + if (resize_timeout) { + clearTimeout(resize_timeout); + } + resize_timeout = setTimeout(real_resize, 200); + }); +} diff --git a/visualize/tests.py b/visualize/tests.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/visualize/tests.py diff --git a/visualize/urls.py b/visualize/urls.py new file mode 100644 index 00000000..8c3ea06a --- /dev/null +++ b/visualize/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import patterns + +urlpatterns = patterns('visualize.views', + (r'^$', 'index', {}, 'visualize-index'), + (r'^by_arch/$', 'by_arch', {}, 'visualize-byarch'), + (r'^by_repo/$', 'by_repo', {}, 'visualize-byrepo'), +) + +# vim: set ts=4 sw=4 et: diff --git a/visualize/views.py b/visualize/views.py new file mode 100644 index 00000000..9c537c20 --- /dev/null +++ b/visualize/views.py @@ -0,0 +1,74 @@ +import json + +from django.db.models import Count, Sum +from django.http import HttpResponse +from django.shortcuts import render +from django.views.decorators.cache import cache_page + +from main.models import Package, Arch, Repo + + +def index(request): + return render(request, 'visualize/index.html') + + +def arch_repo_data(): + qs = Package.objects.select_related().values( + 'arch__name', 'repo__name').annotate( + count=Count('pk'), csize=Sum('compressed_size'), + isize=Sum('installed_size'), + flagged=Count('flag_date')).order_by() + arches = Arch.objects.values_list('name', flat=True) + repos = Repo.objects.values_list('name', flat=True) + + def build_map(name, arch, repo): + key = '%s:%s' % (repo or '', arch or '') + return { + 'key': key, + 'name': name, + 'arch': arch, + 'repo': repo, + 'data': [], + } + + # now transform these results into two mappings: one ordered (repo, arch), + # and one ordered (arch, repo). + arch_groups = {a: build_map(a, a, None) for a in arches} + repo_groups = {r: build_map(r, None, r) for r in repos} + for row in qs: + arch = row['arch__name'] + repo = row['repo__name'] + values = { + 'arch': arch, + 'repo': repo, + 'name': '%s (%s)' % (repo, arch), + 'key': '%s:%s' % (repo, arch), + 'csize': row['csize'], + 'isize': row['isize'], + 'count': row['count'], + 'flagged': row['flagged'], + } + arch_groups[arch]['data'].append(values) + repo_groups[repo]['data'].append(values) + + data = { + 'by_arch': { 'name': 'Architectures', 'data': arch_groups.values() }, + 'by_repo': { 'name': 'Repositories', 'data': repo_groups.values() }, + } + return data + + +@cache_page(1800) +def by_arch(request): + data = arch_repo_data() + to_json = json.dumps(data['by_arch'], ensure_ascii=False) + return HttpResponse(to_json, content_type='application/json') + + +@cache_page(1800) +def by_repo(request): + data = arch_repo_data() + to_json = json.dumps(data['by_repo'], ensure_ascii=False) + return HttpResponse(to_json, content_type='application/json') + +# vim: set ts=4 sw=4 et: |