def PUT(self):
		if not self.hasperm("tbt"):
			self.status_code = 403
			return {"e":1, "msg": "Permission denied."}
		
		if not "authorizer" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "The authorizer is required."}
		if not "title" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "Missing Title."}
		if not "author" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "Missing Author."}
		if not "price" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "Missing Price."}
		if not "courses" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "Missing Courses."}
		if not "seller" in self.req.json:
			self.status_code = 400
			return {"e":1, "msg": "Missing Seller."}
		
		authorizer = self.dbs.query(Person).get(self.req.json["authorizer"])
		if not authorizer:
			self.status_code = 400
			return {"e":1, "msg": "Authorizer is not a person."}
		if not "tbt" in authorizer.perms:
			self.status_code = 403
			return {
				"e": 1,
				"msg":
					"Authorizer is not allowed to make changes. " +
					"(They don't have the 'tbt' permission.)",
			}
		
		seller = self.dbs.query(Person).get(self.req.json["seller"])
		if not seller:
			self.status_code = 400
			return {"e":1, "msg": "Seller does not exist."}
		
		courses = []
		
		for c in self.req.json["courses"]:
			if not CourseCode.valid(c):
				self.status_code = 400
				return {"e":1, "msg":"Invalid course code '"+c+"'."}
			
			courses.append(Course(c))
		
		b = TBTBook(seller=seller,
		            title=self.req.json["title"],
		            author=self.req.json["author"],
		            price=int(float(self.req.json["price"])*100),
		            courses=courses)
		
		if "edition" in self.req.json:
			b.edition = str(self.req.json["edition"])
		
		c = TBTBookChange(book=b,
		                  desc="created\n"+repr(b),
		                  user=authorizer)
		self.dbs.add(b, c)
		self.dbs.commit()
		
		return {"e":0,
			"id": b.id,
		}
	def GET(self):
		uq = parse_qs(self.req.query_string.decode(), keep_blank_values=True)
		
		q = self.dbs.query(TBTBook.id)
		
		if "sold" in uq:
			if uq["sold"][0] == "0":
				q = q.filter(TBTBook.buyer == None)
			else:
				q = q.filter(TBTBook.buyer != None)
		
		if "course" in uq:
			c = CourseCode.clean(uq["course"][0])
			
			if len(c) == 8:
				p = Course.code == c
			else:
				p = db.prefixof(Course.code, c)
			
			q = q.join(Course).filter(p)
		
		if "title" in uq:
			words = uq["title"][0].split(" ")
			
			if len(words) > 10: # You are asking for a lot.
				words = words[:5]
			
			q = q.filter(*(TBTBook.title.ilike("%"+t+"%") for t in words))
		
		if "involves" in uq:
			if not self.req.auth:
				self.status_code = 401
				return {"e":1, "msg":"You must authenticate to filter by involvement."}
			
			inv = int(uq["involves"][0])
			
			if inv != self.req.auth.user.id:
				self.status_code = 403
				return {"e":1, "msg":"You can only search for your own involvement."}
			
			q = q.filter(
				(TBTBook.seller == Person(id=inv)) | (TBTBook.buyer == Person(id=inv))
			)
		
		if "paid" in uq:
			if not self.req.auth:
				self.status_code = 401
				return {"e":1,"msg":"You must authenticate to filter by paid."}
			
			if not "tbt" in self.req.auth.perms:
				self.status_code = 403
				return {"e":1, "msg":"You may not filter by paid."}
			
			paid = uq["paid"][-1]
			
			q = q.filter(TBTBook.paid == (paid != "0"))
		
		q = q.group_by(TBTBook.id)
		
		return {"e":0,
			"books": [r[0] for r in q],
		}