Please create a colorful handbook pdf with grammar explained in more easy and interesting way by using bold text of specific phrasal verbs and binomials,idioms used from the pdf which I have attached and also do prepare list of vocabulary words along with it's Russian translation under their English meanings
English grammar handbook colorful PDF design learner-friendly best practices
~/
python - <<'PY' import pdfplumber p='/tmp/workspace/attachments/eee631fc-5690-4fa4-b4bf-2c64803066cf/DOC-20260903-WA0006.pdf' with pdfplumber.open(p) as pdf: print('PAGES',len(pdf.pages)) for i,page in enumerate(pdf.pages): text=page.extract_text() or '' print(f'\n===== PAGE {i+1} =====\n{text[:12000]}') PY
mkdir -p "/tmp/workspace/entertainment_english_handbook/src" "/tmp/workspace/entertainment_english_handbook/output" && python - <<'PY' from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont import os for p in ['/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf','/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf']: print(p, os.path.exists(p)) PY
**/*DejaVuSans*.ttf in /usr/share/fonts
fc-match -f '%{file}\n' 'Noto Sans' && fc-match -f '%{file}\n' 'DejaVu Sans' && fc-match -f '%{file}\n' 'Liberation Sans'
fc-list | head -20
python - <<'PY' from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont p='/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf' pdfmetrics.registerFont(TTFont('Noto',p)) print('registered') PY
fc-match -f '%{file}\n' 'Droid Sans:style=Bold'
cat > "/tmp/workspace/entertainment_english_handbook/src/create_handbook.py" <<'PY' from reportlab.lib import colors from reportlab.lib.colors import HexColor from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.lib.units import cm from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.pdfgen import canvas OUT='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Handbook.pdf' REG='/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf' BOLD='/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf' pdfmetrics.registerFont(TTFont('Noto',REG)) pdfmetrics.registerFont(TTFont('NotoBold',BOLD)) NAVY=HexColor('#183B56'); BLUE=HexColor('#2176AE'); SKY=HexColor('#E8F5FC'); TEAL=HexColor('#06A6A6'); MINT=HexColor('#E7F7F5') ORANGE=HexColor('#F18F01'); PEACH=HexColor('#FFF1DD'); PINK=HexColor('#E94F7A'); LILAC=HexColor('#F3EDFF'); INK=HexColor('#263238'); GREY=HexColor('#607D8B'); WHITE=colors.white class NumberedCanvas(canvas.Canvas): def __init__(self,*args,**kwargs): canvas.Canvas.__init__(self,*args,**kwargs); self.pages=[] def showPage(self): self.pages.append(dict(self.__dict__)); self._startPage() def save(self): n=len(self.pages) for state in self.pages: self.__dict__.update(state) if self._pageNumber>1: self.setStrokeColor(HexColor('#D8E5EB')); self.setLineWidth(.7); self.line(1.55*cm,1.35*cm,19.45*cm,1.35*cm) self.setFont('Noto',8); self.setFillColor(GREY) self.drawString(1.55*cm,.85*cm,'Entertainment English | Easy grammar handbook') self.drawRightString(19.45*cm,.85*cm,f'{self._pageNumber} / {n}') canvas.Canvas.showPage(self) canvas.Canvas.save(self) def P(text, style): return Paragraph(text,style) styles=getSampleStyleSheet() base=ParagraphStyle('base', parent=styles['BodyText'], fontName='Noto', fontSize=10.2, leading=14.2, textColor=INK, spaceAfter=6) small=ParagraphStyle('small', parent=base, fontSize=8.4, leading=11) title=ParagraphStyle('title', parent=styles['Title'], fontName='NotoBold', fontSize=31, leading=37, textColor=NAVY, alignment=TA_CENTER, spaceAfter=12) subtitle=ParagraphStyle('subtitle', parent=base, fontSize=13, leading=18, textColor=GREY, alignment=TA_CENTER) h1=ParagraphStyle('h1', parent=styles['Heading1'], fontName='NotoBold', fontSize=21, leading=25, textColor=NAVY, spaceBefore=3, spaceAfter=11) h2=ParagraphStyle('h2', parent=styles['Heading2'], fontName='NotoBold', fontSize=13.5, leading=17, textColor=BLUE, spaceBefore=7, spaceAfter=6) label=ParagraphStyle('label', parent=base, fontName='NotoBold', fontSize=9, leading=11, textColor=WHITE, alignment=TA_CENTER) callout=ParagraphStyle('callout', parent=base, fontSize=10.1, leading=14, leftIndent=3, rightIndent=3) story=[] def chip(text, color=TEAL): t=Table([[P(text,label)]],colWidths=[5.1*cm]); t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),color),('BOX',(0,0),(-1,-1),0,color),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)])); return t def box(titletext, content, bg=SKY, color=BLUE): tab=Table([[P(titletext,ParagraphStyle('bt',parent=h2,textColor=color,spaceBefore=0,spaceAfter=3)),P(content,callout)]],colWidths=[17.8*cm]) tab.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.6,color),('LEFTPADDING',(0,0),(-1,-1),11),('RIGHTPADDING',(0,0),(-1,-1),11),('TOPPADDING',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),8)])); return tab def two_cols(left,right): t=Table([[left,right]],colWidths=[8.75*cm,8.75*cm],hAlign='LEFT'); t.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),8),('TOPPADDING',(0,0),(-1,-1),0),('BOTTOMPADDING',(0,0),(-1,-1),0)])); return t def vocab(rows): data=[[P('<b>Word / phrase</b>',small),P('<b>Easy English meaning</b>',small),P('<b>Русский перевод</b>',small)]] for a,b,c in rows:data.append([P(a,small),P(b,small),P(c,small)]) t=Table(data,colWidths=[4.2*cm,8.3*cm,5.1*cm],repeatRows=1) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#C9D8DF')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,SKY])])) return t # cover story += [Spacer(1,2.4*cm), chip('UNIT 1 | ENTERTAINMENT & HABITS',ORANGE), Spacer(1,.65*cm), P('English that sounds<br/>natural',title), P('A colourful, learner-friendly mini handbook based on your lesson: habits, entertainment, polite disagreement and useful vocabulary.',subtitle), Spacer(1,.75*cm)] cover=Table([[P('<b>Talk about what you do</b><br/>Use the present and past to describe routines.',callout),P('<b>Share opinions kindly</b><br/>Disagree without sounding rude.',callout),P('<b>Remember real phrases</b><br/>Bold expressions come from the lesson.',callout)]],colWidths=[5.85*cm]*3) cover.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),MINT),('BACKGROUND',(1,0),(1,0),PEACH),('BACKGROUND',(2,0),(2,0),LILAC),('BOX',(0,0),(-1,-1),.6,HexColor('#B5C8D1')),('INNERGRID',(0,0),(-1,-1),.5,HexColor('#B5C8D1')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),12),('BOTTOMPADDING',(0,0),(-1,-1),12)])); story += [cover,Spacer(1,1.1*cm),box('How to use this handbook','Read the <b>bold</b> expressions aloud. They are the high-value phrases from the lesson. Then make every example true for you. Small changes make grammar memorable.',SKY,TEAL),Spacer(1,.4*cm),P('Level: A2-B1 • Topic: free time, films, books and music',subtitle),PageBreak()] # habits story += [P('1. Habits: say what you usually do',h1),P('Use the <b>present simple</b> for routines and repeated actions. Add a frequency phrase to show how often something happens.',base),two_cols(box('Simple pattern','<b>I / you / we / they + verb</b><br/>I read online.<br/><b>He / she + verb-s</b><br/>She watches short videos.',MINT,TEAL),box('Make it more natural','I <b>rarely</b> go to concerts.<br/>We go out <b>all the time</b>.<br/>He is online <b>all the time</b>.',PEACH,ORANGE)),Spacer(1,.2*cm),P('Frequency ladder',h2)] ladder=Table([[P('<b>100%</b><br/>all the time',small),P('<b>usually</b><br/>as a rule',small),P('<b>sometimes</b><br/>now and then',small),P('<b>almost never</b><br/>hardly ever / rarely',small)]],colWidths=[4.4*cm]*4) ladder.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),PINK),('BACKGROUND',(1,0),(1,0),ORANGE),('BACKGROUND',(2,0),(2,0),TEAL),('BACKGROUND',(3,0),(3,0),BLUE),('TEXTCOLOR',(0,0),(-1,-1),WHITE),('ALIGN',(0,0),(-1,-1),'CENTER'),('VALIGN',(0,0),(-1,-1),'MIDDLE'),('TOPPADDING',(0,0),(-1,-1),12),('BOTTOMPADDING',(0,0),(-1,-1),12),('INNERGRID',(0,0),(-1,-1),1,WHITE)])); story += [ladder,Spacer(1,.3*cm),box('Memory trick','Put the frequency word <b>before</b> most verbs: “I <b>rarely read</b> fiction.” But put it <b>after be</b>: “He is <b>always</b> online.”',LILAC,PINK),P('Try it',h2),P('Finish these ideas: “I usually …”, “I hardly ever …”, “Now and then, I …”. Then ask a friend: “Do you go to the cinema much?”',base),PageBreak()] # past habits story += [P('2. Past habits: then and now',h1),P('Use <b>used to</b> for a regular past habit or situation that is no longer true. Use the past simple for a finished action, not for a long-term routine.',base),box('The easy formula','<b>used to + base verb</b><br/>I <b>used to go out</b> four nights a week. (This was my old routine.)<br/><b>Did + subject + use to + base verb?</b><br/>Did you <b>use to watch</b> that show?',MINT,TEAL),Spacer(1,.22*cm)] compare=Table([[P('<b>Past habit</b>',small),P('<b>Meaning</b>',small),P('<b>Example</b>',small)],[P('<b>used to + verb</b>',small),P('Something happened regularly in the past, but not now.',small),P('We <b>used to hang out</b> after class.',small)],[P('<b>would + verb</b>',small),P('A repeated past action, usually with time context.',small),P('On Fridays, we would watch films.',small)],[P('<b>past simple</b>',small),P('One completed event.',small),P('Last Friday, we watched a film.',small)]],colWidths=[4*cm,6.5*cm,7.1*cm]) compare.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#C9D8DF')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),7),('BOTTOMPADDING',(0,0),(-1,-1),7),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,SKY])])) story += [compare,Spacer(1,.35*cm),box('Common correction','After <b>did</b>, use <b>use to</b>, not “used to”:<br/><font color="#E94F7A">✗ Did you used to go?</font> <font color="#068A8A">✓ Did you use to go?</font>',PEACH,ORANGE),P('Your timeline',h2),P('Write one old habit and one current habit: “I <b>used to</b> …, but now I …”. Example: “I <b>used to go out</b> a lot, but now I prefer quiet evenings.”',base),PageBreak()] # phrases story += [P('3. Natural phrases from the lesson',h1),P('These expressions make your English sound less like a grammar exercise and more like a real conversation.',base),P('Phrasal verbs',h2)] pv=Table([[P('<b>Expression</b>',small),P('<b>Easy meaning + example</b>',small)],[P('<b>go out</b>',small),P('leave home to socialise: “We <b>go out</b> on Saturdays.”',small)],[P('<b>hang out</b>',small),P('spend relaxed time with people: “We <b>hang out</b> at a café.”',small)],[P('<b>take over</b>',small),P('become so important that it controls a situation: “Short videos have <b>taken over</b> his free time.”',small)]],colWidths=[4.3*cm,13.3*cm]); pv.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),TEAL),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#B8DBD9')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,MINT])])) story += [pv,Spacer(1,.25*cm),P('Fixed phrases, idioms and a binomial',h2)] story += [box('<b>now and then</b> | binomial / fixed pair','Meaning: sometimes, but not regularly. It joins two time words with <i>and</i>. Example: “I read novels <b>now and then</b>.”',LILAC,PINK),Spacer(1,.13*cm),box('<b>as a rule</b>','Meaning: generally; in most cases. “<b>As a rule</b>, I do not listen to dance music.”',SKY,BLUE),Spacer(1,.13*cm),box('<b>my kind of thing</b>','Meaning: something that suits my taste. “Horror films are not really <b>my kind of thing</b>.”',PEACH,ORANGE),Spacer(1,.13*cm),box('<b>do much for me</b>','Meaning: give me pleasure or interest. “The film was fine, but it did not <b>do much for me</b>.”',MINT,TEAL),Spacer(1,.13*cm),box('<b>for my liking</b>','Meaning: in my personal opinion or taste. “It is a bit too strange <b>for my liking</b>.”',LILAC,PINK),PageBreak()] # opinions story += [P('4. Agreeing and disagreeing politely',h1),P('In English, people often soften a negative opinion. This helps you sound friendly when someone likes something you do not like.',base),two_cols(box('Too direct','“I hate it.”<br/>“That film is weird.”<br/>“Your music is terrible.”',PEACH,ORANGE),box('More polite','“I am <b>not that keen on</b> it.”<br/>“It is <b>a bit</b> weird <b>for my liking</b>.”<br/>“It is <b>not really my kind of thing</b>.”',MINT,TEAL)),Spacer(1,.25*cm),P('Build a soft response',h2)] steps=Table([[P('<b>1. Start gently</b><br/>Yeah, I guess, but …',small),P('<b>2. Add your view</b><br/>to be honest, I am not that keen on …',small),P('<b>3. Give a kind reason</b><br/>It is a bit too over-the-top for my liking.',small)]],colWidths=[5.85*cm]*3) steps.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),SKY),('BACKGROUND',(1,0),(1,0),MINT),('BACKGROUND',(2,0),(2,0),LILAC),('BOX',(0,0),(-1,-1),.5,HexColor('#B5C8D1')),('INNERGRID',(0,0),(-1,-1),.5,HexColor('#B5C8D1')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),9),('RIGHTPADDING',(0,0),(-1,-1),9),('TOPPADDING',(0,0),(-1,-1),10),('BOTTOMPADDING',(0,0),(-1,-1),10)])); story += [steps,Spacer(1,.35*cm),box('Model response','A: “I love reality TV.”<br/>B: “Yeah, I guess, but <b>to be honest</b>, it is <b>not really my kind of thing</b>. It is <b>a bit</b> repetitive <b>for my liking</b>.”',SKY,BLUE),P('Useful softeners',h2),P('<b>I guess</b> • <b>I suppose</b> • <b>to be honest</b> • <b>not that keen on</b> • <b>a bit</b> • <b>for my liking</b>',base),PageBreak()] # descriptive vocab story += [P('5. Describe films, books and music',h1),P('Choose one strong adjective. Then say why you feel that way. This makes your opinion clearer and more interesting.',base),vocab([('catchy','easy to remember, especially a tune','запоминающийся, навязчивый'),('hilarious','extremely funny','очень смешной'),('commercial','made for a large audience and profit','коммерческий, массовый'),('disturbing','making you feel worried or upset','тревожный, неприятный'),('over-the-top','too extreme, dramatic or excessive','слишком чрезмерный, вычурный'),('gripping','so exciting that you cannot stop reading or watching','захватывающий'),('uplifting','making you feel happier or more hopeful','вдохновляющий, поднимающий настроение'),('weird','very strange or unusual','странный'),('astonishing','very surprising or impressive','поразительный'),('dreadful','very bad or unpleasant','ужасный')]),Spacer(1,.25*cm),box('Quick speaking pattern','“It was <b>gripping</b> because I wanted to know what happened next.”<br/>“The song is <b>catchy</b>, but the lyrics are not very deep.”<br/>“The story was <b>uplifting</b> and made me feel hopeful.”',PEACH,ORANGE),PageBreak()] # wider vocabulary story += [P('6. Vocabulary bank: habits and opinions',h1),P('Learn each item as a small idea, not as a single translated word. Say an example aloud after reading the meaning.',base),vocab([('tend to','usually do something; have a general habit','обычно склонен что-то делать'),('rarely','not often','редко'),('hardly ever','almost never','почти никогда'),('fiction','stories that are invented, not factual','художественная литература'),('novel','a long fictional book','роман'),('concert','a live music performance','концерт'),('club','a place for dancing and socialising','ночной клуб'),('keen on','liking or interested in something','увлекающийся; любящий'),('viewpoint','an opinion or way of thinking','точка зрения'),('upsetting','making someone sad or worried','расстраивающий'),('inspiring','giving you enthusiasm or good ideas','вдохновляющий'),('pretty much','almost; nearly completely','почти; практически')]),Spacer(1,.23*cm),box('Mini-review','Say three true sentences: “I <b>tend to</b> …”, “I am quite <b>keen on</b> …”, “I <b>hardly ever</b> …”.',MINT,TEAL),PageBreak()] # practice & key story += [P('7. Make it yours: 5-minute practice',h1),P('Do these without looking back. Then use the answer guide to check your grammar.',base),box('A. Complete','1. I ______ to play games every evening, but now I do not.<br/>2. We ______ out at the park after school.<br/>3. I watch documentaries now and ______.<br/>4. I am not that ______ on action films.<br/>5. That song is very ______. I cannot stop humming it.',SKY,BLUE),Spacer(1,.22*cm),box('B. Make it polite','Rewrite: “I do not like opera. It is strange.”<br/><br/>Start with: “Yeah, I guess, but to be honest, …”',LILAC,PINK),Spacer(1,.22*cm),box('C. Talk','Choose a film, book or song. Give one positive opinion and one polite negative opinion. Include one <b>phrasal verb</b> and one phrase from the fixed-expression boxes.',PEACH,ORANGE),Spacer(1,.3*cm),P('Answer guide',h2),P('A: 1 <b>used</b> 2 <b>hung</b> 3 <b>then</b> 4 <b>keen</b> 5 <b>catchy</b>. B: Example: “Yeah, I guess, but to be honest, I am not that keen on opera. It is a bit strange for my liking.”',base),Spacer(1,.35*cm),box('Keep this rule','Grammar gives you the structure. Repeated phrases give you confidence. Use one new bold expression today.',MINT,TEAL)] doc=SimpleDocTemplate(OUT,pagesize=A4,rightMargin=1.55*cm,leftMargin=1.55*cm,topMargin=1.55*cm,bottomMargin=1.75*cm,title='Entertainment English Handbook',author='Orris') doc.build(story,canvasmaker=NumberedCanvas) print(OUT) PY python "/tmp/workspace/entertainment_english_handbook/src/create_handbook.py" python - <<'PY' from pypdf import PdfReader p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Handbook.pdf' r=PdfReader(p) print('pages=',len(r.pages),'bytes=',__import__('os').path.getsize(p)) for i,pge in enumerate(r.pages): print(i+1,(pge.extract_text() or '')[:90].replace('\n',' | ')) PY
When I am clicking the pdf isn't opening.
Entertainment English Handbook
PDF Document · PDF
Please make few changes in the colorful handbook pdf prepared by you, firstly explain the grammar part according to B2 proficiency and in compact way but interestingly by using information mentioned from the original file attached, secondly don't add any other extra text that this pdf is for B2 esl students.thirdly for vocabulary words include the words from box from original attached file only and if you want to add some extra words for vocabulary then only add B2 proficiency and fourthly remove the last page of practice questions.
B2 English grammar teaching habits used to tend to concise explanations CEFR
~/entertainment_english_handbook
cat > "/tmp/workspace/entertainment_english_handbook/src/create_revised_handbook.py" <<'PY' from reportlab.lib import colors from reportlab.lib.colors import HexColor from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER from reportlab.lib.units import cm from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfgen import canvas import os OUT='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Handbook_Revised.pdf' pdfmetrics.registerFont(TTFont('Noto','/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf')) pdfmetrics.registerFont(TTFont('NotoBold','/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf')) NAVY=HexColor('#183B56'); BLUE=HexColor('#2176AE'); SKY=HexColor('#E8F5FC'); TEAL=HexColor('#06A6A6'); MINT=HexColor('#E7F7F5'); ORANGE=HexColor('#F18F01'); PEACH=HexColor('#FFF1DD'); PINK=HexColor('#E94F7A'); LILAC=HexColor('#F3EDFF'); INK=HexColor('#263238'); GREY=HexColor('#607D8B'); WHITE=colors.white class Canvas(canvas.Canvas): def __init__(self,*a,**kw): canvas.Canvas.__init__(self,*a,**kw); self.saved=[] def showPage(self): self.saved.append(dict(self.__dict__)); self._startPage() def save(self): total=len(self.saved) for st in self.saved: self.__dict__.update(st) if self._pageNumber>1: self.setStrokeColor(HexColor('#D8E5EB'));self.line(1.55*cm,1.3*cm,19.45*cm,1.3*cm);self.setFillColor(GREY);self.setFont('Noto',8) self.drawString(1.55*cm,.82*cm,'Entertainment English');self.drawRightString(19.45*cm,.82*cm,f'{self._pageNumber} / {total}') canvas.Canvas.showPage(self) canvas.Canvas.save(self) def P(s,st):return Paragraph(s,st) ss=getSampleStyleSheet(); base=ParagraphStyle('base',parent=ss['BodyText'],fontName='Noto',fontSize=10.1,leading=14,textColor=INK,spaceAfter=6) small=ParagraphStyle('small',parent=base,fontSize=8.4,leading=10.8); title=ParagraphStyle('title',parent=ss['Title'],fontName='NotoBold',fontSize=31,leading=37,textColor=NAVY,alignment=TA_CENTER,spaceAfter=12); sub=ParagraphStyle('sub',parent=base,fontSize=13,leading=18,textColor=GREY,alignment=TA_CENTER); h1=ParagraphStyle('h1',parent=ss['Heading1'],fontName='NotoBold',fontSize=21,leading=25,textColor=NAVY,spaceAfter=10); h2=ParagraphStyle('h2',parent=ss['Heading2'],fontName='NotoBold',fontSize=13.5,leading=17,textColor=BLUE,spaceBefore=5,spaceAfter=5); label=ParagraphStyle('label',parent=base,fontName='NotoBold',fontSize=9,leading=11,textColor=WHITE,alignment=TA_CENTER) def box(head,body,bg=SKY,edge=BLUE): t=Table([[P(head,ParagraphStyle('bhead',parent=h2,textColor=edge,spaceBefore=0,spaceAfter=2)),P(body,base)]],colWidths=[17.8*cm]);t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.65,edge),('LEFTPADDING',(0,0),(-1,-1),11),('RIGHTPADDING',(0,0),(-1,-1),11),('TOPPADDING',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),8)]));return t def cols(a,b): t=Table([[a,b]],colWidths=[8.75*cm,8.75*cm]);t.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),8),('TOPPADDING',(0,0),(-1,-1),0),('BOTTOMPADDING',(0,0),(-1,-1),0)]));return t def vtable(rows): data=[[P('<b>Word</b>',small),P('<b>English meaning</b>',small),P('<b>Русский перевод</b>',small)]]+[[P(a,small),P(b,small),P(c,small)] for a,b,c in rows] t=Table(data,colWidths=[4.2*cm,8.3*cm,5.1*cm],repeatRows=1);t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#C9D8DF')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,SKY])])) return t S=[] # cover badge=Table([[P('UNIT 1 | ENTERTAINMENT & HABITS',label)]],colWidths=[5.3*cm]);badge.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),ORANGE),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)])) S += [Spacer(1,2.35*cm),badge,Spacer(1,.65*cm),P('English that sounds<br/>natural',title),P('Habits, entertainment and tactful opinions',sub),Spacer(1,.8*cm)] intro=Table([[P('<b>Habits</b><br/>Describe routines with precision.',base),P('<b>Taste</b><br/>Review films, books and music.',base),P('<b>Tact</b><br/>Disagree without sounding abrupt.',base)]],colWidths=[5.85*cm]*3);intro.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),MINT),('BACKGROUND',(1,0),(1,0),PEACH),('BACKGROUND',(2,0),(2,0),LILAC),('BOX',(0,0),(-1,-1),.6,HexColor('#B5C8D1')),('INNERGRID',(0,0),(-1,-1),.5,HexColor('#B5C8D1')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),12),('BOTTOMPADDING',(0,0),(-1,-1),12)]));S += [intro,Spacer(1,1.05*cm),box('A practical approach','Notice the <b>bold</b> language from the lesson, then adapt each example to your own life. The most natural grammar comes with a clear context.',SKY,TEAL),PageBreak()] # page 2 S += [P('1. Habits: frequency and tendency',h1),P('For present routines, the present simple is the default. Frequency adverbials make the statement more precise; <b>tend to</b> expresses a general tendency rather than an absolute rule.',base),cols(box('Position matters','Place adverbs such as <b>rarely</b> and <b>hardly ever</b> before a main verb: “I <b>rarely read</b> fiction.”<br/>After <i>be</i>: “He is <b>always</b> online.”',MINT,TEAL),box('Degree of regularity','<b>all the time</b> = extremely frequently<br/><b>as a rule</b> = generally<br/><b>now and then</b> = occasionally<br/><b>hardly ever</b> = almost never',PEACH,ORANGE)),Spacer(1,.22*cm),box('Nuance: <b>tend to</b>','Use it to avoid overgeneralising: “I <b>tend not to</b> read much fiction.” It means “this is normally true”, not “this is true on every occasion”.',LILAC,PINK),Spacer(1,.22*cm),box('Comparison with a past routine','<b>We do not go to the cinema as much as we used to.</b><br/>This contrasts the present frequency with an earlier period. The comparison implies that cinema visits are less common now.',SKY,BLUE),Spacer(1,.2*cm),P('High-frequency phrases',h2),P('<b>all the time</b> • <b>now and then</b> • <b>as a rule</b> • <b>not as much as I’d like to</b> • <b>hardly ever</b>',base),PageBreak()] # p3 S += [P('2. Past habits: <b>used to</b> and context',h1),P('Use <b>used to + infinitive</b> for past habits or states that are no longer typical or true. The contrast with now may be stated or simply understood.',base),box('Form and meaning','<b>Affirmative:</b> I <b>used to go out</b> a lot.<br/><b>Negative:</b> I did not <b>use to go out</b> much.<br/><b>Question:</b> Did you <b>use to watch</b> that programme?<br/><br/>After <b>did</b>, write <b>use to</b>, not “used to”.',MINT,TEAL),Spacer(1,.2*cm),box('Do not confuse the time frames','“I <b>used to go out</b> four nights a week” describes a former pattern. “I went out last night” reports one completed event. The past simple does not itself signal a discontinued habit.',PEACH,ORANGE),Spacer(1,.2*cm),box('A natural contrast','“We’d <b>hang out</b> all the time, but now we hardly ever do.” Here, <b>would</b> can describe a repeated past action when the time frame is clear. <b>Used to</b> is more direct for old habits and states.',LILAC,PINK),Spacer(1,.2*cm),box('One useful question','“Did you ever <b>use to</b> go to the Teatro Colón when you lived in Buenos Aires?” <b>ever</b> makes the question broader: it asks about any point in that past period.',SKY,BLUE),PageBreak()] # p4 phrases S += [P('3. Natural language for free time',h1),P('These lesson expressions carry meaning beyond their individual words. Use them as complete chunks.',base),P('Phrasal verbs',h2)] pt=Table([[P('<b>Expression</b>',small),P('<b>Meaning in context</b>',small)],[P('<b>go out</b>',small),P('leave home to socialise or enjoy entertainment: “We <b>go out</b> at weekends.”',small)],[P('<b>hang out</b>',small),P('spend informal, relaxed time with someone: “We used to <b>hang out</b> all the time.”',small)],[P('<b>take over</b>',small),P('become so dominant that it controls a situation: “TikTok has <b>taken over</b> his life.”',small)]],colWidths=[4.4*cm,13.2*cm]);pt.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),TEAL),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#B8DBD9')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),7),('BOTTOMPADDING',(0,0),(-1,-1),7),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,MINT])])) S += [pt,Spacer(1,.25*cm),box('<b>now and then</b>','A fixed pair meaning “occasionally”: “I read novels <b>now and then</b>.” It gives a softer, less exact sense of frequency than <i>sometimes</i>.',LILAC,PINK),Spacer(1,.12*cm),box('<b>my kind of thing</b>','Something that matches your preferences: “Action movies are not really <b>my kind of thing</b>.”',PEACH,ORANGE),Spacer(1,.12*cm),box('<b>do much for me</b>','Give me pleasure, interest or a strong reaction: “It did not <b>do much for me</b>.”',MINT,TEAL),Spacer(1,.12*cm),box('<b>for my liking</b>','In my personal view or according to my taste: “It was a bit too weird <b>for my liking</b>.”',SKY,BLUE),PageBreak()] # p5 opinions S += [P('4. Tactful disagreement',h1),P('When disagreeing about taste, soften the negative point rather than rejecting the other person’s view. The aim is not to weaken your opinion, but to make the interaction more cooperative.',base),cols(box('Abrupt','“I do not like it.”<br/>“It is weird.”<br/>“That music is terrible.”',PEACH,ORANGE),box('Tactful','“I am <b>not that keen on</b> it.”<br/>“It is <b>a bit</b> weird <b>for my liking</b>.”<br/>“It is <b>not really my kind of thing</b>.”',MINT,TEAL)),Spacer(1,.25*cm),box('A three-part response','<b>1. Acknowledge:</b> “Yeah, I guess, but …”<br/><b>2. Qualify:</b> “<b>To be honest</b>, I am not that keen on …”<br/><b>3. Give a measured reason:</b> “It is a bit too over-the-top for my liking.”',SKY,BLUE),Spacer(1,.22*cm),box('Useful discourse markers','<b>I guess</b> and <b>I suppose</b> signal partial agreement or uncertainty. <b>To be honest</b> introduces a personal view. <b>A bit</b> reduces the force of a negative adjective.',LILAC,PINK),Spacer(1,.2*cm),box('Model','A: “I love Tarantino’s films.”<br/>B: “He is all right, I suppose, but I am <b>not that keen on</b> his films. They are a bit <b>over-the-top</b> for my liking.”',PEACH,ORANGE),PageBreak()] # p6 vocabulary only exact box S += [P('5. Vocabulary: films, music and books',h1),P('The vocabulary below is taken from the descriptive-word box in the lesson. Pair each adjective with a specific reaction or reason when giving an opinion.',base),vtable([('astonishing','very surprising or impressive','поразительный, удивительный'),('catchy','easy to remember, especially a tune','запоминающийся, навязчивый'),('commercial','made for a mass audience, often to make money','коммерческий, массовый'),('disturbing','making you feel worried, upset or uncomfortable','тревожный, неприятный'),('dreadful','extremely bad or unpleasant','ужасный'),('gripping','so exciting that it holds your attention','захватывающий'),('hilarious','extremely funny','очень смешной'),('over-the-top','too extreme, dramatic or excessive','чрезмерный, вычурный'),('uplifting','making you feel happier or more hopeful','вдохновляющий, поднимающий настроение'),('weird','strange or unusual','странный')]),Spacer(1,.25*cm),box('Precise opinion patterns','“It is <b>catchy</b>, so I remember the tune immediately.”<br/>“The book is <b>gripping</b>; I cannot stop reading it.”<br/>“The film is <b>disturbing</b>, but it is also astonishing.”<br/>“The story is genuinely <b>uplifting</b>.”',MINT,TEAL),Spacer(1,.22*cm),box('Contrast carefully','A work can have more than one quality: “It is well made, but a bit <b>over-the-top</b> for my liking.” This structure lets you recognise a positive feature while still expressing a reservation.',PEACH,ORANGE)] doc=SimpleDocTemplate(OUT,pagesize=A4,rightMargin=1.55*cm,leftMargin=1.55*cm,topMargin=1.55*cm,bottomMargin=1.75*cm,title='Entertainment English Handbook',author='Orris') doc.build(S,canvasmaker=Canvas) print(OUT,os.path.getsize(OUT)) PY python "/tmp/workspace/entertainment_english_handbook/src/create_revised_handbook.py" python - <<'PY' from pypdf import PdfReader p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Handbook_Revised.pdf' r=PdfReader(p);print('pages:',len(r.pages)); for i,x in enumerate(r.pages): print(i+1, (x.extract_text() or '')[:75].replace('\n',' | ')) PY
~/entertainment_english_handbook/output
Entertainment English Handbook Revised
PDF Document · PDF
Please make few changes, firstly don't explain the grammar part deeply just write all the phrasal verbs/ metaphor/ idioms/binomials used with their meanings and add extra if required for B2 proficiency and create a list of them with meanings.Secondly text of pdf should not be cut from left or right side please be careful of that technical error, thirdly prepare list of" disagreeing politely " phrasal verbs and binomials and idioms which we use for B2 proficiency conversation and create a list with meanings .
British Council B2 polite disagreement phrases idioms phrasal verbs
~/entertainment_english_handbook
cat > "/tmp/workspace/entertainment_english_handbook/src/create_expression_handbook.py" <<'PY' from reportlab.lib import colors from reportlab.lib.colors import HexColor from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER from reportlab.lib.units import cm from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfgen import canvas import os OUT='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Expressions_B2.pdf' pdfmetrics.registerFont(TTFont('Noto','/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf')) pdfmetrics.registerFont(TTFont('NotoBold','/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf')) NAVY=HexColor('#183B56'); BLUE=HexColor('#2176AE'); TEAL=HexColor('#008C95'); MINT=HexColor('#E8F7F5'); SKY=HexColor('#EAF5FC'); ORANGE=HexColor('#E98500'); PEACH=HexColor('#FFF0DC'); PINK=HexColor('#C83E70'); LILAC=HexColor('#F1ECFF'); INK=HexColor('#263238'); GREY=HexColor('#607D8B'); WHITE=colors.white class NumCanvas(canvas.Canvas): def __init__(self,*a,**kw): canvas.Canvas.__init__(self,*a,**kw);self.states=[] def showPage(self): self.states.append(dict(self.__dict__));self._startPage() def save(self): n=len(self.states) for s in self.states: self.__dict__.update(s) if self._pageNumber>1: self.setStrokeColor(HexColor('#D6E3E8'));self.line(2*cm,1.35*cm,19*cm,1.35*cm);self.setFont('Noto',8);self.setFillColor(GREY);self.drawString(2*cm,.85*cm,'Entertainment English | Expression handbook');self.drawRightString(19*cm,.85*cm,f'{self._pageNumber} / {n}') canvas.Canvas.showPage(self) canvas.Canvas.save(self) ss=getSampleStyleSheet(); body=ParagraphStyle('body',parent=ss['BodyText'],fontName='Noto',fontSize=9.7,leading=13.2,textColor=INK,spaceAfter=4); tiny=ParagraphStyle('tiny',parent=body,fontSize=8.35,leading=10.7); title=ParagraphStyle('title',parent=ss['Title'],fontName='NotoBold',fontSize=29,leading=35,textColor=NAVY,alignment=TA_CENTER); sub=ParagraphStyle('sub',parent=body,fontSize=12.5,leading=17,textColor=GREY,alignment=TA_CENTER); h1=ParagraphStyle('h1',parent=ss['Heading1'],fontName='NotoBold',fontSize=20,leading=24,textColor=NAVY,spaceAfter=8); h2=ParagraphStyle('h2',parent=ss['Heading2'],fontName='NotoBold',fontSize=13.5,leading=16,textColor=BLUE,spaceBefore=4,spaceAfter=5); lab=ParagraphStyle('lab',parent=body,fontName='NotoBold',fontSize=8.6,leading=10,textColor=WHITE,alignment=TA_CENTER) def P(t,s=body):return Paragraph(t,s) def banner(t,c=TEAL): x=Table([[P(t,lab)]],colWidths=[5.8*cm]);x.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),c),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)]));return x def box(head,text,bg=SKY,edge=BLUE): x=Table([[P(head,ParagraphStyle('xx',parent=h2,textColor=edge,spaceBefore=0,spaceAfter=2)),P(text,body)]],colWidths=[17*cm]);x.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.65,edge),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),7),('BOTTOMPADDING',(0,0),(-1,-1),7)]));return x def table(rows, widths=(4.45,7.1,5.45), header=('Expression','Meaning','Example / note'), color=NAVY): data=[[P(f'<b>{x}</b>',tiny) for x in header]]+[[P(a,tiny),P(b,tiny),P(c,tiny)] for a,b,c in rows] x=Table(data,colWidths=[v*cm for v in widths],repeatRows=1) x.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),color),('TEXTCOLOR',(0,0),(-1,0),WHITE),('GRID',(0,0),(-1,-1),.35,HexColor('#C7D7DE')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5),('ROWBACKGROUNDS',(0,1),(-1,-1),[WHITE,SKY])])) return x S=[] S += [Spacer(1,2.2*cm),banner('UNIT 1 | ENTERTAINMENT & HABITS',ORANGE),Spacer(1,.6*cm),P('Natural English<br/>expressions',title),P('Phrasal verbs, fixed phrases and tactful disagreement',sub),Spacer(1,.75*cm)] cover=Table([[P('<b>Recognise</b><br/>Learn the exact chunk, not separate words.',body),P('<b>Understand</b><br/>Read the short meaning and note.',body),P('<b>Reuse</b><br/>Adapt the expression to your own opinion.',body)]],colWidths=[5.66*cm]*3);cover.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),MINT),('BACKGROUND',(1,0),(1,0),PEACH),('BACKGROUND',(2,0),(2,0),LILAC),('BOX',(0,0),(-1,-1),.6,HexColor('#B5C8D1')),('INNERGRID',(0,0),(-1,-1),.5,HexColor('#B5C8D1')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),12),('BOTTOMPADDING',(0,0),(-1,-1),12)]));S += [cover,Spacer(1,1*cm),box('What is inside?','The first lists preserve language from the source lesson. Additional B2 items are marked <b>B2+</b>. They are useful for conversations about free time, films, books, music and opinions.',SKY,TEAL),PageBreak()] S += [P('1. Expressions from the lesson',h1),P('Phrasal verbs and fixed expressions used in the original lesson.',body),P('Phrasal verbs',h2),table([('<b>go out</b>','leave home to socialise or enjoy entertainment','We <b>go out</b> less often now.'),('<b>hang out</b>','spend relaxed, informal time with other people','We used to <b>hang out</b> all the time.'),('<b>take over</b>','become so dominant that it controls a situation','TikTok has <b>taken over</b> his life.')],color=TEAL),Spacer(1,.2*cm),P('Fixed phrases, idiomatic language and binomial',h2),table([('<b>now and then</b>','occasionally; not very often','I read novels <b>now and then</b>.'),('<b>as a rule</b>','generally; in most cases','<b>As a rule</b>, I avoid dance music.'),('<b>my kind of thing</b>','something that matches my taste','Opera is not really <b>my kind of thing</b>.'),('<b>do much for me</b>','give me pleasure, interest or a strong reaction','The film did not <b>do much for me</b>.'),('<b>for my liking</b>','in my personal opinion or according to my taste','It was too weird <b>for my liking</b>.'),('<b>all the time</b>','very frequently or constantly','He is online <b>all the time</b>.'),('<b>not as much as I’d like to</b>','less frequently than I want','I do not travel <b>as much as I’d like to</b>.')]),Spacer(1,.16*cm),box('Note on <b>now and then</b>','This is a <b>binomial</b>: a fixed pair linked by <i>and</i>. Its meaning is “occasionally”.',LILAC,PINK),PageBreak()] S += [P('2. Useful B2+ expressions for entertainment',h1),P('These additions are suitable for discussing films, books, music and leisure activities.',body),P('Phrasal verbs',h2),table([('<b>be into</b>','be very interested in or enthusiastic about','I am really <b>into</b> crime novels.'),('<b>grow on</b>','become more enjoyable as time passes','The album slowly <b>grew on</b> me.'),('<b>put off</b>','make someone lose interest in something','The slow opening <b>put me off</b>.'),('<b>catch up on</b>','do something you have not had time to do','I am <b>catching up on</b> a series.'),('<b>turn out</b>','develop in a particular way; have a final result','The film <b>turned out</b> to be excellent.'),('<b>stand out</b>','be noticeably better or more unusual','The soundtrack really <b>stood out</b>.')],color=TEAL),Spacer(1,.2*cm),P('Idiomatic and fixed language',h2),table([('<b>right up my street</b>','exactly the type of thing I enjoy','A historical drama is <b>right up my street</b>.'),('<b>not my cup of tea</b>','not something I personally enjoy','Reality TV is not <b>my cup of tea</b>.'),('<b>hit the spot</b>','be exactly satisfying or suitable','That light comedy really <b>hit the spot</b>.'),('<b>have a soft spot for</b>','feel special affection for','I <b>have a soft spot for</b> old jazz.'),('<b>on the whole</b>','generally, considering everything','<b>On the whole</b>, it was well made.'),('<b>pros and cons</b>','advantages and disadvantages','The book has its <b>pros and cons</b>.')]),PageBreak()] S += [P('3. Disagreeing politely: B2 conversation',h1),P('A tactful disagreement usually recognises the other view first, then presents a different personal view in measured language.',body),P('Source-lesson softeners',h2),table([('<b>I guess, but …</b>','signals partial agreement before a contrast','I <b>guess</b> it is popular, <b>but</b> it is not for me.'),('<b>I suppose, but …</b>','a mild, non-confrontational contrast','He is talented, <b>I suppose</b>, but …'),('<b>to be honest</b>','introduces a sincere personal opinion','<b>To be honest</b>, I am not that keen on it.'),('<b>not that keen on</b>','a gentle way to say you do not like something','I am <b>not that keen on</b> action movies.'),('<b>a bit</b>','softens a negative adjective','It is <b>a bit</b> too commercial for me.'),('<b>for my liking</b>','limits the opinion to personal taste','It is too over-the-top <b>for my liking</b>.'),('<b>not really my kind of thing</b>','softly says something does not suit your taste','Opera is <b>not really my kind of thing</b>.')],color=PINK),Spacer(1,.2*cm),box('Useful pattern','<b>Yeah, I can see why you like it, but to be honest, I am not that keen on it. It is a bit too over-the-top for my liking.</b>',LILAC,PINK),PageBreak()] S += [P('4. Disagreeing politely: B2+ toolkit',h1),P('Use these expressions when you need to disagree clearly without sounding dismissive.',body),P('Diplomatic phrases and idioms',h2),table([('<b>I see your point, but …</b>','acknowledges the other person’s argument before disagreeing','<b>I see your point</b>, but the plot felt predictable.'),('<b>I take your point, but …</b>','a slightly more formal way to recognise an argument','<b>I take your point</b>, but I found it disturbing.'),('<b>I am not sure I agree.</b>','a cautious, direct disagreement','<b>I am not sure I agree</b>; it was not gripping.'),('<b>I would not go that far.</b>','says the other opinion is too strong','I liked it, but <b>I would not go that far</b>.'),('<b>I beg to differ.</b>','polite but firm disagreement; often formal or playful','<b>I beg to differ</b>; the ending worked well.'),('<b>each to their own</b>','people have different tastes; accept the difference','I dislike it, but <b>each to their own</b>.'),('<b>agree to disagree</b>','accept that agreement will not be reached','Let us <b>agree to disagree</b> on that film.'),('<b>fair enough</b>','accept another view or decision, even if you differ','You prefer thrillers? <b>Fair enough</b>.')],color=PINK),Spacer(1,.2*cm),P('Phrasal verbs and fixed language for measured discussion',h2),table([('<b>go along with</b>','agree with or accept an idea','I cannot really <b>go along with</b> that view.'),('<b>come round to</b>','gradually begin to agree or change your opinion','I eventually <b>came round to</b> your view.'),('<b>hear someone out</b>','listen fully before responding','Let me <b>hear you out</b> first.'),('<b>meet someone halfway</b>','reach a compromise','We can <b>meet halfway</b> and choose a comedy.'),('<b>see eye to eye</b>','share the same opinion','We do not <b>see eye to eye</b> on reality TV.'),('<b>give someone the benefit of the doubt</b>','choose to believe someone or judge them positively despite uncertainty','I will <b>give it the benefit of the doubt</b>.')],color=TEAL),Spacer(1,.18*cm),box('Conversation tip','Avoid “You are wrong.” Prefer: <b>I see your point, but …</b>, <b>I am not sure I agree</b>, or <b>That may be true, although …</b>. Then give one short reason.',MINT,TEAL)] doc=SimpleDocTemplate(OUT,pagesize=A4,leftMargin=2*cm,rightMargin=2*cm,topMargin=1.65*cm,bottomMargin=1.85*cm,title='Natural English Expressions',author='Orris') doc.build(S,canvasmaker=NumCanvas) print(OUT,os.path.getsize(OUT)) PY python "/tmp/workspace/entertainment_english_handbook/src/create_expression_handbook.py" python - <<'PY' from pypdf import PdfReader p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Expressions_B2.pdf';r=PdfReader(p);print('pages',len(r.pages),'bytes',__import__('os').path.getsize(p)) for i,x in enumerate(r.pages): t=x.extract_text() or '';print(i+1,len(t),t[:56].replace('\n',' | ')) PY
python - <<'PY' import pdfplumber p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Expressions_B2.pdf' with pdfplumber.open(p) as pdf: for i,page in enumerate(pdf.pages,1): words=page.extract_words() left=min(w['x0'] for w in words); right=max(w['x1'] for w in words) top=min(w['top'] for w in words); bottom=max(w['bottom'] for w in words) print(f'page {i}: bounds x={left:.1f}..{right:.1f} of {page.width:.1f}, y={top:.1f}..{bottom:.1f} of {page.height:.1f}, words={len(words)}') assert left>=50 and right<=545, 'outside safe horizontal bounds' print('Margin validation passed') PY
python - <<'PY' import pdfplumber p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Expressions_B2.pdf' with pdfplumber.open(p) as pdf: for i,page in enumerate(pdf.pages,1): ws=page.extract_words() out=[w for w in ws if w['x0']<40 or w['x1']>555] print('\nPAGE',i,'OFFENDERS',len(out)) for w in out[:20]:print(w['text'],round(w['x0'],1),round(w['x1'],1)) PY
python - <<'PY' p='/tmp/workspace/entertainment_english_handbook/src/create_expression_handbook.py' s=open(p,encoding='utf8').read() old="""def box(head,text,bg=SKY,edge=BLUE): x=Table([[P(head,ParagraphStyle('xx',parent=h2,textColor=edge,spaceBefore=0,spaceAfter=2)),P(text,body)]],colWidths=[17*cm]);x.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.65,edge),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),7),('BOTTOMPADDING',(0,0),(-1,-1),7)]));return x """ new="""def box(head,text,bg=SKY,edge=BLUE): # A one-column, two-row layout keeps all callout text safely inside the page margins. x=Table([[P(head,ParagraphStyle('xx',parent=h2,textColor=edge,spaceBefore=0,spaceAfter=2))],[P(text,body)]],colWidths=[17*cm]) x.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.65,edge),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),7),('BOTTOMPADDING',(0,0),(-1,-1),7)])) return x """ assert old in s open(p,'w',encoding='utf8').write(s.replace(old,new)) PY python "/tmp/workspace/entertainment_english_handbook/src/create_expression_handbook.py" python - <<'PY' import pdfplumber, os p='/tmp/workspace/entertainment_english_handbook/output/Entertainment_English_Expressions_B2.pdf' with pdfplumber.open(p) as pdf: print('pages',len(pdf.pages),'bytes',os.path.getsize(p)) for i,page in enumerate(pdf.pages,1): words=page.extract_words() left=min(w['x0'] for w in words); right=max(w['x1'] for w in words) print(f'page {i}: x={left:.1f}..{right:.1f} | safe bounds 50..545') assert left>=50 and right<=545, f'page {i} exceeds safe horizontal margins' print('Margin validation passed') PY
Entertainment English Expressions B2
PDF Document · PDF