text:
The Melbourne Urbanist
Planning and development issues with a particular focus on Melbourne, Australia
Should replacing level crossings be given higher priority?
Posted: August 16, 2011 | Author: Alan Davies | Filed under: Cars & traffic, Public transport | Tags: Brian Negus, bridge, Committee for Melbourne, development rights, grade separation, level crossing, overpass, PTUA, RACV, rail, surplus railway land | 14 Comments
Hot wheels metropolis (1200 cars, but no trains)
The Committee for Melbourne has called for a $17.2 billion program to remove all Melbourne's level crossings over the next 20 years.
The Committee says just two separations of road and rail were constructed by the Kennett government and two by the Bracks/Brumby government. While Melbourne has 172 level crossings, Sydney tackled the issue years ago and now has only eight.
However the Baillieu government has given an undertaking to grade-separate ten crossings at an estimated cost, on average, of around $100 million each. The Committee reckons the private sector could pay a big chunk of the $17.2 billion cost in return for the commercial rights to each site, although the Herald-Sun warns such a move would very likely "be fiercely opposed by anti-development groups".
There's a lot to be said for giving a higher priority in the transport capital works program to eliminating level crossings, as they present a number of problems. One is they slow traffic, including buses and trucks. According to the RACV's public policy manager, Brian Negus, crossings along the Dandenong line are closed for 30-40 minutes an hour during the peak, exacerbating traffic congestion. This is likely to become a bigger problem as the share of public transport trips carried by buses increases. The interaction between crossings and nearby signalled junctions is a major barrier to the efficient performance of the transport network.
Level crossings also impose a limit on the frequency of train services. There are only so many trains that can realistically be sent down a line given each service entails stopping traffic in both directions for well in excess of one minute (in Newcastle, crossings are closed on average for passenger and freight trains for between three and seven minutes!). Some crossings are forecast to carry nearly 40 trains per hour in the peak by 2021. Another issue is traffic queuing across rail lines — as well as the occasional car/train incident — limits the efficiency of the network. Further, level crossings are a safety hazard for pedestrians and give parents a reason to discourage children from walking to school.
While I've not seen an analysis for Melbourne, there's little doubt the benefit-cost ratio of level crossing elimination would be very high. I expect it would be well ahead of some other much larger transport projects, such as the Avalon, Doncaster or Rowville rail proposals.
There are nevertheless a number of issues raised by this proposal. One is the need to prioritise works – some crossings are relatively minor and simply don't warrant expenditure in the forseeable future. Probably 80% of the benefits will come from grade separating 20% of crossings. Back in 2009, the Public Transport Users Association argued these ten crossing should be given the highest priority, given their impact on road-based public transport:
Bell Street and Munro Street, Coburg (one project) (Smartbus 903)
Springvale Road, Springvale (Smartbus 888/889)
Bell Street, Cramer Street and Murray Road, Preston (one project) (Smartbus 903)
Glen Huntly Road and Neerim Road, Glenhuntly (one project) (Tram 67, and trains subject to speed restrictions)
Balcombe Road, Mentone (Smartbus 903)
Buckley Street, Essendon (Smartbus 903)
Clayton Road, Clayton (Smartbus 703)
Burke Road, Gardiner (Tram 72, and trains subject to speed restrictions)
Camp Road, Campbellfield (crossing elimination and new station) (proposed Smartbus 902)
Glenferrie Road, Kooyong (Tram 16, and trains subject to speed restrictions)
That's a particular perspective, yet it matches some of the RACV's priorities. Last year the RACV said the four worst crossings in Melbourne are in High Street near Reservoir station, on Burke Road near Gardiner station in Glen Iris, on Clayton Road next to Clayton station, and Murrumbeena Road near the station. The Dandenong rail corridor also figures high in the RACV's priorities.
I'm not sure there is as much value in development rights as the Committee for Melbourne imagines. Many level crossings, perhaps most, may not have enough suitable land available for development after meeting grade separation and operational needs. The most promising opportunities are probably where the rail line rather than the road has been lowered, but this can be expensive. Many of those that do have land available may be in locations considered unsuitable for development by planners. And let's be clear that development in air space over railway lines is a fantasy – it's simply too expensive in all but an extremely small number of cases. For practical purposes, development in air space is not an option. Read the rest of this entry »
What's good (and bad) about greater diversity?
Posted: February 13, 2011 | Author: Alan Davies | Filed under: Planning, Social and community | Tags: Beyond 5 Million, Committee for Melbourne, Disconnected, diversity, Dr Andrew Leigh, ethnicity, Melbourne 2030, The cities we need, The Grattan Institute, Tiger Mother | 6 Comments
High-level city objectives in The Grattan Institute's 'The cities we need'
A standard objective these days in high-level city strategic plans is greater diversity. It's mentioned, for example, in Melbourne 2030, in the Committee for Melbourne's Beyond 5 Million and in The Grattan Institute's The Cities We Need (see graphic).
The Grattan Institute says diversity is important because "many economists think that mixing of ethnicity, age, culture and education is important for a modern knowledge economy, in order to stimulate and disperse ideas".
But according to Dr Andrew Leigh, it's not necessarily all mother's milk, at least in relation to ethnic diversity (which is what most discussion of diversity in Australia is about). In his new book on social capital, Disconnected (which I've discussed before), he points out that there is a negative correlation between trust and ethnic diversity:
Residents of multi-racial neighbourhoods are more likely to agree that 'you can't be too careful in dealing with most Australians'. In particular, neighbourhoods where many languages are spoken tend have lower levels of trust…
This accords with the findings of a succession of studies of ethnic diversity in the US and other countries. We will have to work harder, Dr Leigh suggests, if we are to make Australia both diverse and high trust.
Let me emphasise that Dr Leigh, who is the new ALP member for Fraser in the ACT and until the last election was a Professor of economics at ANU, is a supporter of immigration:
A spate of studies suggest that continued high levels of immigration will most likely bring a raft of economic and social benefits to Australia. But we should not gild the lily. Most likely, higher diversity will lead to lower levels of interpersonal trust…..the challenge for policymakers is how to maintain the current levels of immigration while mitigating the impact on our social and political fabric.
But how do you mitigate that impact? Most city policy documents don't even acknowledge that there might be potential downsides to ethnic diversity. Nor do they usually specify what the spatial dimension is, much less what specific policies ought to be pursued. Read the rest of this entry »
Is Melbourne better today than it was in the sixties?
Posted: July 18, 2010 | Author: Alan Davies | Filed under: Planning, Population | Tags: 1960s, Andrew Mcleod, Brisbane, Committee for Melbourne, Population | 3 Comments
Little Collins St traffic 1960 (by FailingMemory)
I've previously discussed the argument advanced by the CEO of the Committee for Melbourne, Andrew Mcleod, that Melbourne can get better as it gets bigger.
Mr Mcleod has another interesting contention – he argues that Melbourne is unambiguously better and more liveable today than it was in 1960. Back then Melbourne had a population of around two million but now it has four million.
I have my doubts about the political wisdom of running that line but that's neither here nor there – my primary interest is whether or not Mr Mcleod's proposition makes sense.
I've no doubt the response of many people would be that housing in Melbourne is now less affordable than it was forty years ago and the roads and public transport are more congested. Some people also think it's less safe, less equal and has a much larger per capita ecological footprint. For others, the footy lost something really important when the AFL was created.
On the other hand, many would argue that Melbourne is now more tolerant, more diverse and more exciting than it ever was. It's now a city with a global profile, a better educated population and a vastly more sophisticated lifestyle. You can drive from the west to the south east fringe today entirely on freeway in under an hour in the off peak and you can take a train around the CBD. Read the rest of this entry »
Is a bigger Melbourne a better Melbourne?
Posted: June 23, 2010 | Author: Alan Davies | Filed under: Planning, Population | Tags: Andrew Mcleod, city size, Committee for Melbourne, density, Los Angeles, Manhattan, New York, Shaping Melbourne | 6 Comments
The CEO of the Committee for Melbourne, Andrew Mcleod, advanced an interesting argument about the importance of growth when launching the Committee's new report, Melbourne Beyond 5 Million, earlier this month.
He contended that Melbourne can get better as it gets bigger. His main argument is that Melbourne in 2010, with 4 million people, is double the size it was in 1960 and is, he says, unambiguously more liveable.
Big city - East Village, Manhattan
So is bigger better? I don't think I have a definitive answer and I'm not even sure there is one, but I think it's useful in light of the high population growth projected for Melbourne to canvass some of the issues.
The fear many people have is that a bigger Melbourne will mean housing is less affordable and roads and public transport more congested. Some people also think it would be less safe, less equal and have a much larger per capita ecological footprint.
But there are advantages in getting bigger. Larger cities are usually denser and have a lower ecological footprint than smaller cities. There is also an extensive literature showing that the productivity of cities increases with population.
There are different opinions on the underlying reasons but many observers, like Harvard's Professor Edward Glaeser, think that big cities enable people to connect and learn from one another. They tend to be more diverse and offer greater specialisation in work, consumption, socialising and ideas.
There are more than thirty cities in the OECD countries alone that have a larger population than Melbourne. They must be doing something right if people want to live in them. For all the complaints made about Los Angeles, many more people seem to want to live there than in Melbourne. Many talented Australians aspire to move to LA to work in specialised industries like entertainment, higher education and technology. Read the rest of this entry »
Is the online version of The Age still a paper?
Posted: June 15, 2010 | Author: Alan Davies | Filed under: Miscellaneous | Tags: Committee for Melbourne, e-commerce, Fairfax, Financial Review, internet, online, review, Sydney Morning Herald, The Age, theage.com.au | 4 Comments
I value having The Age delivered to my door each morning, but I'm disappointed with the online version, theage.com.au. I refer to it often, but my experience with the site suggests I'd have to think long and hard before I'd be prepared to pay to access it online.
Charging is of course Fairfax's ultimate goal (the online version of The Financial Review, which is also Fairfax owned, is pay for use) and seen as a way of making up for the declining popularity of newspapers – sales of the Monday to Friday edition of The Age fell 4% in the March Quarter, 2010. Sales of the Saturday edition fell 5%.
Those video advertisements that automatically start when you click on the site are a real turn-off but I have some sympathy for Fairfax's search for a financially viable online model (although since I pay for the hard copy, why should I have to endure such intrusive advertising?). No, my disappointment relates to management issues.
A key reason for my dissatisfaction is basic – it's hard to find stuff on the site. I imagine that many people want to track down an article they recall seeing in yesterday's paper or last week's, yet you can't search by date of publication. You have to know the title or author. That seems like a terribly basic omission to me. Why can't I look up a simple table of contents for each day, showing the name and author of articles with the ability to jump straight to what I want? Read the rest of this entry »
The Melbourne Urbanist has moved to a new address (and taken a new name)!!
The Melbourne Urbanist has moved out of home and is now living in a share house. In true Aussie tradition, the new house mates have shortened my name to The Urbanist. The entire blog has been moved to Crikey, so existing discussions can be continued there. All new posts now emanate from: http://blogs.crikey.com.au/theurbanist/
CLOSED – 'Human Transit'
HARD QUESTIONS
Is labelling the outer suburbs as 'job deserts' helpful?
Should public transport fares be abolished?
Do citizens really like road pricing?
Should Shorten fund Melbourne's suburban rail loop?
Is Labor serious about electrical vehicles?
How desperate can the Morrison government get?
Why is east coast High Speed Rail still being taken seriously?
What would happen if public transport use grew faster?
Why do (some) motorists think cyclists don't have a right to the roads?
Suburban rail loop – how can this mistake be prevented?
Could powered two-wheelers be a game-changer for urban travel?
Where to with transport in our capital cities?
The Urbanist's annual holiday reading guide
Is infrastructure why Victorian voters swung so decisively to Labor?
Is growth in driving really outstripping surging population?
Should adult cyclists be permitted on footpaths?
Isn't long-term planning for urban public transport a no-brainer?
Is Melbourne's promised loop rail line justified by jobs growth in suburban centres?
Architecture & buildings
Cars & traffic
Education, justice, health
Energy & GHG
Growth Areas
HSR High Speed Rail
Social and community
Transport – general

redpajama_set_name: RedPajamaCommonCrawl


Jamie Hastings died last Thursday. I don't know any of the particulars, other than what was in the obituary.
I first heard about it late Tuesday night, and at first it didn't bother me much. We hadn't had any contact in 20 years. But on Wednesday, I found myself in a lot of pain and pondering on the frailty of life and the amount of wasted potential in the world.
The funeral is taking place now, but I live in Arizona and am not able to attend. I still want to do something, though.
I got a request from Lori Nielsen Jeffs (via Travis Nelson) for memories of Jamie. She is speaking at the funeral and was looking for ideas.
If you have read Speaker for the Dead by Orson Scott Card, you have run into an entirely different kind of eulogy—one that speaks simply the truth of the life lived, not one whitewashed. That's kind of what I gave Lori—mostly unfiltered memories I had of Jamie.
I want to share it with those who remember, and those who never knew. I hope it's a fitting tribute.
I'll give you what I can, but it's more of me vomiting on the page than a eulogy. More Speaker for the Dead style, really. I don't know how much (if any) of it will be appropriate to your purpose, so use what you want (if any) as you see fit. I'm not embarrassed by it, at least not any more.
Like a lot of us (it sounds like), I hung out with Jamie a bit in high school, but we weren't really close. I consider him a friend, but we last talked 20 years ago. I don't think I was ever at his house. He was a year ahead of me in school, and enough older than me that we didn't spend more than a few months in the same priesthood quorum at church.
I really liked Jamie's artwork, but I honestly never saw much of it. I remember 2 pieces in particular, though.
One was a heart-shaped box made of clay. It was decorated nicely, but the cool part was that it had a key and working lock, also made of clay. I thought it was ingenious. He gave it to Tiffany Kohler (now Klick). It was in her room that I saw it, and I asked her about it.
I introduced Jamie to the Society for Creative Anachronism (a medieval reenactment organization), and we went to a couple of events. One was in Sealander park, near Shelley, but I don't think he enjoyed it very much. He didn't have any period garb, so he ended up wearing a pirate shirt and jeans. He spent most of the time commenting on all the fat women in low-cut dresses. He did buy himself a nice, hand forged knife though. He actually haggled the merchant down on the price.
The other event we went to was near Bozeman, Montana. He drove us up, so we had a lot of time to talk. Unfortunately, I can't remember anything that was said. I don't think any of it was of consequence. Since neither of us really knew anyone else at the event, we spent the whole day together. It was fun, and after it was over, we were closer. But I still can't say I knew much about his inner life. He never really talked about it.
We used to play Dungeons & Dragons together, with Travis Nelson, Chuck Burgess, and Nathan Wingert (and maybe Jeff Nielsen and Alan Scholes—I can't remember any more). Jamie always seemed to willfully double-cross members of the party (his team) and ended up getting killed, in the game. In one session, he stole from me, so I knocked him unconscious and left him to die (which is to say, my character did that to his character). I don't know why it always ended like that. It was just a game, but he always used the same failing strategy.
I only have a couple of other specific memories. I remember borrowing some of his Conan comic books, and I remember him saying that he wanted to become successful and come back to build a million-dollar house in Basalt. I have no idea whether it was purely in jest or something of a wish.
In the end, I wish we'd been better friends. I wish we'd stayed in touch. I wish… but I guess it doesn't matter now.


The first result of Janus Henderson Group following the recent merger was a great result with almost all key indicators moving in the right direction.
The highly complementary businesses of Janus Capital Group and Henderson Global Investors merged at the end of May. The Henderson share price had been sold down substantially since the merger was announced due to a range of concerns, including whether synergies would be achieved and potential client losses during the merger process.
This provided Perennial Value with an opportunity to increase exposure to the company at an attractive valuation. A number of the market concerns were allayed by the result. Importantly, the $110million synergy target was reaffirmed and timing of synergy realisation brought forward. Net fund flows were better than expected and the key leading indicator of investment performance has improved across the group. This resulted in higher than expected performance fees. Management fees were also better than expected due to both higher than expected funds under management and a higher fee rate due to the favourable mix of flows.
In our view, the valuation of the company remains undemanding even after the strong price rise on the day after the result. We see the merger as a rare case where the merging businesses are truly complementary.
We expect that over time the stronger Janus Henderson Group will shine through – in terms of not just the cost synergies but also in stronger distribution of the products of the respective former businesses.
For instance, Henderson is strong geographically in Europe and the UK while Janus is strong in the US and Japan. Henderson is strong in Equities and Alternative asset classes, while Janus is strong in Fixed Interest and Quantitative Investing. The stronger global distribution teams across the globe will now be able to sell all of the products of the group in their respective markets.
If these benefits are confirmed, there is both earnings and earnings multiple upside for Janus Henderson.


text:
Q: Best way to deal with unittest and imports of local modules in Python3 without using hacky solutions I know this is an hot topic in the community and a lot of people asked the same thing. Unfortunately, after I read a huge number of these topics I did not find yet a proper solution.
I am asking your kind support to find the best way to deal with unittest and imports so that I don't get the popular message "No module "a.py" found.."
My project structure is:
my_project
    ├── some_script.sh
    ├── log
    ├── README.md
    ├── requirements.txt
    ├── src
    │   ├── __init__.py
    │   ├── config.yml
    │   ├── a.py
    │   ├── b.py
    │   ├── c.py
    ├── tests
    │   ├── __init__.py
    │   ├── test_a.py
    │   ├── test_b.py
    │   ├── test_c.py

About the imports, I use this schema:
a.py
import b
import c

test_a.py
from src import a

When I run the tests I use the autodiscovery, so I do something like:
cd my_project
python3 -m unittest -v

This way the directory my_project should be automatically included in the sys path and python should found all the imported modules inside it.
The issue is that when I import the module "a.py" in in "test_a.py" python complains that module b and c are not found. This is quite reasonable because modules "b.py" and "c.py" are inside "src" and not inside "tests".
How should I deal with imports and unittest in the cleanest way possible?
With cleanest I mean without hacking the pythonpath or adding the dir to the syspath in my python code. Thank you.

redpajama_set_name: RedPajamaStackExchange


4-star guard Jordan Rawls just committed to Western Kentucky. Will reclassify to 2019. Was ranked No. 66 in the 2020 247 composite rankings. This makes the 4th top 100 recruit he has signed in his early tenure. If they get Bassey back watch out for them again next season!
College football attendance lowest in 22 years?
UTEP assistant coach Lamont Smith resigned. Smith was implicated in the college entrance scandal, from when he was the head coach at the University of San Diego. Smith accepted a bribe of $100k from a Hollywood real estate developer. UTEP recruit Brendan Wenzel has asked for and been granted his release. About two weeks ago it was announced that UTEP guards Evan Gilyard and Kobe McGee would not return.
MTSU, UAB, WKU, ODU & Charlotte are all in the field C-USA and the Big East have the most teams in the field, with 5 each. Proud of these ladies and schools.
Who gonna win ODU v WKU?
WKU vs. ODU 7:30 (Central)--CBS Sports Network Good to see the best two programs made it! My choice is WKU!
https://www.herald-dispatch.com/_recent_...9e17a.html HUNTINGTON – The Marshall University men's basketball program has accepted an invitation to participate in the CollegeInsider.com postseason tournament – commonly referred to as the CIT – on Tuesday, March 19 at the Cam Henderson Center, according to a release from the team. Tickets for the first round game – the Jim Phelan Classic – will go on sale today at 3 p.m. to season ticket holders. Season ticket holders will have the ability to access their ticket account online at HerdZone.com and reserve their same season ticket locations for the first round. Season ticket holders will have 24-hour period after each round Marshall advances to secure tickets before they go on sale to the general public. Online orders will be available through HerdZone.com two hours after the conclusion of each round. Season ticket holders will have until noon Monday, March 18, to secure tickets. Unsecured season tickets will go on sale at 2 p.m. Monday.


text:
"""
Configuration items for the shop.
Also contains shopping cart and related classes.
"""

from decimal import Decimal, ROUND_CEILING
from django.contrib.sites.models import Site
from django.conf import settings
from django.core import urlresolvers
from django.db import models
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext, ugettext_lazy as _
from l10n.models import Country
from l10n.utils import moneyfmt
from livesettings import ConfigurationSettings, config_value
from payment.fields import PaymentChoiceCharField
from product.models import Discount, Product, Price, get_product_quantity_adjustments
from product.prices import PriceAdjustmentCalc, PriceAdjustment
from satchmo_store.contact.models import Contact
from satchmo_utils.fields import CurrencyField
from satchmo_utils.numbers import trunc_decimal
from shipping.fields import ShippingChoiceCharField
from tax.utils import get_tax_processor
import datetime
import keyedcache
import logging
import operator
import signals

log = logging.getLogger('satchmo_store.shop.models')

class NullConfig(object):
    """Standin for a real config when we don't have one yet."""

    def __init__(self):
        self.store_name = self.store_description = _("Test Store")
        self.store_email = self.street1 = self.street2 = self.city = self.state = self.postal_code = self.phone = ""
        self.site = self.country = None
        self.in_country_only = True
        self.sales_country = None

    def _options(self):
        return ConfigurationSettings()

    options = property(fget=_options)

    def __str__(self):
        return "Test Store - no configured store exists!"

class ConfigManager(models.Manager):
    def get_current(self, site=None):
        """Convenience method to get the current shop config"""
        if not site:
            site = Site.objects.get_current()

        site = site.id

        try:
            shop_config = keyedcache.cache_get("Config", site)
        except keyedcache.NotCachedError, nce:
            try:
                shop_config = self.get(site__id__exact=site)
                keyedcache.cache_set(nce.key, value=shop_config)
            except Config.DoesNotExist:
                log.warning("No Shop Config found, using test shop config for site=%s.", site)
                shop_config = NullConfig()

        return shop_config

class Config(models.Model):
    """
    Used to store specific information about a store.  Also used to
    configure various store behaviors
    """
    site = models.OneToOneField(Site, verbose_name=_("Site"), primary_key=True)
    store_name = models.CharField(_("Store Name"),max_length=100, unique=True)
    store_description = models.TextField(_("Description"), blank=True, null=True)
    store_email = models.EmailField(_("Email"), blank=True, null=True, max_length=75)
    street1=models.CharField(_("Street"),max_length=50, blank=True, null=True)
    street2=models.CharField(_("Street"), max_length=50, blank=True, null=True)
    city=models.CharField(_("City"), max_length=50, blank=True, null=True)
    state=models.CharField(_("State"), max_length=30, blank=True, null=True)
    postal_code=models.CharField(_("Zip Code"), blank=True, null=True, max_length=9)
    country=models.ForeignKey(Country, blank=False, null=False, verbose_name=_('Country'))
    phone = models.CharField(_("Phone Number"), blank=True, null=True, max_length=30)
    in_country_only = models.BooleanField(
        _("Only sell to in-country customers?"),
        default=True)
    sales_country = models.ForeignKey(
        Country, blank=True, null=True,
        related_name='sales_country',
        verbose_name=_("Default country for customers"))
    shipping_countries = models.ManyToManyField(
        Country,
        blank=True,
        verbose_name=_("Shipping Countries"),
        related_name="shop_configs")

    objects = ConfigManager()

    def _options(self):
        return ConfigurationSettings()

    options = property(fget=_options)

    def areas(self):
        """Get country areas (states/counties).  Used in forms."""
        if self.in_country_only:
            return self.sales_country.adminarea_set.filter(active=True)
        else:
            return None

    def countries(self):
        """Get country selections.  Used in forms."""
        if self.in_country_only:
            return Country.objects.filter(pk=self.sales_country.pk)
        else:
            return self.shipping_countries.filter(active=True)

    def _base_url(self, secure=False):
        prefix = "http"
        if secure:
            prefix += "s"
        return prefix + "://" + self.site.domain

    base_url = property(fget=_base_url)

    def save(self, **kwargs):
        keyedcache.cache_delete("Config", self.site.id)
        # ensure the default country is in shipping countries
        mycountry = self.country

        if mycountry:
            if not self.sales_country:
                log.debug("%s: No sales_country set, adding country of store, '%s'", self, mycountry)
                self.sales_country = mycountry

# This code doesn't work when creating a new site. At the time of creation, all of the necessary relationships
# aren't setup. I modified the load_store code so that it would create this relationship manually when running
# with sample data. This is a bit of a django limitation so I'm leaving this in here for now. - CBM
#            salescountry = self.sales_country
#            try:
#                need = self.shipping_countries.get(pk=salescountry.pk)
#            except Country.DoesNotExist:
#                log.debug("%s: Adding default country '%s' to shipping countries", self, salescountry.iso2_code)
#                self.shipping_countries.add(salescountry)
        else:
            log.warn("%s: has no country set", self)

        super(Config, self).save(**kwargs)
        keyedcache.cache_set("Config", self.site.id, value=self)

    def __unicode__(self):
        return self.store_name

    class Meta:
        verbose_name = _("Store Configuration")
        verbose_name_plural = _("Store Configurations")

class NullCart(object):
    """Standin for a real cart when we don't have one yet.  More convenient than testing for null all the time."""
    desc = None
    date_time_created = None
    customer = None
    total = Decimal("0")
    numItems = 0

    def add_item(self, *args, **kwargs):
        pass

    def remove_item(self, *args, **kwargs):
        pass

    def empty(self):
        pass

    def __str__(self):
        return "NullCart (empty)"

    def __iter__(self):
        return iter([])

    def __len__(self):
        return 0

class OrderCart(NullCart):
    """Allows us to fake a cart if we are reloading an order."""

    def __init__(self, order):
        self._order = order

    def _numItems(self):
        return self._order.orderitem_set.count()

    numItems = property(_numItems)

    def _cartitem_set(self):
        return self._order.orderitem_set

    cartitem_set = property(_cartitem_set)

    def _total(self):
        return self._order.balance

    total = property(_total)

    is_shippable = False

    def __str__(self):
        return "OrderCart (%i) = %i" % (self._order.id, len(self))

    def __len__(self):
        return self.numItems

class CartManager(models.Manager):

    def from_request(self, request, create=False, return_nullcart=True):
        """Get the current cart from the request"""
        cart = None
        try:
            contact = Contact.objects.from_request(request, create=False)
        except Contact.DoesNotExist:
            contact = None

        if 'cart' in request.session:
            cartid = request.session['cart']
            if cartid == "order":
                log.debug("Getting Order Cart from request")
                try:
                    order = Order.objects.from_request(request)
                    cart = OrderCart(order)
                except Order.DoesNotExist:
                    pass

            else:
                try:
                    cart = Cart.objects.get(id=cartid)
                except Cart.DoesNotExist:
                    log.debug('Removing invalid cart from session')
                    del request.session['cart']

        if isinstance(cart, NullCart) and not isinstance(cart, OrderCart) and contact is not None:
            carts = Cart.objects.filter(customer=contact)
            if carts.count() > 0:
                cart = carts[0]
                request.session['cart'] = cart.id

        if not cart:
            if create:
                site = Site.objects.get_current()
                if contact is None:
                    cart = Cart(site=site)
                else:
                    cart = Cart(site=site, customer=contact)
                cart.save()
                request.session['cart'] = cart.id

            elif return_nullcart:
                cart = NullCart()

            else:
                raise Cart.DoesNotExist()

        #log.debug("Cart: %s", cart)
        return cart

class Cart(models.Model):
    """
    Store items currently in a cart
    The desc isn't used but it is needed to make the admin interface work appropriately
    Could be used for debugging
    """
    site = models.ForeignKey(Site, verbose_name=_('Site'))
    desc = models.CharField(_("Description"), blank=True, null=True, max_length=10)
    date_time_created = models.DateTimeField(_("Creation Date"))
    customer = models.ForeignKey(Contact, blank=True, null=True, verbose_name=_('Customer'))

    objects = CartManager()

    def _get_count(self):
        itemCount = 0
        for item in self.cartitem_set.all():
            itemCount += item.quantity
        return (itemCount)
    numItems = property(_get_count)

    def _get_discount(self):
        return self.undiscounted_total - self.total

    discount = property(_get_discount)

    def _get_total(self, include_discount=True):
        total = Decimal("0")
        for item in self.cartitem_set.all():
            if include_discount:
                total += item.line_total
            else:
                total += item.undiscounted_line_total
        return(total)
    total = property(_get_total)

    def _get_undiscounted_total(self):
        return self._get_total(False)

    undiscounted_total = property(_get_undiscounted_total)

    def __iter__(self):
        return iter(self.cartitem_set.all())

    def __len__(self):
        return self.cartitem_set.count()

    def __nonzero__(self):
        """
        This is used by django to evaluate whether or not to
        include an object when dumping data. Therefore, we will dump
        carts even if they have no items. This is ok because the most likely
        scenario is moving data from one db to the next. See ticket #1015 for
        discussion.

        Use len(cart) if you want to know if there are items in the cart.
        """
        return True

    def _is_empty(self):
        return self.cartitem_set.count() == 0
    is_empty = property(_is_empty)

    def __unicode__(self):
        return u"Shopping Cart (%s)" % self.date_time_created

    def add_item(self, chosen_item, number_added, details=[]):
        alreadyInCart = False
        # Custom Products will not be added, they will each get their own line item
        if 'CustomProduct' in chosen_item.get_subtypes():
            item_to_modify = CartItem(cart=self, product=chosen_item, quantity=Decimal('0'))
        else:
            item_to_modify = CartItem(cart=self, product=chosen_item, quantity=Decimal('0'))
            for similarItem in self.cartitem_set.filter(product__id = chosen_item.id):
                looksTheSame = len(details) == similarItem.details.count()
                if looksTheSame:
                    for detail in details:
                        try:
                            similarItem.details.get(
                                    name=detail['name'],
                                    value=str(detail['value']),     # typecasting for Postgresql
                                    price_change=detail['price_change']
                                    )
                        except CartItemDetails.DoesNotExist:
                            looksTheSame = False
                if looksTheSame:
                    item_to_modify = similarItem
                    alreadyInCart = True
                    break

        # Verify that the 'item_to_modify' can be added to the cart regardless
        # of whether or not it is already in the cart
        signals.satchmo_cart_add_verify.send(
            self,
            cart=self,
            cartitem=item_to_modify,
            added_quantity=number_added,
            details=details)

        if not alreadyInCart:
            self.cartitem_set.add(item_to_modify)

        item_to_modify.quantity += number_added
        item_to_modify.save()
        if not alreadyInCart:
            for data in details:
                item_to_modify.add_detail(data)

        return item_to_modify

    def remove_item(self, chosen_item_id, number_removed):
        item_to_modify = self.cartitem_set.get(id = chosen_item_id)
        item_to_modify.quantity -= number_removed
        if item_to_modify.quantity <= 0:
            item_to_modify.delete()
        else:
            item_to_modify.save()

    def merge_carts(self, src_cart):
        """
        Merge the items from the src_cart into
        the destination. Source cart will be emptied
        """
        for item in src_cart.cartitem_set.all():
            self.add_item(item.product, item.quantity, item.details.all())
            item.delete()
        self.save()

    def empty(self):
        for item in self.cartitem_set.all():
            item.delete()
        self.save()

    def save(self, **kwargs):
        """Ensure we have a date_time_created before saving the first time."""
        if not self.pk:
            self.date_time_created = datetime.datetime.now()
        try:
            site = self.site
        except Site.DoesNotExist:
            self.site = Site.objects.get_current()
        super(Cart, self).save(**kwargs)

    def _get_shippable(self):
        """Return whether the cart contains shippable items."""
        for cartitem in self.cartitem_set.all():
            if cartitem.is_shippable:
                return True
        return False
    is_shippable = property(_get_shippable)

    def get_shipment_list(self):
        """Return a list of shippable products, where each item is split into
        multiple elements, one for each quantity."""
        items = []
        for cartitem in self.cartitem_set.all():
            if cartitem.is_shippable:
                p = cartitem.product
                q =  int(cartitem.quantity.quantize(Decimal('0'), ROUND_CEILING))
                for single in range(0, q):
                    items.append(p)
        return items

    class Meta:
        verbose_name = _("Shopping Cart")
        verbose_name_plural = _("Shopping Carts")

class NullCartItem(object):
    def __init__(self, itemid):
        self.id = itemid
        self.quantity = Decimal('0')
        self.line_total = 0

class CartItem(models.Model):
    """
    An individual item in the cart
    """
    cart = models.ForeignKey(Cart, verbose_name=_('Cart'))
    product = models.ForeignKey(Product, verbose_name=_('Product'))
    quantity = models.DecimalField(_("Quantity"),  max_digits=18,  decimal_places=6)

    def _get_line_unitprice(self, include_discount=True):
        # Get the qty discount price as the unit price for the line.

        if config_value('SHOP','CART_QTY'):
            qty = self.cart.numItems
        else:
            qty = self.quantity

        self.qty_price = self.get_qty_price(qty, include_discount=include_discount)

        self.detail_price = self.get_detail_price()
        #send signal to possibly adjust the unitprice
        if include_discount:
            signals.satchmo_cartitem_price_query.send(self, cartitem=self)
        price = self.qty_price + self.detail_price

        #clean up temp vars
        del self.qty_price
        del self.detail_price

        return price

    unit_price = property(_get_line_unitprice)

    def _get_undiscounted_unitprice(self):
        return self._get_line_unitprice(include_discount=False)

    undiscounted_unit_price = property(_get_undiscounted_unitprice)

    def get_detail_price(self):
        """Get the delta price based on detail modifications"""
        delta = Decimal("0")
        if self.has_details:
            for detail in self.details.all():
                if detail.price_change and detail.value:
                    delta += detail.price_change
        return delta

    def get_qty_price(self, qty, include_discount=True):
        """Get the price for for each unit before any detail modifications"""
        return self.product.get_qty_price(qty, include_discount=include_discount)

    def _get_line_total(self):
        return self.unit_price * self.quantity
    line_total = property(_get_line_total)

    def _get_undiscounted_line_total(self):
        return self.undiscounted_unit_price * self.quantity

    undiscounted_line_total = property(_get_undiscounted_line_total)

    def _get_description(self):
        return self.product.translated_name()
    description = property(_get_description)

    def _is_shippable(self):
        return self.product.is_shippable

    is_shippable = property(fget=_is_shippable)

    def add_detail(self, data):
        detl = CartItemDetails(
            cartitem=self,
            name=data['name'],
            value=data['value'],
            sort_order=data['sort_order'],
            price_change=data['price_change'])

        detl.save()
        #self.details.add(detl)

    def _has_details(self):
        """
        Determine if this specific item has more detail
        """
        return (self.details.count() > 0)

    has_details = property(_has_details)

    def __unicode__(self):
        money_format = force_unicode(moneyfmt(self.line_total))
        return u'%s - %s %s' % (self.quantity, self.product.name,
            money_format)

    class Meta:
        verbose_name = _("Cart Item")
        verbose_name_plural = _("Cart Items")
        ordering = ('id',)

class CartItemDetails(models.Model):
    """
    An arbitrary detail about a cart item.
    """
    cartitem = models.ForeignKey(CartItem, related_name='details', )
    value = models.TextField(_('detail'))
    name = models.CharField(_('name'), max_length=100)
    price_change = CurrencyField(_("Item Detail Price Change"), max_digits=6,
        decimal_places=2, blank=True, null=True)
    sort_order = models.IntegerField(_("Sort Order"),
        help_text=_("The display order for this group."))

    class Meta:
        ordering = ('sort_order',)
        verbose_name = _("Cart Item Detail")
        verbose_name_plural = _("Cart Item Details")

ORDER_CHOICES = (
    ('Online', _('Online')),
    ('In Person', _('In Person')),
    ('Show', _('Show')),
)

ORDER_STATUS = (
    ('Temp', _('Temp')),
    ('New', _('New')),
    ('Blocked', _('Blocked')),
    ('In Process', _('In Process')),
    ('Billed', _('Billed')),
    ('Shipped', _('Shipped')),
    ('Complete', _('Complete')),
    ('Cancelled', _('Cancelled')),
)

class OrderManager(models.Manager):
    def from_request(self, request):
        """Get the order from the session

        Returns:
        - Order object
        """
        order = None
        if 'orderID' in request.session:
            try:
                order = Order.objects.get(id=request.session['orderID'])
                # TODO: Validate against logged-in user.
            except Order.DoesNotExist:
                pass

            if not order:
                del request.session['orderID']

        if not order:
            raise Order.DoesNotExist()

        return order

    def remove_partial_order(self, request):
        """Delete cart from request if it exists and is incomplete (has no status)"""
        try:
            order = Order.objects.from_request(request)
            if not order.status:
                del request.session['orderID']
                log.info("Deleting incomplete order #%i from database", order.id)
                order.delete()
                return True
        except Order.DoesNotExist:
            pass
        return False

class Order(models.Model):
    """
    Orders contain a copy of all the information at the time the order was
    placed.
    """
    site = models.ForeignKey(Site, verbose_name=_('Site'))
    contact = models.ForeignKey(Contact, verbose_name=_('Contact'))
    ship_addressee = models.CharField(_("Addressee"), max_length=61, blank=True)
    ship_street1 = models.CharField(_("Street"), max_length=80, blank=True)
    ship_street2 = models.CharField(_("Street"), max_length=80, blank=True)
    ship_city = models.CharField(_("City"), max_length=50, blank=True)
    ship_state = models.CharField(_("State"), max_length=50, blank=True)
    ship_postal_code = models.CharField(_("Zip Code"), max_length=30, blank=True)
    ship_country = models.CharField(_("Country"), max_length=2, blank=True)
    bill_addressee = models.CharField(_("Addressee"), max_length=61, blank=True)
    bill_street1 = models.CharField(_("Street"), max_length=80, blank=True)
    bill_street2 = models.CharField(_("Street"), max_length=80, blank=True)
    bill_city = models.CharField(_("City"), max_length=50, blank=True)
    bill_state = models.CharField(_("State"), max_length=50, blank=True)
    bill_postal_code = models.CharField(_("Zip Code"), max_length=30, blank=True)
    bill_country = models.CharField(_("Country"), max_length=2, blank=True)
    notes = models.TextField(_("Notes"), blank=True, null=True)
    sub_total = CurrencyField(_("Subtotal"),
        max_digits=18, decimal_places=10, blank=True, null=True, display_decimal=4)
    total = CurrencyField(_("Total"),
        max_digits=18, decimal_places=10, blank=True, null=True, display_decimal=4)
    discount_code = models.CharField(
        _("Discount Code"), max_length=20, blank=True, null=True,
        help_text=_("Coupon Code"))
    discount = CurrencyField(_("Discount amount"),
        max_digits=18, decimal_places=10, blank=True, null=True)
    method = models.CharField(_("Order method"),
        choices=ORDER_CHOICES, max_length=50, blank=True)
    shipping_description = models.CharField(_("Shipping Description"),
        max_length=50, blank=True, null=True)
    shipping_method = models.CharField(_("Shipping Method"),
        max_length=50, blank=True, null=True)
    shipping_model = ShippingChoiceCharField(_("Shipping Models"),
        max_length=30, blank=True, null=True)
    shipping_cost = CurrencyField(_("Shipping Cost"),
        max_digits=18, decimal_places=10, blank=True, null=True)
    shipping_discount = CurrencyField(_("Shipping Discount"),
        max_digits=18, decimal_places=10, blank=True, null=True)
    tax = CurrencyField(_("Tax"),
        max_digits=18, decimal_places=10, blank=True, null=True)
    time_stamp = models.DateTimeField(_("Timestamp"), blank=True, null=True)
    status = models.CharField(_("Status"), max_length=20, choices=ORDER_STATUS,
        blank=True, help_text=_("This is set automatically."))

    objects = OrderManager()

    def __unicode__(self):
        return "Order #%s: %s" % (self.id, self.contact.full_name)

    def add_status(self, status=None, notes=""):
        orderstatus = OrderStatus()
        if not status:
            try:
                curr_status = self.orderstatus_set.latest()
                status = curr_status.status
            except OrderStatus.DoesNotExist:
                status = 'New'

        orderstatus.status = status
        orderstatus.notes = notes
        orderstatus.order = self
        orderstatus.save()

    def add_variable(self, key, value):
        """Add an OrderVariable, used for misc stuff that is just too small to get its own field"""
        try:
            v = self.variables.get(key__exact=key)
            v.value = value
        except OrderVariable.DoesNotExist:
            v = OrderVariable(order=self, key=key, value=value)
        v.save()

    def _authorized_remaining(self):
        auths = [p.amount for p in self.authorizations.filter(complete=False)]
        if auths:
            amount = reduce(operator.add, auths)
        else:
            amount = Decimal('0.00')

        return amount

    authorized_remaining = property(fget=_authorized_remaining)

    def _get_count(self):
        itemCount = 0
        for item in self.orderitem_set.all():
            itemCount += item.quantity
        return (itemCount)
    numItems = property(_get_count)

    def get_variable(self, key, default=None):
        qry = self.variables.filter(key__exact=key)
        ct = qry.count()
        if ct == 0:
            return default
        else:
            return qry[0]

    def copy_addresses(self):
        """
        Copy the addresses so we know what the information was at time of order.
        """
        shipaddress = self.contact.shipping_address
        billaddress = self.contact.billing_address
        self.ship_addressee = shipaddress.addressee
        self.ship_street1 = shipaddress.street1
        self.ship_street2 = shipaddress.street2
        self.ship_city = shipaddress.city
        self.ship_state = shipaddress.state
        self.ship_postal_code = shipaddress.postal_code
        self.ship_country = shipaddress.country.iso2_code
        self.bill_addressee = billaddress.addressee
        self.bill_street1 = billaddress.street1
        self.bill_street2 = billaddress.street2
        self.bill_city = billaddress.city
        self.bill_state = billaddress.state
        self.bill_postal_code = billaddress.postal_code
        self.bill_country = billaddress.country.iso2_code

    def remove_all_items(self):
        """Delete all items belonging to this order."""
        for item in self.orderitem_set.all():
            item.delete()
        self.save()

    def _balance(self):
        if self.total is None:
            self.force_recalculate_total(save=True)
        return trunc_decimal(self.total-self.balance_paid, 2)

    balance = property(fget=_balance)

    def balance_forward(self):
        return moneyfmt(self.balance)

    balance_forward = property(fget=balance_forward)

    def _balance_paid(self):
        payments = [p.amount for p in self.payments.all()]
        if payments:
            paid = reduce(operator.add, payments)
        else:
            paid = Decimal("0.0000000000")

        return paid + self.authorized_remaining

    balance_paid = property(_balance_paid)

    def _credit_card(self):
        """Return the credit card associated with this payment."""
        from payment.models import CreditCardDetail
        for payment in self.payments.order_by('-time_stamp'):
            try:
                if payment.creditcards.count() > 0:
                    return payment.creditcards.get()
            except CreditCardDetail.DoesNotExist:
                pass
        return None
    credit_card = property(_credit_card)

    def _full_bill_street(self, delim="\n"):
        """
        Return both billing street entries separated by delim.
        Note - Use linebreaksbr filter to convert to html in templates.
        """
        if self.bill_street2:
            address = self.bill_street1 + delim + self.bill_street2
        else:
            address = self.bill_street1
        return mark_safe(address)
    full_bill_street = property(_full_bill_street)

    def _full_ship_street(self, delim="\n"):
        """
        Return both shipping street entries separated by delim.
        Note - Use linebreaksbr filterto convert to html in templates.
        """
        if self.ship_street2:
            address = self.ship_street1 + delim + self.ship_street2
        else:
            address = self.ship_street1
        return mark_safe(address)
    full_ship_street = property(_full_ship_street)

    def _ship_country_name(self):
        return Country.objects.get(iso2_code=self.ship_country).name
    ship_country_name = property(_ship_country_name)

    def _bill_country_name(self):
        return Country.objects.get(iso2_code=self.bill_country).name
    bill_country_name = property(_bill_country_name)

    def _ship_first_name(self):
        """Given the addressee name, try to return a first name"""
        return ' '.join(self.ship_addressee.split()[0:-1]) or ''
    ship_first_name = property(_ship_first_name)

    def _ship_last_name(self):
        """Given the addressee name, try to return a last name"""
        return ' '.join(self.ship_addressee.split()[-1:]) or ''
    ship_last_name = property(_ship_last_name)

    def _discounted_sub_total(self):
        return self.sub_total - self.item_discount

    discounted_sub_total = property(_discounted_sub_total)

    def _get_balance_remaining_url(self):
        return ('satchmo_balance_remaining_order', None, {'order_id' : self.id})
    get_balance_remaining_url = models.permalink(_get_balance_remaining_url)

    def _partially_paid(self):
        return self.balance_paid > Decimal("0.0000000000")

    partially_paid = property(_partially_paid)

    def _is_partially_paid(self):
        if self.total:
            return (
                float(self.balance) > 0.0
                and float(self.balance_paid) > 0.0
                and self.balance != self.balance_paid
                )
        else:
            return False

    is_partially_paid = property(fget=_is_partially_paid)

    def payments_completed(self):
        q = self.payments.exclude(transaction_id__isnull = False, transaction_id = "PENDING")
        result = [p for p in q if p.amount]
        return result

    def save(self, **kwargs):
        """
        Copy addresses from contact. If the order has just been created, set
        the create_date.
        """
        if not self.pk:
            self.time_stamp = datetime.datetime.now()
            self.copy_addresses()
        super(Order, self).save(**kwargs) # Call the "real" save() method.

    def invoice(self):
        url = urlresolvers.reverse('satchmo_print_shipping', None, None, {'doc' : 'invoice', 'id' : self.id})
        return mark_safe(u'<a href="%s">%s</a>' % (url, ugettext('View')))
    invoice.allow_tags = True

    def _item_discount(self):
        """Get the discount of just the items, less the shipping discount."""
        return self.discount-self.shipping_discount
    item_discount = property(_item_discount)

    def packingslip(self):
        url = urlresolvers.reverse('satchmo_print_shipping', None, None, {'doc' : 'packingslip', 'id' : self.id})
        return mark_safe(u'<a href="%s">%s</a>' % (url, ugettext('View')))
    packingslip.allow_tags = True

    def recalculate_total(self, save=True):
        """Calculates sub_total, taxes and total if the order is not already partially paid."""
        if self.is_partially_paid:
            log.debug("Order %i - skipping recalculate_total since product is partially paid.", self.id)
        else:
            self.force_recalculate_total(save=save)

    def force_recalculate_total(self, save=True):
        """Calculates sub_total, taxes and total."""
        zero = Decimal("0.0000000000")
        total_discount = Decimal("0.0000000000")

        discount = Discount.objects.by_code(self.discount_code)
        discount.calc(self)

        discounts = discount.item_discounts
        itemprices = []
        fullprices = []

        qty_override = config_value('SHOP','CART_QTY')
        if qty_override:
            itemct = self.numItems

        for lineitem in self.orderitem_set.all():
            lid = lineitem.id
            if lid in discounts:
                lineitem.discount = discounts[lid]
                total_discount += lineitem.discount
                #log.debug('total_discount (calc): %s', total_discount)
            else:
                lineitem.discount = zero
            # now double check against other discounts, such as tiered discounts
            if qty_override:
                qty = itemct
            else:
                qty = lineitem.quantity

            adjustment = get_product_quantity_adjustments(lineitem.product, qty=qty)

            if adjustment and adjustment.price:
                baseprice = adjustment.price.price
                finalprice = adjustment.final_price()
                #We need to add in any OrderItemDetail price adjustments before we do anything else
                baseprice += lineitem.get_detail_price()
                finalprice += lineitem.get_detail_price()
                if baseprice > finalprice or baseprice != lineitem.unit_price:
                    unitdiscount = (lineitem.discount/lineitem.quantity) + baseprice-finalprice
                    unitdiscount = trunc_decimal(unitdiscount, 2)
                    linediscount = unitdiscount * lineitem.quantity
                    total_discount += linediscount
                    #log.debug('total_discount (line): %s', total_discount)
                    fullydiscounted = (baseprice - unitdiscount) * lineitem.quantity
                    lineitem.unit_price = baseprice
                    lineitem.discount = linediscount
                    lineitem.line_item_price = baseprice * lineitem.quantity
                    log.debug('Adjusting lineitem unit price for %s. Full price=%s, discount=%s.  Final price for qty %d is %s',
                        lineitem.product.slug, baseprice, unitdiscount, lineitem.quantity, fullydiscounted)
            if save:
                lineitem.save()

            itemprices.append(lineitem.sub_total)
            fullprices.append(lineitem.line_item_price)

        shipprice = Price()
        shipprice.price = self.shipping_cost
        shipadjust = PriceAdjustmentCalc(shipprice)
        if 'Shipping' in discounts:
            shipadjust += PriceAdjustment('discount', _('Discount'), discounts['Shipping'])

        signals.satchmo_shipping_price_query.send(self, adjustment=shipadjust)
        shipdiscount = shipadjust.total_adjustment()
        self.shipping_discount = shipdiscount
        total_discount += shipdiscount
        #log.debug('total_discount (+ship): %s', total_discount)

        self.discount = total_discount

        if itemprices:
            item_sub_total = reduce(operator.add, itemprices)
        else:
            item_sub_total = zero

        if fullprices:
            full_sub_total = reduce(operator.add, fullprices)
        else:
            full_sub_total = zero

        self.sub_total = full_sub_total

        taxProcessor = get_tax_processor(self)
        totaltax, taxrates = taxProcessor.process()
        self.tax = totaltax

        # clear old taxes
        for taxdetl in self.taxes.all():
            taxdetl.delete()

        for taxdesc, taxamt in taxrates.items():
            taxdetl = OrderTaxDetail(order=self, tax=taxamt, description=taxdesc, method=taxProcessor.method)
            taxdetl.save()

        log.debug("Order #%i, recalc: sub_total=%s, shipping=%s, discount=%s, tax=%s",
            self.id,
            moneyfmt(item_sub_total),
            moneyfmt(self.shipping_sub_total),
            moneyfmt(self.discount),
            moneyfmt(self.tax))

        self.total = Decimal(item_sub_total + self.shipping_sub_total + self.tax)

        if save:
            self.save()

    def shippinglabel(self):
        url = urlresolvers.reverse('satchmo_print_shipping', None, None, {'doc' : 'shippinglabel', 'id' : self.id})
        return mark_safe(u'<a href="%s">%s</a>' % (url, ugettext('View')))
    shippinglabel.allow_tags = True

    def _order_total(self):
        #Needed for the admin list display
        return moneyfmt(self.total)
    order_total = property(_order_total)

    def order_success(self):
        """Run each item's order_success method."""
        log.info("Order success: %s", self)
        for orderitem in self.orderitem_set.all():
            subtype = orderitem.product.get_subtype_with_attr('order_success')
            if subtype:
                subtype.order_success(self, orderitem)

        signals.order_success.send(self, order=self)

    def order_cancel(self):
        """Ask if the order can be cancelled. By default, do not cancel shipped, completed and
        already cancelled orders."""
        self.is_cancellable = self.status not in ('Shipped', 'Completed', 'Cancelled')
        # listeners can override default flag setting and (dis)allow cancellation
        signals.order_cancel_query.send(self, order=self)
        if self.is_cancellable:
           self.add_status('Cancelled')
           signals.order_cancelled.send(self, order=self)
        return self.is_cancellable

    def _paid_in_full(self):
        """True if total has been paid"""
        return self.balance == Decimal('0.00')
    paid_in_full = property(fget=_paid_in_full)

    def _has_downloads(self):
        """Determine if there are any downloadable products on this order"""
        if 'product.modules.downloadable' in settings.INSTALLED_APPS \
            and self.downloadlink_set.count() > 0:
            return True
        return False
    has_downloads = property(_has_downloads)

    def _is_downloadable(self):
        """Determine if all products on this order are downloadable"""
        for orderitem in self.orderitem_set.all():
           if not orderitem.product.is_downloadable:
               return False
        return True
    is_downloadable = property(_is_downloadable)

    def _is_shippable(self):
        """Determine if we will be shipping any items on this order """
        for orderitem in self.orderitem_set.all():
            if orderitem.is_shippable:
                return True
        return False
    is_shippable = property(_is_shippable)

    def _shipping_sub_total(self):
        if self.shipping_cost is None:
            self.shipping_cost = Decimal('0.00')
        if self.shipping_discount is None:
            self.shipping_discount = Decimal('0.00')
        return self.shipping_cost-self.shipping_discount
    shipping_sub_total = property(_shipping_sub_total)

    def _shipping_tax(self):
        rates = self.taxes.filter(description__iexact = 'shipping')
        if rates.count()>0:
            tax = reduce(operator.add, [t.tax for t in rates])
        else:
            tax = Decimal("0.0000000000")
        return tax
    shipping_tax = property(_shipping_tax)

    def _shipping_with_tax(self):
        return self.shipping_sub_total + self.shipping_tax
    shipping_with_tax = property(_shipping_with_tax)

    def sub_total_with_tax(self):
        return reduce(operator.add, [o.total_with_tax for o in self.orderitem_set.all()])

    def update_status(self, status):
        """WARNING: To just change order status, use Order.add_status().
        This method is called back when OrderStatus is saved and does not create required object."""
        oldstatus = self.status
        self.status = status
        self.save()
        if (oldstatus != self.status):
            signals.satchmo_order_status_changed.send(self, oldstatus=oldstatus, newstatus=status, order=self)

    def validate(self, request):
        """
        Return whether the order is valid.
        Not guaranteed to be side-effect free.
        """
        valid = True
        for orderitem in self.orderitem_set.all():
            for subtype_name in orderitem.product.get_subtypes():
                subtype = getattr(orderitem.product, subtype_name.lower())
                validate_method = getattr(subtype, 'validate_order', None)
                if validate_method:
                    valid = valid and validate_method(request, self, orderitem)
        return valid

    class Meta:
        verbose_name = _("Product Order")
        verbose_name_plural = _("Product Orders")

class OrderItem(models.Model):
    """
    A line item on an order.
    """
    order = models.ForeignKey(Order, verbose_name=_("Order"))
    product = models.ForeignKey(Product, verbose_name=_("Product"))
    quantity = models.DecimalField(_("Quantity"),  max_digits=18,  decimal_places=6)
    unit_price = CurrencyField(_("Unit price"),
        max_digits=18, decimal_places=10)
    unit_tax = CurrencyField(_("Unit tax"), default=Decimal('0.00'),
        max_digits=18, decimal_places=10)
    line_item_price = CurrencyField(_("Line item price"),
        max_digits=18, decimal_places=10)
    tax = CurrencyField(_("Line item tax"), default=Decimal('0.00'),
        max_digits=18, decimal_places=10)
    expire_date = models.DateField(_("Subscription End"), help_text=_("Subscription expiration date."), blank=True, null=True)
    completed = models.BooleanField(_("Completed"), default=False)
    discount = CurrencyField(_("Line item discount"),
        max_digits=18, decimal_places=10, blank=True, null=True)

    def __unicode__(self):
        return self.product.translated_name()

    def _get_category(self):
        return(self.product.get_category.translated_name())
    category = property(_get_category)

    def _is_shippable(self):
        return self.product.is_shippable

    is_shippable = property(fget=_is_shippable)

    def _has_details(self):
        """Determine if this specific item has more detail"""
        return (self.orderitemdetail_set.count() > 0)

    has_details = property(_has_details)

    def get_detail_price(self):
        """Get the delta price based on detail modifications"""
        delta = Decimal("0.000000")
        if self.has_details:
            for detail in self.orderitemdetail_set.all():
                if detail.price_change and detail.value:
                    delta += detail.price_change
        return delta

    def _sub_total(self):
        if self.discount:
            return self.line_item_price-self.discount
        else:
            return self.line_item_price
    sub_total = property(_sub_total)

    def _total_with_tax(self):
        return self.sub_total + self.tax
    total_with_tax = property(_total_with_tax)

    def _unit_price_with_tax(self):
        return self.unit_price + self.unit_tax
    unit_price_with_tax = property(_unit_price_with_tax)

    def _get_description(self):
        return self.product.translated_name()
    description = property(_get_description)

    def _get_line_total(self):
        return self.unit_price * self.quantity
    line_total = property(_get_line_total)

    def save(self, **kwargs):
        self.update_tax()
        super(OrderItem, self).save(**kwargs)

    def update_tax(self):
        taxclass = self.product.taxClass
        processor = get_tax_processor(order=self.order)

        if self.product.taxable:
            self.unit_tax = processor.by_price(taxclass, self.unit_price)
            self.tax = processor.by_orderitem(self)

    class Meta:
        verbose_name = _("Order Line Item")
        verbose_name_plural = _("Order Line Items")
        ordering = ('id',)

class OrderItemDetail(models.Model):
    """
    Name, value pair and price delta associated with a specific item in an order
    """
    item = models.ForeignKey(OrderItem, verbose_name=_("Order Item"), )
    name = models.CharField(_('Name'), max_length=100)
    value = models.CharField(_('Value'), max_length=255)
    price_change = CurrencyField(_("Price Change"), max_digits=18, decimal_places=10, blank=True, null=True)
    sort_order = models.IntegerField(_("Sort Order"),
        help_text=_("The display order for this group."))

    def __unicode__(self):
        return u"%s - %s,%s" % (self.item, self.name, self.value)

    class Meta:
        verbose_name = _("Order Item Detail")
        verbose_name_plural = _("Order Item Details")
        ordering = ('sort_order',)

class OrderStatus(models.Model):
    """
    An order will have multiple statuses as it moves its way through processing.
    """
    order = models.ForeignKey(Order, verbose_name=_("Order"))
    status = models.CharField(_("Status"),
        max_length=20, choices=ORDER_STATUS, blank=True)
    notes = models.CharField(_("Notes"), max_length=100, blank=True)
    time_stamp = models.DateTimeField(_("Timestamp"))

    def __unicode__(self):
        return self.status

    def save(self, **kwargs):
        if not self.pk and not self.time_stamp:
            self.time_stamp = datetime.datetime.now()
        super(OrderStatus, self).save(**kwargs)
        self.order.update_status(self.status)

    class Meta:
        verbose_name = _("Order Status")
        verbose_name_plural = _("Order Statuses")
        ordering = ('time_stamp',)
        get_latest_by = 'time_stamp'

class OrderPaymentBase(models.Model):
    payment = PaymentChoiceCharField(_("Payment Method"),
        max_length=25, blank=True)
    amount = CurrencyField(_("amount"),
        max_digits=18, decimal_places=10, blank=True, null=True)
    time_stamp = models.DateTimeField(_("timestamp"), blank=True, null=True)
    transaction_id = models.CharField(_("Transaction ID"), max_length=45, blank=True, null=True)
    details = models.CharField(_("Details"), max_length=255, blank=True, null=True)
    reason_code = models.CharField(_('Reason Code'),  max_length=255, blank=True, null=True)

    def _credit_card(self):
        """Return the credit card associated with this payment."""
        try:
            return self.creditcards.get()
        except self.creditcards.model.DoesNotExist:
            return None
    credit_card = property(_credit_card)

    def _amount_total(self):
        return moneyfmt(self.amount)

    amount_total = property(fget=_amount_total)

    def save(self, **kwargs):
        if not self.pk:
            self.time_stamp = datetime.datetime.now()

        super(OrderPaymentBase, self).save(**kwargs)

    class Meta:
        abstract = True

class OrderAuthorization(OrderPaymentBase):
    order = models.ForeignKey(Order, related_name="authorizations")
    capture = models.ForeignKey('OrderPayment', related_name="authorizations")
    complete = models.BooleanField(_('Complete'), default=False)

    def __unicode__(self):
        if self.id is not None:
            return u"Order Authorization #%i" % self.id
        else:
            return u"Order Authorization (unsaved)"

    def remaining(self):
        payments = [p.amount for p in self.order.payments.all()]
        if payments:
            amount = reduce(operator.add, payments)
        else:
            amount = Decimal('0.00')

        remaining = self.order.total - amount
        if remaining > self.amount:
            remaining = self.amount

        return trunc_decimal(remaining, 2)

    def save(self, **kwargs):
        # create linked payment
        try:
            capture = self.capture
        except OrderPayment.DoesNotExist:
            log.debug('Payment Authorization - creating linked payment')
            log.debug('order is: %s', self.order)
            self.capture = OrderPayment.objects.create_linked(self)
        super(OrderPaymentBase, self).save(**kwargs)

    class Meta:
        verbose_name = _("Order Payment Authorization")
        verbose_name_plural = _("Order Payment Authorizations")

class OrderPaymentManager(models.Manager):
    def create_linked(self, other, **kwargs):
        linked = OrderPayment(
                order = other.order,
                payment = other.payment,
                amount=Decimal('0.00'),
                transaction_id="LINKED",
                details=other.details,
                reason_code="")
        linked.save(**kwargs)
        return linked

class OrderPayment(OrderPaymentBase):
    order = models.ForeignKey(Order, related_name="payments")

    objects = OrderPaymentManager()

    def __unicode__(self):
        if self.id is not None:
            return u"Order Payment #%i" % self.id
        else:
            return u"Order Payment (unsaved)"

    class Meta:
        verbose_name = _("Order Payment")
        verbose_name_plural = _("Order Payments")

class OrderPendingPayment(OrderPaymentBase):
    order = models.ForeignKey(Order, related_name="pendingpayments")
    capture = models.ForeignKey('OrderPayment', related_name="pendingpayments")

    def __unicode__(self):
        if self.id is not None:
            return u"Order Pending Payment #%i" % self.id
        else:
            return u"Order Pending Payment (unsaved)"

    def save(self, **kwargs):
        # create linked payment
        try:
            capture = self.capture
        except OrderPayment.DoesNotExist:
            log.debug('Pending Payment - creating linked payment')
            self.capture = OrderPayment.objects.create_linked(self, **kwargs)
        super(OrderPaymentBase, self).save(**kwargs)

    class Meta:
        verbose_name = _("Order Pending Payment")
        verbose_name_plural = _("Order Pending Payments")

class OrderPaymentFailure(OrderPaymentBase):
    order = models.ForeignKey(Order, null=True, blank=True, related_name='paymentfailures')

class OrderVariable(models.Model):
    order = models.ForeignKey(Order, related_name="variables")
    key = models.SlugField(_('key'), )
    value = models.CharField(_('value'), max_length=100)

    class Meta:
        ordering=('key',)
        verbose_name = _("Order variable")
        verbose_name_plural = _("Order variables")

    def __unicode__(self):
        if len(self.value)>10:
            v = self.value[:10] + '...'
        else:
            v = self.value
        return u"OrderVariable: %s=%s" % (self.key, v)

class OrderTaxDetail(models.Model):
    """A tax line item"""
    order = models.ForeignKey(Order, related_name="taxes")
    method = models.CharField(_("Model"), max_length=50, )
    description = models.CharField(_("Description"), max_length=50, blank=True)
    tax = CurrencyField(_("Tax"),
        max_digits=18, decimal_places=10, blank=True, null=True)

    def __unicode__(self):
        if self.description:
            return u"Tax: %s %s" % (self.description, self.tax)
        else:
            return u"Tax: %s" % self.tax

    class Meta:
        verbose_name = _('Order tax detail')
        verbose_name_plural = _('Order tax details')
        ordering = ('id',)

import config

import listeners
listeners.start_default_listening()

redpajama_set_name: RedPajamaGithub


We are looking for an administrator to work for a public sector client based in Sutton.
The role will involve pulling files and updating information on an inhouse database on which full training will be given. You will have good Word and Excel skills although most of the work will be on the inhouse database. This role will involve some manual handling as there are lots of files to be updated.
Ideally you will have some basic office experience, be willing to learn and keen to commit to at least 6 months temporary work.


During my upcoming CPE Residency – a 9-month hospital chaplaincy – the cross I wear every day around my neck will remain tucked under my shirt, at the urging of my supervisor. "We are here to serve people of all faiths, and it is best that we not wear our religious affiliation on our sleeves," he said.
I have mixed feelings about this. On one hand, I am glad to tuck my cross under my shirt and present myself to hospital patients and staff as a chaplain serving all members of the hospital community, regardless of their faith (or lack of faith). Indeed, overtly religious jewelry or clothing – such as my necklace or a clerical collar – can be a turn-off and impediment for non-Christians or to Christians from other traditions. Thus we chaplains are instructed to dress professionally – a shirt and tie for the men (which pretty much puts the cross under the shirt, anyway) – and let our words and actions, not clothing and symbols, define our role and work with the hospital community.
I see the value in shying away from overt religious symbols in a multi-faith setting, but I wonder if this instruction to shed religious symbols is not based on a well-intentioned but flawed belief that we can somehow be all things to all people. I don't want to belabor or exaggerate this point, for I believe that in most situations I will be able to provide some level of spiritual or emotional comfort. But the truth is that I cannot serve all the people in my hospital. I cannot be all things to all people. I can be pretty flexible, and I will listen to and console most anyone who is in grief or pain. Yet I come to ministry from a particular perspective – cultural, socio-economic, and of course, religious – and these undeniable factors shade how I carry out the ministry of care and comfort to those who suffer. My patients also have their own experiences and perspectives, shading how they understand suffering, faith, God, life. I can approach each patient intending to provide the spiritual comfort they need, or I can approach each patient with an honesty and humility that recognizes that I may not have what this person needs.
As I said, I don't want to belabor this point, but whether in rituals (Hebrew prayers or Catholic sacraments) or in theology (does God suffer along side the patient, or is God powerful and in control?) or in many other ways, there will be times when what I bring to the table won't feed the patient. Nonetheless, I believe that God can work through me – even through my particularity – to bring a modicum of comfort to those who suffer. At least, I pray that this is the case, or its going to be a long 9 months . . .
I deleted the long comment I was writing and will post on it instead.
The nine months will go by before you know it. The best part of CPE is that you will learn more about yourself than you ever thought possible.
Well, what manner of chaplain are you? Were you accepted into the residency as an interfaith chaplain? If you were ordained and doing this residency, would you be allowed to wear a collar, as is normative for ordained folks in our tradition?
Symbols mean things, and to have you conceal the wearing of a cross that marks you publicly does make me wonder if they will ask you to conceal anything else. The logic does somehow seemed flawed and informed by a theology and hermeneutic that do not seem helpful. If I were in the hospital, and called for a chaplain, I would want to know for certain that he or she were Christian, crosses and all.
Sorry, just the clerical collar thing in the post.
LZ, I've been a professional chaplain for 25 years, and Board Certified for 15 (APC, for what it's worth). I have always had some question about the model your supervisor and your department seem to have adopted. Now, I've known situations in which students were encouraged to try the unexpected to see what they learned. That's particularly true about religious symbols. We are called to experience and reflect the authority of God working in us, and not in the collar or the cross we wear. There have always been those students who thought it was the collar or the cross that gave the authority. Sooner or later they either learned otherwise or were lost in the tool. Granted, it's hard to stay that lost through three units….
I encourage my staff to provide a spiritually safe place for patients and their families, and to realize that in their crises they are more vulnerable. I don't think that we deny our identity in that context, but we may go well out of our way to be hospitable, even at some cost to ourselves. Now, I haven't found as many people to be traumatized by symbols of someone else's religion as I used to fear. That doesn't mean I don't acknowledge the costs that come with being a professional chaplain and wearing a collar all the time. There are some people who can't get past it; but they're rare, as long as I take my time and honor their discomfort.
As for being all things to all people: it's not required. You will be enough to enough people, in more ways than you now imagine. And one of the first things I think you'll discover that you can bring what they need. After all, what then need most often isn't content anyway.
Hopefully, your boss can't make you take your faith out of you, so why take it off of you? What is his/her reason, I mean, deeper than what he/she apparently said?
I guess I'd want to know something about who was "ministering" to me if I were in a hospital bed, but I might not have the energy to play 20 questions to find out.


text:
Meats and Processed Food Products
K Trademark Information
AL-Qasrawi Industrial & Trading CO. Ltd.
Potato Chips; Potato crisps
potato chips potato crisps
This is a brand page for the K trademark by AL-Qasrawi Industrial & Trading CO. Ltd. in Hebron, PalestinianTer, , .
Write a review about a product or service associated with this K trademark. Or, contact the owner AL-Qasrawi Industrial & Trading CO. Ltd. of the K trademark by filing a request to communicate with the Legal Correspondent for licensing, use, and/or questions related to the K trademark.
On Monday, June 22, 2020, a U.S. federal trademark registration was filed for K. The USPTO has given the K trademark serial number of 90014251. The current federal status of this trademark filing is PUBLISHED FOR OPPOSITION. The correspondent listed for K is KEVIN G. SMITH of SUGHRUE MION, PLLC, 2000 PENNSYLVANIA AVE., NW, SUITE 900, WASHINGTON, DC 20006 . The K trademark is filed in the category of Meats and Processed Food Products . The description provided to the USPTO for K is Potato Chips; Potato crisps.
Goods and Services: Potato Chips; Potato crisps
Mark Description: The mark consists of Arabic characters in white outlined in black and red. Under the Arabic characters is an animal character with a primarily blue body, outlined in black, with white features on its face around a black nose and mouth, wearing white gloves and making a thumbs up gesture. The eyes are white, light blue, and black. The shoes on the character are red with white trim. Around the neck of the animal figure is an orange award ribbon and medal with a "K" in white on the medal.
Published For Opposition Date: 11/10/2020
Last Applicant/Owner: AL-Qasrawi Industrial & Trading CO. Ltd.
Hebron, PalestinianTer
Hands and fingers forming the following: handshake, finger pointing, fingers walking, OK sign, and thumbs up or thumbs down (Human Beings - Parts of the human body, skeletons, skulls) see more design...
Medals (alone or suspended from ribbons or pins) (Heraldry, flags, crowns, crosses, arrows and symbols - Coins, medals) see more design...
Inscriptions in Arabic characters (Inscriptions in various characters - Inscriptions ) see more design...
Domestic cats (Animals - Cats, dogs, wolves, foxes, bears, lions, tigers ) see more design...
Gloves, including golf and ski gloves, mittens (Textile, Clothing, Headwear, Footwear & Sewing accessories. - Clothing) see more design...
Other stylized footwear (Textile, Clothing, Headwear, Footwear & Sewing accessories. - Footwear) see more design...
KEVIN G. SMITH
SUGHRUE MION, PLLC
2000 PENNSYLVANIA AVE., NW, SUITE 900
Meat, fish, poultry and game; meat extracts; preserved, frozen, dried and cooked fruits and vegetables; jellies, jams, compotes; eggs, milk and milk products; edible oils and fats.
First Use In Commerce: 12/1/2019
Trademarkia-Network law firms can help you incorporate a business around your K trademark in less than 5 minutes. Trademarkia makes the process easy and convenient, so start now!
KEVIN G. SMITH is a correspondent of K trademark.
Please Rate and Review for K
K is providing Potato Chips; Potato crisps.


During all this time we stayed true to one and the same principles of business operations.
Construction's core values have been shaped over more than 10 years of delivering the finest construction services to our clients. They stood to the test of time and these principles remain our bedrock lynchpins. We never tried to cut on either quality, the pace of work or any other construction aspect. We stay true to our full promise of efficiency!
Our love for detailed, bullet-point preparations, as well as to open and clear project management and communication is what makes us faster than the competition. Recently we compared a technically similar 10-stories building that we built, and the other built by our main competitor. Their price and pace was 2 times lower than hours!
Quality is focal in every little aspect of the construction. The mindset of both our senior employees and all the way to our on-site contractors and construction workers centers on attention. It's out attention to details that allows us to work on a multitude of projects simultaneously, while staying on schedule!
Besides valuing your time, your money and your vision for the project, we also value the Mother Nature as well…It cannot be denied anymore, that even the small construction implements the nature in a bad way… That's why we're leading the effort to use only eco-friendly materials and comply with keeping the environment unpollluted by the work we do!


text:
Social development specialists with decades of
International development sector experience
Chris Hearle
Senior Technical Specialist
Chris joined our technical team in March 2019 and works as a senior consultant in the women's economic empowerment team. He is currently the Senior Technical Adviser on the Work and Opportunities for Women (WOW) programme Helpdesk which provides DFID and other government departments with access to rapid technical assistance and expert analysis for guidance and know-how to address women's economic empowerment.
Chris brings ten years of experience in international development, across a range of social development-related areas including women's economic empowerment, voice and accountability, disability inclusion, and social norms and behaviour change. He is particularly interested in qualitative, participatory and ethnographic methods, and has significant experience in utilizing these approaches in complex multi-year evaluations. For example, he led the qualitative work on gender and poverty reduction in the evaluation of Trademark East Africa, investigating the impacts of trade interventions on girls/women and boys/men from low-income households. Earlier in his career he worked at the International Labour Organisation on gender and economic development issues, and he has 3 ½ years' experience working in Cambodia in project management and business development roles.
Chris received his MPhil in Development Studies from the University of Cambridge and a BA in Human Geography from University of Southampton. He has co-published academic papers in "Oxford Development Studies" and "Women Studies International Forum" and is a regular academic reviewer for the journals "Health and Place" and "Gender, Place and Culture".
Outside of work, Chris is a dog-lover, who enjoys marathon running and tennis.


First off I have to say that I came to this series with an open mind. I genuinely want it to succeed, I think everyone does. So why am I feeling a crushing disappointment at this moment in time.
Sure, this new series has had it's niggles, the 45 minute format quite obviously is not working, the incidental music has been rubbish to say the least, Eccleston's mugging veers dangerously close to ham acting on too many occasions, the sonic get out of jail free and, while you're at it, why not pass go screwdriver.
And then there are my personal annoyances with the series, the insistence that all no obscure references to the original series be made, so as not to confuse younger viewers, lets just make this clear, there are several million more older viewers than younger. We appreciate a bit of continuity (it doesn't take much for the younger ones to brush up, there's plenty of quality stories on DVD and audio). The fact that special effects are not equal across the board, they can be fantastic in one episode and distinctly ropey in another, and while some of the acting has been cringeworthy, some of it, by the guest stars, has outshone the regulars. And also the fact that I am now quite safely able to predict the paths that each character will take in any given episode.
However, as I say these are personal minor niggles and haven't really affected my enjoyment of the series so far, mainly due to the fact that Unquiet Dead and End Of The World were such distinctly great scripts, even if they had plot holes I could drive a bus through (I'll be kind and ignore Rose here).
Aliens Of London, unfortunately, had plot holes I could have driven that spaceship through. Ladies and Gentlemen welcome to the worst story of the series so far, and quite possibly the worst story in Who since those Comic Relief things.
We'll deal first with the blatant stupidities of the script, what was RTD thinking? Firstly, why do these aliens, who have already infiltrated the British Government (Hardly taking over the world is it?) take the trouble to do the whole Pig thing? Especially as they are bodysnatchers. Quite frankly it would have been easier (and more interesting) for them to win a ruddy election than to go through the whole evil machinations plan. Was it me or was the entire first 35 mins of this 45 min episode completely irrelevant to anything more than character development, of which there was pitifully little.
There is a reason the Doctor never ever takes his companions home, or if he does, that's it, the end of the affair. Precisely because of the reaction of Rose's family. This is a condition of entering the Tardis, the first thing that the First Doctor pushed onto Ian and Barbara. The price for wandering the Galaxy is that you become a hobo, you can't just pop home for a cup of tea whenever you feel like it. This is perhaps the worst crime the new series has committed bar one. It just takes away the whole romance of the Doctor, step into the Tardis and get whisked away on unbelievable adventure, step out and that's it, no more. And the Doctor will leave and maybe he was just a figment of your imagination all along and he'll be as sad as you but he will continue on other planets, other worlds, other times, with other companions. And in our heads, we were his only constant companion.
RTD allowing the Doctor to take Rose home just ripped out the romance and the soul of Doctor Who. It's gone, I'm not sure it can come back. His exclamation to Rose not to bring her domestic into the Tardis was simply embarassing, Camille Coduri's excruciating performance didn't help, kudos to Noel Clarke however, Mickey was just annoying this time around rather than all out pathetic. But why did the Doctor insist on calling him Ricky? Is the Doctor as petulant as all that? It was like watching jealous schoolkids, it didn't sit right, as so many things didn't.
Let's move on in this excuse for an episode (We'll ignore the fact that the Doctor should have been arrested the first time around as a kidnapper or something) lets report something positive. Penelope Wilton, gave an excellent, as always, performance.
Ok that's the positive side over and done with. It must be said that Andrew Marr also gave a great performance, but there is something seriously wrong with the BBC casting agents when he outperforms every actor on the show.
Several commentators have noticed that for all the dash and vim of this Doctor, what does he actually do?
Apart from figuring out that the so called alien was actually just a pig, lets just go over the events here, first contact is made with an alien species and the corpse is left in the care of a single med student in a minimum security and blatantly unsterile environment who can't work out that it is a pig, despite the fact that it is, actually, a pig? This from the man who promised us more realism in the show.
So The Doctor figures out that the Pig is in fact, a pig. What else did he do in this episode exactly except watch telly and avoid Rose's mum?
Ok now we come to the actual bad guys of the piece. Simple things first, their design was just utterly awful. There have been better monsters in Troma films. Secondly the CG was pretty bad, not terrible but not great by any means.
Why have a cliffhanger if you're gonna spoil it with a trailer of next week??? WHY WHY WHY!
4th Doctor fought Sutekh, Sontarans, Rutans, Zygons and Wirrin.
8th Doctor fought The Master and the end of the world.
9th Doctor fought fat farting aliens.
This really is an embarrassment on the scale of Dimensions in Time. Not only is RTD pulling apart they Mythos and Romance of Who, he seems to be intent on removing its dignity as well. There have been bad scripts before in Who, but never have they degenerated to the level of infantile pap that this was. They might as well have cast Matt Lucas and Peter Kay, in fact they probably should have, at least they might have been funny.
Who at its best is incredibly clever and witty, look at Tom Baker's era. Degenerating to fart gags indicates a lack of ideas and ability. Not even the Carry On's were that crude.
This marks the moment that I lost faith in RTD's ability to deliver Dr Who.
The announcement of David Tennant as the 10th Doctor does not fill me with hope and smacks of an RTD love in as he just recruits his former leading men. No offence to Tennant, I'm sure he's a great actor, but he doesn't appear to have the physical presence to hold the role when there are great actors who could do a really credible performance who don't even seem to get a look in. Was anyone else (Such as media favourites Nighy or Davies) ever really considered?
I shall continue to watch until the return of the Daleks, as that will be the story that this series will succeed or fail on, but it's going to have to do a heck of a lot more to convince me now than it did before Aliens of London. To be frank, even if it's perfect I'm not sure it can. This was a pathetic attempt to play at Who, written by fanboys with a mental age of ten and may have done irreparable damage to the esteem of the show.