Try out our Premium Member services: Virtual Legal Assistant, Query Alert Service and an ad-free experience. Free for one month and pay only if you like it.
BEFORE THE NATIONAL GREEN TRIBUNAL (PRINCIPAL BENCH), NEW DELHI APPEAL No. 22/2011 18TH JULY, 2013 CORAM: 1. Hon'ble Shri Justice V.R. Kingaonkar (Judicial Member) 2. Hon'ble Shri Justice U.D. Salvi (Judicial Member) 3. Hon'ble Dr. P.C. Mishra (Expert Member) 4. Hon'ble Shri P.S. Rao (Expert Member) 5. Hon'ble Shri Bikram Singh Sajwan (Expert Member) B E T W E E N: 1. Mahesh Chandulal Solanki R/o Village Samagogha, Taluka Mundra, District-Kutch Gujarat 2. Aniruddhsinh Kakubha Jethava R/o Village Samagogha, Taluka Mundra, District- Kutch Gujarat ....Appellants AND 1|Page 1. Union of India Through the Joint Secretary, Ministry of Environment & Forests Paryavaran Bhawan, C.G.O Complex, Lodhi Road, New Delhi -110003 2. Member Secretary, Gujarat Pollution Control Board, Pariyavaran Bhavan, Sector 10-A, Gandhinagar-382010 3. The Collector Office of Collectorate, Jilla Seva Sadan, Bhuj, District: Kutch, Gujarat 4. State Level Expert Appraisal Committee, Gujarat Pollution Control Board, Pariyavaran Bhavan, Sector-10-A, Gandhinagar 382010 5. Jindal SAW Limited through General Manager/ Authorised Representative, Village Samagogha, Taluka Mundra, District Kutch 6. Samagogha Jooth Gram Panchayat, Through its Sarpanch, Village Samagogha, Taluka Mundra, District Kutch ......Respondents 2|Page (Advocates appeared: Mr. Abhimanue Shrestha and Mr. Abhas Mishra along with Ms. Sridevi Panikkar, Advocates for the Appellant, Ms. Neelam Rathore, Advocate for Respondent No. 1, Mr. Satyabrata Panda, Advocate for Respondents No. 2 to 4 and Mr. Arun Kumar Varma along with Mr. Ashish Bansal, Advocates for Respondent No. 5) (Judgment) 1. Environmental Clearance (EC) granted by the State Level Environment Impact Assessment Authority ( "SEIAA" in short) of Gujarat State vide Order No. SEIAA/ GUJ/ EC/ 3(a)/122/2011 dated 23.6.2011 permitting M/S Jindal Saw Limited, the Respondent No.5, for expansion of "Smaller Diameter Ductile Iron Pipe" Plant upon land bearing Survey Nos. 334/1,335,336/2 & 336/3, of Village Samaghogha, Taluka: Mundra, District: Kutch and incidental amendment thereto dated 9.8.2011, are assailed in the present Appeal. 2. The Appellants, residents of village Samaghogha, situated in the proximity of the proposed project site, claim that the environment, in which they live and make their living is going to be affected seriously as a result of the expansion of the said "Ductile Iron Pipe" Plant; and more so as the village Samaghogha is substantially polluted due to concentration of several industries including manufacturing unit of the Respondent No. 5 producing iron pipes, having come up within the limits of Village Samaghogha. 3. Facts
leading to the impugned Environmental Clearance (in Short 'EC') and amendment thereto are as under:
The Respondent No. 5 established a Blast furnace and Ductile Iron (DI) Pipe manufacturing Unit at Village Samaghogha after
3|Page duly obtaining various governmental and regulatory clearances including Environmental Clearance dated 21.10.2004. DI Pipes were / are manufactured from the molten iron metal obtained from Blast furnace. The respondent No. 5 proposed expansion of the capacity of its existing Blast furnace with addition of new blast furnace of capacity of 2, 80,000 TPA in the year 2009, and for this purpose EC was obtained from the Government of India, Ministry of Environment & Forests ( MoEF) on 26.11.2009. The Gujarat State Pollution Control Board issued 'consent to establish' the said project on 13.4.2010.
The Respondent No. 5 took a decision to establish a separate facility for producing smaller Diameter DI Pipes in its existing factory at Samaghogha, and pursuant thereto applied for necessary EC therefor to the Respondent No. 4 - State Level Expert Appraisal Committee (In short, 'SEAC') it being the project falling under category B- Activity No. 3(a)(c) in the schedule of Environment Regulation, 2006 issued vide Notification No. S.O 1533( E) dated 14.9.2006 ( in short EC Notification).
In the meeting of SEAC held on 30.9.2010 the Application of the Respondent No. 5 for finalisation of Terms of Reference (in short 'ToR') for EIA study was considered. ToR dated 30.11.2010 were issued and communicated to the Respondent No. 5 thereafter. However, the EIA study was carried out between October 2010 and December, 2010. Based on this EIA study, a draft EIA Report and its summary were prepared by the Respondent No. 5 and the same were submitted to the Respondent No. 4- SEAC.
Thereupon, the process of holding a Public Hearing was initiated and it was scheduled to be held on 29.3.2011. A public notice in that regard, as contemplated under the EC
4|Page Notification was published in issues dated 27.2.2011 and 2.3.2011 of 'Divya Bhasker' - a daily newspaper in vernacular language (Gujarati) and 'The Times of India' - a daily national newspaper in English, respectively. As scheduled the Public Hearing was held in the school- O.P. Jindal Vidhya Niketan School run by the Respondent No. 5 at village Samaghogha. Members of public gathered, numbering 275 persons, were heard and responded to by the project proponent in the presence of Additional District Magistrate and Additional District Collector, District Kutch and the Regional Officer of Gujarat Pollution Control Board, Bhuj. Ultimately, on appraisal of the final EIA Report and outcome of the Public Consultations the SEAC recommended grant of Environmental Clearance on certain terms and conditions to the said project, which resulted in grant of impugned Environmental Clearance by the SEIAA.
4. According to the Appellants, the entire process of grant of Environmental Clearance is tainted for the following reasons:
1. Construction of the project was started prior to the grant of Environmental Clearance.
2. ToR were issued on 30.11.2010. However, the EIA study was done between October 2010 and December, 2010 prior to the communication of ToR.
3. Notice of Public Hearing was not adequate in terms of the mandate of EC Regulation.
4. Summary of EIA Report was not supplied in vernacular language in stipulated time.
5. Summary of EIA Report was inadequate and not as required by the EC Regulation.
6. Public hearing was not held in neutral venue so as to permit free, fair and open participation of the members of public.
7. Minutes of meeting were not prepared or read over to the participants as required.
5|Page
8. There was no detailed scrutiny of final EIA Report and outcome of Public consultation for the purpose of appraisal as required under the said Regulation and the grant of EC was recommended mechanically by the SEAC; in violation of the mandate of the EIA Notification.
5. The Respondent No. 4 -SEAC Gujarat, resisted the appeal with an affidavit in reply dated 6.11.2012 and placed before us its version of events leading to the grant of EC in question.
6. The Respondent No. 5 controverted the appellant's case vide affidavit in reply dated 19.1.2012 and annexures thereto, and further offered explanation regarding the facts in controversy.
7. Counsel for the parties were heard at length. Ld. Adv. Sri Abhas Mishra for the appellant's tendered written submissions on 12.3.2013, and reiterated the prayers in the Appeal. He placed before us bunch of judicial precedents as follows:
1. T. Mohan Rao Vs. MOEF (Appeal No. 23/2011,Dt.23.05.2012)
2. M/s Vedanta Aluminium Ltd. Vs. UOI (WP(C) No. 19605 of 2010, Dt. 19.07.2011)
3. Jagpal Singh Vs. State of Punjab in (2011) 11 SSC 396
4. Akhil Bhartiya Upbhokta Congress Vs. State of Madhya Pradesh (2011) 5 SCC 29
5. Noida Entrepreneurs' Assn. Vs. Noida (2011) 6 SCC 508
6. Delhi Airtech Service Vs. State of UP (2011) 9 SCC 354
6|Page
7. Humanity & Ors. Vs. State of WB (2011) 6 SCC 125
8. Utkarsh Mandal Vs. UOI (WP(C) No. 9340 of 2009)
9. Intellectual Forum Vs. State of AP (2006) 3 SCC 549
8. Inviting our attention to the record, Ld. Adv. Shri Arun Kumar Varma for the Respondent No. 5 submitted that the entire proceedings of the Public Hearing were videographed and nothing more needs to be scrutinised to ascertain the manner in which such proceedings of Public Consultation were held. He further submitted that the Respondent No. 5 had commenced the construction activities for setting up of the new blast furnace within the available open area of its factory premises at Village Samagogha in a bid to expand steel plant on the strength of EC granted dated 26.11.2009 and "Consent to Establish" dated 13.4.2010; and no sooner it was objected to vide notice dated 18.3.2011 issued under Sec. 33(A) of the Water (Prevention and Control of Pollution) Act, 1974, the Respondent No. 5 had stopped the said construction activities and given an undertaking dated 19.3.2011 to abide by such directions to the Respondent No. 4; and SEAC had appraised the project only after the construction work was stopped and given green signal to the grant of EC to the project upon due consideration of the final EIA Report and outcome of Public Consultation.
Ld. Adv. Verma for the Respondent No. 5 further pointed out that the Office Memorandum dated 19.8.2010 issued by the Ministry of Environment and Forests, Govt. of India restrained all the projects undertaken without Environmental Clearance from going on with the construction activity except fencing of the site to protect it from getting encroached and construction of temporary sheds for the guard(s).
7|Page MoEF is vested with sufficient discretion to suspend or revoke the Terms of Reference (ToR) and also to invoke the Penal provisions. He further pointed out that the MoEF has not exercised the discretion so vested to suspend or revoke the proceedings for grant of Environmental Clearance but has opted for invoking penal provisions for initiation of prosecution of the Project Proponent for the lapses committed by it.
As regards to carrying out the EIA study prior to the communication of TOR, Learned Advocate for the Respondent No. 5 invited our attention to the minutes of the meeting in which the TOR were settled. He pointed out that the Project Proponent was present at the time of settlement of ToR and as such had the knowledge about the TOR on the basis of which EIA study was carried out before the ToR were issued or officially communicated. He submitted that there is nothing to point out that the EIA study thus carried out was contrary to Terms of Reference (ToR) as settled in the said meeting or that it did not meet the expectation for which such study is designed.
Learned Advocate for the Respondent No. 5 invited our attention to the Public Notice on Public Hearing published in Gujarati Daily Newspaper "Divya Bhasker" issue dated 27.2.11 vide Annexure-5 in Compilation II of the Appeal, and submitted that notice of Public Hearing was published in Vernacular language in time for the benefit of the public at large, particularly the local people, in as much as it was adequate in terms of the mandate of Environment Clearance Regulations/EIA Notification. Adverting to Annexure R-8 & R- 9 Annexed to the reply filed by the Respondent No.5- the copy of the letter dated 1.3.2011 of Gujarat State Pollution Control Board (GSPCB) issued by its Regional Office and the acknowledgments obtained by Gujarat State Pollution Control Board (GSPCB) acknowledging the receipt of summary of EIA report, he submitted that the exception taken on the ground of
8|Page non- supply of summary of EIA report in Vernacular language is without any merit.
Further inviting our attention to the minutes of Public Hearing the Learned Advocate for the Respondent No. 5 submitted that all the issues raised in Public Hearing were suitably addressed and the same were duly considered by the SEAC before recommending the grant of EC. He submits that there is no violation of EIA Notification while granting the EC in question and the Appeal deserves to be dismissed.
Controversies thus raised calls for answering the following points:
1 Whether the construction of the project was started prior to the granting of Environmental Clearance in question. 2 Whether summary of EIA report was not furnished in Vernacular Language.
3 Whether summary of EIA report was inadequate and not as required by the Environmental Clearance Regulations /EIA Notification.
4 Whether the Public Hearing was not held in neutral venue. 5 Whether there is any contravention of the Environmental Clearance Regulations /EIA Notification.
6 Whether any such contravention would vitiate the grant of Environmental Clearance in question.
Reasons Point No. 1. Admittedly, the Respondent No. 5, namely the Project Proponent, had commenced the construction activity for setting up of new Blast Furnace within the available open area of its factory premises at Village Samaghogha. Reply to the Appeal dated 19.1.2012 filed by the Respondent No. 5 reveals that it had commenced the said construction activity for setting up of the new Blast Furnace in a bid to expand steel
9|Page making plant on the strength of EC dated 26.11.2009 and during the continuance of the said construction activity decision was taken to expand its DI Pipe Plant within the said area which had resulted in making of Application for obtaining necessary EC in question. Respondent No. 5 further averred that since there were certain common technical features between the Steel making expansion plant and the DI Pipe expansion plant, construction continued for some time after the Application for grant of Environmental Clearance for the DI Pipe Plant i.e. Environmental Clearance in question was made. However such construction was stopped and undertaking dated 19.3.2011 not to undertake any excavation and foundation work relating to the plant expansion project was given on receiving notice/directions dated 18.3.2011 issued under section 33(a) of the Water (Prevention and Control of Pollution) Act, 1974, by the Respondent No. 4.
Photographs in Annexure-4 to the Appeal show excavation and foundation work and nothing beyond it. However, the Respondent No. 5 has not clarified in its Affidavit in reply as to what were those common technical features between the Steel making expansion plant and DI expansion Plant thereby clearly indicating the works involving such common technical features undertaken by it . As a result the point needs to be answered affirmatively.
Point No. 2. Perusal of the copy of the letter dated 1.3.2011 of Gujarat State Pollution Control Board and the acknowledgment obtained by GSPCB at Annexure R-8 & R-9 respectively to the reply filed by the Respondent No. 5 , irrefutably and vividly reveals delivery of draft and summary of EIA report ( in English and Gujarati) to the local bodies /Authorities namely the 10 | P a g e District Collector, District Development Officer, General Manager of District Industrial Centre, District, Kutch. Chief Conservator of Forest, Taluka Development Officer, Taluka Mundra District, Kutch as well as to the local Gram Panchayat between 3.3.2011 and 16.3.2011. Pertinently no grievance was raised by anybody in that regard in time prior to filing of the present Appeal much less at or before the Public Hearing in question. Grievance in that regard is, therefore, a far cry from the truth. The point is therefore answered negatively.
Point No. 3. Public consultation is one of the stages prescribed in the Environmental Clearance Regulations in the process of granting EC. It is the process by which concerns of local affected persons and others who have a plausible stake in the environmental impacts of the project or activity are ascertained with a view to taking into account all the material concerns in the project or activity design as appropriate. To facilitate effective Public Consultation summary EIA Report both in English and Vernacular language are prepared. The Environmental Clearance Regulations, 2006 at para 7, stage-3 Public consultation --- sub para (vi)refer to inviting of responses from other concerned persons by placing on the website of the concerned Regulatory Authority the summary EIA report prepared in the format given in Appendix (III-A) along with a copy of the Application in the prescribed form. Appendix (III) A describes the contents of summary EIA Assessment in following words:
The summary EIA shall be a summary of the full EIA report condensed to ten A-4 size pages at the maximum. It should necessarily cover in brief the following chapters of the full EIA report.
1 Project Description 11 | P a g e 2 Description of the Environment 3 Anticipated Environmental Impacts and mitigation measures 4 Environmental Monitoring programme 5 Additional Studies 6 Project Benefits 7 Environment Management Plan Copies of the executive summary of the project (15 pages) in English and Gujarati languages are made available for our perusal by the Appellant at Annexure A-9 Compilation-II.
The relevant information about the project in question in brief is made available through the said report under the following heads and sub heads:
1 Introduction of the company, (2)Location of the project, (3)Legal requirement, (4) Project review, (5) EIA methodology, (6)Project details
(i)Purpose of the project, (ii)Location and salient features of the project, (iii)Resource requirement:,
(iv)Water requirement, (2)Fuel requirement, (3)Raw Material requirement, (4)Man power 7 Base line status of study area (1) Meteorology, (2) Rainfall ( 3) Temperature.
8 Onsite meteorology (1)Wind speed and direction, (2)Temperature, (3)Relative humidity, (4)Rainfall, (5)Ambient air quality, (i)Suspended particulate matter(PM10), (ii)Suspended particulate matter(PM 2.5), (iii)Sulfur dioxide (SO2, (iv) Oxide of Nitrogen(NO2), (6)Soil Environment, (7)Water Environment (8)Noise Environment, (9)Land use pattern (10) Demography of 12 | P a g e Socio Economic Status, (11)Impact Assessment and Environmental Management Plan, (11)(i) Air Pollution and Mitigation Measures, (11)(ii)Noise Pollution and Mitigation Measures, (11)(iii) Water Pollution and Mitigation Measures, (11)(iv)) Land Pollution and Mitigation Measures, (12)Social Welfare Activities and Green Belt, (13) Risk Assessment.
Environmental Clearance Regulations, 2006 casts duty on the Project Proponent to address all the material environmental concerns. Thus, the focal point of EIA report is anticipated environmental impact and mitigation measures. We find in summary EIA report reference to assessment of air pollution, noise pollution, water pollution and land pollution at Para No. 8(11)(1) to 8(11)(4)and mitigation measures to be adopted by the Project Proponent. Except a statement nothing has been pointed out by the Appellant to show how this EIA report was inadequate so as to thwart public response as contemplated in EC Regulations. The point is, therefore, answered negatively.
Point No. 4. Admittedly, the Public Hearing in the present case was held in the premises of the O. P. Jindal Vidhya Niketan school run by the Respondent No. 5 company in Village Samaghogha. According to the Learned Counsel for the Appellant the venue of holding of Public Hearing was not a neutral one the same being within the premises of the school run by the Respondent No. 5 company and, therefore, such venue was not conducive to free, fair and open participation of the locals as well as other persons who were likely to be affected by the proposed project. In this context our attention was invited to para 7 stage-3 (iii) of the Environmental Clearance Regulations, 2006, by the Learned Counsel for the Respondent No. 5. According to him, there was no legal impediment for holding Public Hearing in the premises under 13 | P a g e the control of Project Proponent. Environmental Clearance Regulation, 2006 mandates at the said provision as follows :-
The Public Hearing at 'or in close proximity to' the site(s) in all cases shall be conducted by the SPCB or the UT Pollution Control Committee concerned in the specified manner and forward the proceedings to the Regulatory Authority concerned within 45 days of request to the effect from the Applicant.
Nowhere Environmental Clearance Regulations, 2006 abjures the use of premises in control of the Project Proponent but in fact chooses the very site of the project which is in control of the Project Proponent, for holding a Public Hearing.
Answer to the question as to why this is so can be easily found in the purpose of holding a Public Hearing. A Public Hearing is one of the components of Public consultation and is the process by which concerns of local affected persons who are likely to suffer due to the environmental impact of project or activity, are ascertained. Naturally, therefore it is expected to hold a public Hearing at or in close proximity to the project site in order to ensure and facilitate wide participation of the Public particularly those who are likely to be affected by the project, being in close proximity. Needless to say that the environmental impact of any project or activity is likely to be felt or perceived immediately and pronouncedly by the local persons living in close proximity of the project site and as such they richly deserve participation in Public Consultation with ease. As a corollary to the mandate of the Environmental Clearance Regulation, 2006 as aforesaid it can be seen that holding of Public Hearing at the project site implies holding of Public Hearing at a place under the control of the Project Proponent. Legally, therefore there can be no sustainable legal exception to holding of a Public Hearing at the premises controlled by the Project Proponent more so when there is no case that the Public Hearing was not held in close proximity 14 | P a g e to the project and as such it posed inconvenience to the members of the public particularly the local persons in attending the proceedings of Public consultation Perusal of the record, both documentary and video graphic, reveals that the Public Hearing was held in the presence of Additional District Magistrate and Additional District Collector, District Kutch, the Regional Officer of PCB, Bhuj and was attended by 275 persons from various villages including the village Samaghogha situated around the said site. It is clearly demonstrated that the Members of the Public were provided with the platform for free, fair and open participation at the said venue. Nothing was pointed from the record that anything was amiss in holding of Public Hearing at the said venue which could be construed as violation of Environmental Clearance Regulations 2006. The point is, therefore, answered is negatively.
Point No. 5 Environmental Clearance Regulations is essentially the product of exercise of power conferred by sub- section (1) and Clause (v) of sub Section (2) of Section (3) Environment (Protection) Act, 1986 read with Clause (d) of sub Rule (3) of Rule (5) of the Environment(Protection) Rules, 1986. Thus, it is a piece of delegated Legislation stipulating the requirements of prior EC from the Central Government as the case may be by SEIAA duly constituted by the Central Government under the said Act, for construction of new projects or activities or the expansion or modernization of existing projects or activities listed in the Schedule there under, anywhere in India. Besides categorization of the projects or activities based on the spatial extent of potential impacts on human health and natural and manmade resources and classifying authorities empowered to grant prior EC, the said regulations charter a course to be adopted in the process of granting EC. Substantially, it governs the matters of procedure relating to grant or rejection of prior EC.
15 | P a g e Keeping this in mind one has to apply the standards stipulated therein to evaluate the process of grant of EC. Evidently a public notice in respect of Public Hearing scheduled to be held on 29.3.2011 was duly published in issues dated 27.2.2011 and 2.3.2011 of "Divya Baskar" daily newspaper in vernacular language (Gujarati) and the "Times of India "daily newspaper in English respectively. The Respondent No. 5 have categorically averred that requisite numbers of hard and soft copies of EIA report including the summary of EIA report in English and in Gujarati were communicated after scoping as per Clause- 2.2, Appendix 4 of EC Regulations/EIA Notification, 2006. It is also revealed that the Respondent No. 4 had forwarded a copy of EIA Report and summary EIA Report in English and in Gujarati to the local authorities with request to display the same and to make them available to the public at large. It is also evident that the Respondent No. 4 had also directly supplied the summary of EIA Report to as many as 16 Gram Panchayats in the vicinity. The Respondent No. 5 averred that the EIA and its summary were available on the website of Respondent No. 4 where anybody could get a copy of the same.
If one looks into the Appendix -IV to the Environmental Clearance Regulations, 2006 it is not difficult to find that the Applicant seeking EC is required to forward to the SPCB a letter of request to arrange the Public Hearing along with ten hard copies and equivalent numbers of soft copies of draft EIA Report including the summary of EIA Report in English and in state/Local Language and to make arrangements to forward such copies that is one hard and one soft of the draft EIA Report along with summary EIA Report to the authorities namely District Collector/ Magistrates/Zilla Parishad or Municipal Corporation, Panchayat Union, District Industries Office, Urban Local Bodies and Concerned Regional Officer of MoEF, who are obliged to make available the draft EIA Report 16 | P a g e for inspection electronically or otherwise to the public during normal office hours. The Concerned SPCB is also required to make similar arrangement for giving publicity about the project in question. Pertinently, no outer limit of time is given for such publicity prescribed under sub Para 2.2 Appendix-IV of Environmental Clearance Regulations, 2006. However, sub Para 3.1 of the said Appendix speaks of the advertising of the notice of Public Hearing in news media and further stipulates a minimum notice period of 30 days to the public for furnishing their responses. Pertinently, this concerns Public Hearing which is one of the component of the Public consultation process devised to ascertain concerns of local affected persons.
Undoubtedly, in the instant case, the object of giving clear notice of 30 days of the proposed Public Hearing to the local persons could be said to have been very well achieved by publication of the notice in State/ Vernacular language i.e. Gujarati Daily News Paper "Divya Bhaskar" issue dated 27.2.2011. This can also be discovered from the material placed before us i.e. the responses received in Gujarati as well as in English from the locals and others as well as responses to the publication of draft EIA Report electronically. A little delay in publication of the notice of Public Hearing in the 'The Times of India' has made any difference with the process of ascertaining the concerns of local affected persons.
The Respondent No. 5 has not disputed the fact of having commenced EIA study in October, 2010 and having completed it in December, 2010. Thus, the EIA study was commenced prior to final communication of ToR dated 30.11.2010. Reading of Affidavit in reply of Respondent No. 4 dated 6.11.2012 and the Annexures thereto clearly reveals that the Respondent No. 5 (Project Proponent) was present in the meeting dated 30.9.2010 of State Level Expert Appraisal Committee( for short 'SEAC') when the issue of ToR was 17 | P a g e deliberated upon and ToR dated 30.11.2010 were duly settled. Thus the Respondent No. 5 (Project Proponent) did gather the knowledge of the ToR and, therefore, could embark upon the EIA study in October, 2010 Official Communication of ToR vide letter dated 30.11.2011 of State Level Expert Appraisal Committee therefore has worth only of creating official record of the communication of the ToR and nothing more. Commencement of EIA study in October, 2010 therefore cannot be regarded contravention of Environmental Clearance Regulations by embarking upon the EIA study before the communication of ToR.
So far as the commencement of the construction of project is concerned the Respondent No. 5 did over step the limitation imposed by EC Regulations. However it is also a fact that the construction activity was undertaken and was halted, on an undertaking given to abide by the directions issued by the Respondent No. 4 SEAC. Cognizance of this fact was taken by the State Level Expert Appraisal Committee in its meeting dated 9.5.2011 vide minutes of the meeting at Annexure -2 to the Affidavit in the reply of Respondent No. 4 (SEAC) dated 6.11.2012. The Affidavit of the Respondent No. 4 further reveals that the Gujarat State Pollution Control Board's officials had visited the project site on 19.5.2011 and noticed that the excavation and foundation work was stopped by the Project Proponent and no construction equipment or activity was seen at the site vide Annexure R-3 Affidavit in reply of the Respondent No. 4, SEAC.
Reading of Annexure R-3 to the Affidavit in reply of the Respondent No. 4 (SEAC) reveals that the SEAC in its 103rd meeting dated 31.5.2011 did examine whether the proposed project or activity was appropriately categorized or not, examine its competence vis. a. vis the categorization of project or activities undertaken as per the Schedule of the said Notification, and thereafter considered the following points:
18 | P a g e
1. Developments leading to the appraisal of the proposed project.
2. Concerns of the local villagers namely closing of the cart track and alternative arrangement made therefor.
3. Construction work undertaken by the Project Proponent prior to the grant of Environmental Clearance.
4. Technical issues raised during the Public Hearing.
5. Project Profile including the water requirements, and effluent generation and measures to counter them.
6. Environmental study and the impact on the ambient air quality due to the proposed project.
7. Solid /Hazardous Waste disposal Ultimate para of the minutes of the SEAC dated 31.5.2011 which is quoted hereunder brings forth the mind of the members of the SEAC in recommending the case for EC.
"During the meeting, various issues raised during the public hearing were discussed at length. The main concerns during the public hearing were regarding starting construction work before prior environmental clearance, depriving farmers from their right to use existing cart track passing in between the proposed survey numbers, ground water extraction by the company, local employment, noise pollution etc. The project proponent explained that earlier they had planned to set up Steel Melting Shop at the place where the new DI Pipe Plant is proposed. He quoted that they obtained environmental clearance from the MoEF on 26/11/2009 for the Steel Melting Shop and they were to transfer molten metal from the new Mini Blast Furnace (2,80,000 TPA) to the Steel Melting Shop, which was to set up on other side of the existing cart track. He added that due to the market considerations, they have now planned to set up DI Pipe Plant at the same place where Steel Melting Shop was to be set up but in either case the molten metal had to be transferred from the new Mini Blast Furnace (2,80,000 TPA) and hence the existing cart road has to be 19 | P a g e closed in view of safety of the farmers passing through the track. The project proponent submitted (i) Extracts from the minutes of meeting of Board of Directors held on 12th May, 2011 and (ii) Notarized undertaking stating that they have provided an alternate new track for free and safe movement of people and it is hardly 400m from the existing track, new proposed track land will be dedicated for use of villagers and the company will not claim the ownership of the cart track land in future and they shall abide by the decision of the Court. However, the committee insisted the project proponent to get permission from the Mamlatdar, Mundra for the new proposed track. While asking by the committee, the project proponent clarified that due to the proposed expansion, production of hot metal/ pig iron shall not exceed 5,80,000 TPA for which EC was obtained from the MoEF on 26/11/2009. The committee felt that one of the reasons for agitation during the public hearing was failure of the company to fulfill the commitments made during the earlier public hearing and hence asked the project proponent to submit the CSR action plan for the year 2011-12 including the details on the proposed activities along with the budget allocation for the same. After deliberation on various issues, the committee decided to recommend the case to SEIAA for grant of environmental clearance after submission of following:
1). Permission from the Mamlatdar, Mundra allowing use of the alternate cart track.
2). Detailed CSR Action Plan for the year 2011-2012 including the details on the proposed activities along with the budget allocation for the same."
Thus, the minutes of the meeting of the SEAC clearly reveal that SEAC had not recommended the grant of EC mechanically and had applied its mind to the final EIA report and outcome of Public consultation for the purpose of appraisal as required under the said EC Regulations. Nothing 20 | P a g e has been pointed that the Minutes of the meeting were not recorded as per the EC Regulations. The point is, therefore, answered accordingly.
Point No. 6 Before arriving at the final conclusion it is necessary to consider the judgments cited on behalf of the Applicant. In T. Mohana Rao's Case this Tribunal, while allowing the Appeal, concluded that the public was deprived of the relevant information which formed the basis of grant of EC and , therefore , directed the MoEF to revisit EIA report from the stage of Public Hearing. It appears that the EIA study was carried out earlier to the settlement of ToR and the EIA did not contain the finding of the special studies thereby giving rise to the cloud of suspicion with regard to due application of mind by the EAC. It further appears that EIA Report was not available to anyone till the time of Public Hearing. Facts in the present case do differ from the facts of T. Mohana Rao's case as discussed above. In M/s Vedenta Aluminum Ltd. case the Hon'ble High Court of Orissa declined to reverse the decision of the MoEF to withdraw the TOR and consequently the Public Hearing organized in the process of grant of EC for expansion of Aluminum refinery on the ground that the Project Proponent had completed 50 to 55 per cent construction of the project prior to grant of EC. In the said case due opportunity was given to the Project Proponent by the MoEF to explain its conduct and only there after the impugned decision to withdraw the ToR was taken. The Hon'ble High Court of Orissa found justification in MoEF's view to hold the process for Environmental Clearance de novo and at Para 36 of its judgment made passing reference to settled legal proposition based on legal maxim "Expressio Uniusest exclusion alteris." What weighed most in the mind of Hon'ble High Court was the justifiable view of the MoEF to hold process of EC de novo vis. a. vis 50 to 55 % construction of the project prior to grant of EC.
21 | P a g e In Jagpal Singh's case the Hon'ble Apex Court while striking down the regularization of Gram Sabha Land in favour of unauthorized and illegal occupants observed that illegalities must not be permitted and condoned. In Akhil Bhartiya Upbhokta Congress's Case the Hon'ble Apex Court reiterated that perpetuation of illegality is not sustainable and nepotism was not to influence the discretion of the authority.
In Noida Entrepreneurs Assn. case the Hon'ble Apex Court while dealing with the matter of Judicial Review of the process of tendering commented with reference to Legal Maxim: "whenever a thing is prohibited, it is prohibited whether done directly or indirectly" and there was need for strict compliance with applicable norms.
In Delhi Airtech Service Case the Hon'ble Apex Court observed that the condition precedent under Section 17 (3-A) of the Land Acquisition Act, 1894 must be strictly construed as the expression "shall" in said provision primarily indicates mandatory compliance and this is more so considering expropriatory character, nature and the design of the said legal provisions. In Humanity and Another Case the Hon'ble Apex Court observed that the ends do not justify the means and state must not be arbitrary.
In Utkarsh Mandal's case the Hon'ble High Court of Delhi noticed flaw in the Public Hearing and proceeded to set aside the Environmental Clearance granted to two groups of mines and remanded the issue to the MoEF for fresh consideration of each of the objections raised at the Public Hearing and to render reasoned decision thereon. It appears that as many as six Public Hearings were scheduled in regard to the various projects including the mining projects in question by the SPCB on the same date, time and the venue and an executive summary was received by the Gram Panchayat of Village Rivona only nine days prior to the date of Public Hearing and the notice of Public Hearing declaring the availability of EIA 22 | P a g e Report and its summary was published in Indian Express dated 18.12.2006. All this the Hon'ble High Court observed can possibly result in avoidable chaos of such hearing and reduced the whole exercise to empty formality.
In Intellectual Forum Vs State of AP Case the Hon'ble Apex court reiterated the "Principle of Sustainable Development" with observations that balance is to be maintained between the development needs asserted and Environmental degradation alleged.
Taking cite from the aforesaid Judgments, the nature, character and design of the Environmental Clearance Regulations need to be examined. From the form and its content, Environmental Clearance Regulations can be seen as set rules governing the procedure of the grant or rejection of Environmental Clearance to the projects and activities enumerated therein. It has been so designed to dispense justice to the local affected persons, public at large and the Project Proponent keeping in mind all the material Environmental concerns. It is therefore, a tool to dispense justice and not the justice itself. Such being the position of the procedure and methodology expressed therein, the use of mandatory words therein may be construed as directory keeping in mind the course of justice.
From the facts it is disclosed before us that there is nothing to demonstrate or suggest that any lapse in strict compliance of the procedure prescribed in Environmental Clearance Regulations has in any way prejudicially affected the course of justice keeping in mind the material Environmental Concern. It is nobody's case that draft EIA report and its summary were not made available when asked for except saying that the same were received on 16.3.2011. Making available things and receiving it have different connotations. The word 'available' means able to be used or obtained whereas the word "receipt" has a connotation as 23 | P a g e what has been obtained. There is nothing before us to show that anyone was disabled for any reason to use or obtain draft EIA report or its summary after publication of notice of Public Hearing in Vernacular Daily Divya Bhaskar issue dated 27.2.2011. The amount of response i.e. placed before us is sufficient to demonstrate the publicity which was given to the draft EIA Report and its summary in Vernacular. No prejudice is seen to have been caused to the course of justice in the present case.
Perusal of the recommendation made by SEAC at Annexure R-4 to the affidavit reply of the Respondent No. 4 SEAC reveals conditions imposed for grant of such Environmental Clearance. No irrationality or procedural impropriety has been pointed out in making of such recommendations. The recommendations are exhaustive and the conditions stipulated, cover not only the general concerns of the locals but also govern the environmental parameters like water, air, noise, solid/ hazardous waste and green belt. Amendment to the Environmental Clearance done at later stage is incidental one made only to correct the description of the project. The point is, therefore, answered negatively.
9. Nevertheless, the Project Proponent did over step the limitation imposed by the Environmental Clearance Regulations by starting with the construction before grant of Environmental Clearance. Regarding construction activities undertaken prior to the grant of EC, we do not agree with the contention of the Project Proponent that the alleged construction work relates to the grant of earlier EC. It may not be proper to accept such contention in view of the fact that the Project Proponent, as revealed from the record, has been in the habit of flouting the procedure of Law by undertaking construction work during 2004 before the relevant EC was granted. Thus, the Respondent No. 5 (Project Proponent) was not the novice to procedure prescribed for grant of 24 | P a g e Environmental Clearance in as much as it had obtained Environmental Clearance before the Environmental Clearance in question.
10. It is also necessary to prescribe a safeguard for checking indiscriminate use of groundwater. The Gujarat State Pollution Control Board is directed to monitor the ground water levels and TDS of the water from bore wells within the premises of the Project Proponent every six months and also to take measures to check the depletion of ground water levels or TDS levels from going beyond the dangerous level.
11. Considering the fact that previously the project was subjected to grant of EC before expansion and that even though there was no EC issued by the MoEF yet the Project Proponent had started the construction activity, such conduct of the Project Proponent shows that he has no sense of impunity. The construction work had been started because the Project Proponent perhaps believed that the EC will be granted. The Project Proponent started such construction activity in 2004 also. It has been again repeated when the EC was sought in 2011. It is but natural to assume that the Project Proponent has no compunction in repeating the same kind of dereliction and proceeded to undertake the construction activity although prior EC was not granted for expansion of the project. The conduct of the Project Proponent is, therefore, reprehensible. The tendency to proceed with the project activity in spite of absence of the EC order has to be dealt with stern hand.
12. In this view of the matter, we are of the opinion that the Project Proponent (Respondent No. 5) shall be directed to deposit Rs. 1,00,00,000/- (Rupees One Crore only) with this Tribunal which may be remitted to Environment Relief Fund. The Registry shall ascertain to whom the fund may be transferred and shall do accordingly.
25 | P a g e
13. In the result, the Appeal is dismissed with direction that the Respondent No. 5 (Project Proponent) shall deposit Rs. 1,00,00,000/- (Rupees One Crore only) with the office of the NGT within four (4) weeks and the same shall be disbursed as directed above. The Gujarat State Pollution Control Board shall make six-monthly monitoring of Ground Water Level and TDS content of ground water within the premises of the project and take necessary steps to check the water level and TDS content before reaching dangerous level.
............................................., JM (V. R. Kingaonkar) ............................................, JM (U. D. Salvi) ............................................, EM (Dr. P. C. Mishra) ............................................, EM (P. S. Rao) ............................................, EM (B.S. Sajwan) 26 | P a g e


Hey, I'm Alan (Yu Kun) Xie! I'm an ambitious, motivated, and hard-working individual interested in the fields of Health Science, Health informatics, and Web Development/Programming. Ideally, I'd like to work on projects that have real-world impacts on both patients and providers in the healthcare industry.
I am currently studying in my second year at the University of Waterloo in the Health Studies Program, an interdisciplinary program with a main focus in population health and a secondary focus in human biochemistry. In my future years, I would like to pursue a minor in computing with the health informatics specialization.
This website you're viewing right now serves as a portfolio for personal projects and as a way to showcase and develop my web-design skills. This project allowed me to use many of my newly-learned skills, such as using the Bootstrap Framework and responsive web-design.
As my first programming project, I'd like for this project to serve as a stepping stone towards future projects.


UTC -6
Voltage: 110 V
Frequency: 60 Hz
Lempira of 100 centavos.
US$ must be declared on arrival.
Cash machines are available throughout the country.
Visa and MasterCard are widely accepted, but expect a significant surcharge.
International dialing code for Honduras +504.
Cellphone GSM Frequencies: 850/1900 (This means you will need a GSM cellphone that will work on 850MHz or 1900Mhz to use it in Honduras.)
Northwest Caribbean Net, 1400 UTC 6209 USB, alternates 6212 and 6516, 7 days/wk. Generally covers Providencia north to Mexico on the Carib side, including Providencia, San Andreas, Honduras, Guatemala, Belize, Mexico, Cuba, Jamaica and the Caymans. They often follow boats all the way home to Key West through Galveston on the US coast, and sometimes boats heading south will continue to check in down to Panama, but not often.
Emergency numbers
Police - Dial 199
Fire Service - Dial 198
Medical Emergency Services - Dial 195 / 37 8654
IMRAY AND ADLARD COLES PILOT BOOKS are available at a discounted price for Noonsite.com users via World Cruising Club
The Pacific Crossing Guide
By Michael Pocock, Revised by Ros Hogbin
Publisher: Adlard Coles; 2nd edition (August 2011)
ISBN-13:<PHONE_NUMBER>828
See the detailed review
Explore Central America - Part 1
Published January 2007 (13th ed. Aug. 2011, continually updated)
This is an e-book available from www.sailsarana.com/guide
The most comprehensive guides ever written about cruising the Pacific coast of
Central America from Mexico to the Panama Canal. In a two part set, these books
provide over 325 GPS waypoints, over 112 charts and city maps, detailed weather
descriptions, forecasting information and surfing locations. These books highlight dozens of anchorages not in other books and tons of local information that sailors care about. Also included are detailed procedures for clearing into and out of the Central American countries as well as Ecuador, the Galapagos and Mexico.
Honduras and Bay Islands - A Mariners Guide
By Rick Rhodes
Publisher: Heron Island Media; December 1999
ISBN-13:<PHONE_NUMBER>619
The geography, natural resources, demographics and economy of Honduras and Its Bay Islands are addressed in this book. This cruising guide contains 55 GPS waypoints for harbor entries, and five city maps.
Cruising Ports:The Central American Route
By Pat Rains
Published by Point Loma Publishing ( March 2011)
ISBN-13:<PHONE_NUMBER>027
See www.MexicoBoating.com for further details.
This book covers Pacific Central America (Guatemala, El Salvador, Nicaragua, Costa Rica, Pacific Panama) plus Mexico’s Gulf Coast to Veracruz, then NW Yucatan, NW Cuba, Yucatan Channel, Belize, Rio Dulce, Honduras and the Bay Islands, the Western Caribbean islands & banks, Panama’s Caribbean cruising grounds. This book culminates in Panama Canal Transit.
http://www.honduras.travel/
Honduras Official Travel Website
Roatan Net
Visitors Guide to Roatan & the Bay Islands


To view which line separators style is used in the current file, look at the Status Bar:
To change the current line ending style, just click the spinner.


How Can We Help You
make your building as best?
We are one of the fastest property maintenance companies in Jordan .
We have a team of expert professionals and engineer. We provide
maintenance services for office, hospital, hotel, warehouse, IT park,
residential and commercial buildings. We have worked with many reputed
clients . Our services include building maintenance, water body
maintenance, building renovation and interior work
Order Survice
Maintinace doctor is a decade-old construction company. We have done more than 250 construction projects for clients like Under construction work, we provide the following services:- Solar plant installation, building construction and swimming pool construction. We also specialize in property/building maintenance services. We have an in-house team of design engineers, structural engineer, site supervisors, building in-charge, field workers, plumber, electrician and masons. Join Our Team
Why We Choose This Website Idea?
With today’s oversaturated markets, starting a business feels like a
shot in the dark. However, you do it because you trust in your idea
and your potential. After all, it’s said that there is nothing you
can’t do if you put your mind to it. I believe that when it comes to
being truly successful you should also involve your heart. Moreover,
your business should have a heart, and that’s the story behind it.
What is this heart? It’s the big question of WHY.
About Us


HERE ARE ALL THE NOTES I TOOK
In this nanodegee we will study the following:
Procedural thinking
Abstract thinking
System thinking
Technological empathy
Debugging
The editor provided can be accessed usin the link below
scratchpad.io
In this lesson we will learn about, Web, HTML, URLs, HTTP, Web Apps.
The Web is a collection of HTML documents
HTML stands for HyperText Markup Language
HTTP is the protocol between the internet and the servers
HTML can contain
Text Content
Markup
References to other docs
Markup
(Opening Tag)contents (closing tag)
The entire thing is called an element
Some examples are:
Markup Names
b – Bold
em – Italics
HTML attributes
a – anchor attr. Used for links
link to reddit
Img – used to add image
Note img has no closing tag. This is called a void tag.
Whitespace – There is no page breaks, lines breaks or formatting
br - Allows you to have a page break
p - Allows you to have a paragraph break
If no closing tag is required then it is called a void tag. br is a Void Tag
br is an inline tag
p is a block tag
There are 3 kinds of elements
Inline elements
Block elements
Container elements


{{product.price}}$
Children are natural mimics who act like their parents despite every effort to teach them good manners.
${{product.price}}.00
Add to cart


Extremely simple replacement for a select field. Style as necessary to achieve desired effect.
Select_it simply does that: Selects a specified select field, hides it, and builds customizable HTML that you can style any way you wish. It's that simple. Works with forms as it changes the value of the hidden select field as well so there aren't any issues.
Select_it simply does that: Selects a specified select field, hides it, and builds customizable HTML that you can style any way you wish. It's that simple. Works with forms as it changes the value of the hidden select field as well so there aren't any issues.


Born in 1978 in Philadelphia, Pennsylvania, Kobe Bryant spent his early years in Italy and joined the NBA straight out of high school. A dominant scorer, Bryant won five NBA championships and the 2008 MVP Award with the Los Angeles Lakers. Although later seasons were marred by injuries, he surpassed Michael Jordan for third place on the NBA all-time scoring list in December 2014. The following year, he announced his plan to retire after the 2015-16 NBA season.
Early Life
Kobe Bean Bryant was born on August 23, 1978, in Philadelphia, Pennsylvania. Named after a Japanese steakhouse, Kobe Bryant is the son of former NBA player Joe "Jellybean" Bryant.
In 1984, after ending his NBA career, the elder Bryant took the family to Italy, where he played in the Italian League. Growing up in Italy alongside two athletic older sisters, Shaya and Sharia, Kobe was an avid player of both basketball and soccer. When the family returned to Philadelphia in 1991, Bryant joined the Lower Merion High School basketball team, leading it to the state championships four years in a row. With an eye on the NBA, he also started working out with the 76ers.
"I, Kobe Bryant...have decided to skip college and take my talents to the NBA."
Though he boasted good grades and high SAT scores, Bryant decided to go straight to the NBA from high school. He was selected by the Charlotte Hornets with the 13th overall pick of the 1996 NBA draft, and was subsequently traded to the Los Angeles Lakers.
NBA Career
In his second season as guard, with the Lakers, Bryant was voted a starter for the 1998 All-Star Game, becoming at 19 the youngest All-Star in NBA history. He then teamed up with superstar center Shaquille O'Neal to win three consecutive NBA championships, and was voted first-team all-NBA from 2002-04. He also inked multi-year endorsement deals with Adidas, Sprite and other top sponsors.
Although the Lakers struggled after O'Neal left in 2004, Bryant performed brilliantly. He scored 81 points against the Toronto Raptors in January 2006, the second-highest single-game mark in NBA history, and led the league in scoring that year and the next.
In 2008, Bryant was named Most Valuable Player and carried his team to the NBA Finals, where they lost to the Boston Celtics. In the 2009 NBA Finals, the Lakers beat the Orlando Magic to win the championship. Shortly afterward, Bryant was part of the memorial service to honor friend and music superstar Michael Jackson. The following year, the Lakers won their second straight title by defeating the Celtics.
Bryant played on both the 2008 and 2012 U.S. Olympic teams, winning consecutive gold medals with teammates Kevin Durant, LeBron James and Carmelo Anthony, among several other top players.
After suffering a torn Achilles tendon in April 2013, Bryant worked hard to return to the court before fracturing his knee just six games into the 2013-14 season. The veteran All-Star surpassed Michael Jordan for third all-time on the NBA scoring list in December 2014, but his season ended due to injury for the third straight year when he sustained a torn rotator cuff in January 2015.
Although Bryant returned in time for the start of the 2015-16 NBA season, he personally struggled alongside his young Lakers teammates. In November 2015, he announced that he would retire at the end of the season. "This season is all I have left to give," he wrote on The Players' Tribune website. "My heart can take the pounding. My mind can handle the grind but my body knows it's time to say goodbye."
The announcement drew a strong reaction, particularly from NBA Commissioner Adam Silver. "With 17 NBA All-Star selections, an NBA MVP, five NBA championships with the Lakers, two Olympic gold medals and a relentless work ethic, Kobe Bryant is one of the greatest players in the history of our game," Silver said in a statement. "Whether competing in the finals or hoisting jump shots after midnight in an empty gym, Kobe has an unconditional love for the game."
On April 13, 2016, Bryant dazzled a sold-out crowd at the Staples Center and fans everywhere in the last game of his career, scoring 60 points and leading the Lakers to a win against the Utah Jazz. It was Bryant’s sixth 60-point game of his career.
After the game, Bryant spoke to the crowd. "I can't believe how fast 20 years went by . . .,” he said.  I think the most important part is we all stayed together throughout."
An all-star lineup of Laker icons also payed tribute to Bryant including Shaquille O’Neal, Phil Jackson, Pau Gasol, Derek Fisher, Lamar Odom and Magic Johnson.
“We are here to celebrate greatness for 20 years,” Johnson said. “Excellence for 20 years. Kobe Bryant has never cheated the game, never cheated us as the fans. He has played through injury, he has played hurt. And we have five championship banners to show for it.
Personal Life
Bryant married 19-year-old Vanessa Laine in April 2001. In July 2003, he was charged with one count of sexual assault on a 19-year-old female hotel worker in Colorado. Bryant said he was guilty of adultery, but innocent of the rape charge. The case against Bryant was dismissed in 2004, and he settled the civil lawsuit filed by the hotel worker against him out of court.
Among his philanthropic endeavors, the basketball great has partnered with the non-profit After-School All-Stars as part of the Kobe & Vanessa Bryant Family Foundation. He also runs an annual summer camp called the Kobe Basketball Academy.
To show some photographs of: Kobe Bryant


Annotater annotater is the solution to all your annotation problems and doesn't need any fussing with HTML. View source if you doubt it! it has no dependencies, and styles well without any css includes. tooltips models generally being verbose


--- title: "Construction of a public dataset of Blood Bowl matches played on FUMBBL.com" author: "Gertjan Verhoeven" date: '2021-12-30' summary: This blogpost is about **Blood Bowl**, a boardgame I started playing last year. The goal of this blog post is to use Python API and HTML scraping to fetch Blood Bowl match outcome data from FUMBBL.com, and to create a structured dataset ready for analysis and visualization. slug: blood-bowl-fumbbl-dataset draft: no categories: - Data paper - Blood Bowl tags: - Python - Pandas - Beautiful Soup baseurl: https://gsverhoeven.github.io header: image: headers/bloodbowl_dataset.png preview: no ---
This blogpost is about Blood Bowl, a boardgame of fantasy football that can also be played online at FUMBBL.com. The goal of this blog post is to use Python API and HTML scraping to fetch online Blood Bowl match outcome data, and to create a publicly available dataset ready for analysis and visualization. In a separate blog post I’ll showcase some analyses on this dataset (also known as Nufflytics in reference to Nuffle, the god of Blood Bowl). The dataset is primarily constructed to analyze rule changes that were introduced on FUMBBL.com last year, and how these affected the relative strengths of the different teams coaches can pick to field against each other.
N.b. an updated version of this post is available as a Jupyter Notebook in a separate Github Repository fumbbl_datasets.
In writing this blog post, I took inspiration from a relatively new development in Open Science, that of the Data paper (Chavan & Penev, 2011). A data paper is a (ideally peer reviewed) publication of a dataset as a stand alone research output. A Data paper can be thought of similar to the “Methods” section of a traditional research article, though with greater detail. A data paper describes the contents of the dataset, the data acquisition process, and includes a discussion of the motivation and considerations regarding experimental design (if applicable). Data papers do not provide any analysis nor results / conclusions. The dataset itself should be online available at a data repository such as Zenodo, Figshare or Dryad.
To give an impression of how this works out in practice, here are two examples: The first data paper, A public data set of spatio-temporal match events in soccer competitions, was published in “Scientific data” with the dataset hosted at Figshare. The second is collected from Twitter: A large-scale COVID-19 Twitter chatter dataset for open scientific research – an international collaboration, with the open dataset published on Zenodo.
*Chavan, V., and Penev, L. (2011). The data paper: a mechanism to incentivize data publishing in biodiversity science. BMC Bioinformatics 12(Suppl. 15):S2. doi:10.1186/1471-2105-12-S15-S2
This blogpost is written as a Jupyter notebook containing Python code, and is fully reproducible. The idea is to make Blood Bowl data analysis accessible to others. Using open source tooling reduces the barriers for others to build on other people’s work.
import random
import time
import requests # API library
import numpy as np
import pandas as pd
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
The FUMBBL website (https://fumbbl.com) contains a large amount of data. From coach pages, with their teams, to team rosters, with players, and match histories. It’s all there.
To obtain FUMBBL data, we need to fetch it match by match, team by team. To do so, the site creator Christer Kaivo-oja, from Sweden, has made an API that allows us to easily fetch data. What follows is a short demonstration how the API works, before we fetch the FUMBBL match and team data of the last 12 months.
I use the Python Requests library to make the API call over HTTPS and obtain the response from the FUMBLL server. The response is in the JSON format, a light-weight data-interchange format which is both easy to read and write for humans, and easy to parse and generate by computers. So this makes it a natural choice for an API.
Here is an example of what is available at the coach level.
We have a list of key-value pairs.
Using brackets []
we can choose keys and retrieve their values.
Some keys contain simple values, such as name
,
response.json()['name']
'gsverhoeven'
but some return as value a new list of key-value pairs, such as teams
.
Actually this is a “list of”lists of key-value pairs”, since we have a separate list for each team.
Even the list of a single team contains new structure, for example under the key raceLogos
.
response.json()['teams'][2]['raceLogos']
[{'size': 32, 'logo': 486290},
{'size': 48, 'logo': 486291},
{'size': 64, 'logo': 486292},
{'size': 96, 'logo': 486293},
{'size': 128, 'logo': 486294},
{'size': 192, 'logo': 486295}]
response.json()['teams'][2]['name']
'Blackbox Bastards'
Now we know how the data comes in, we need to think about which variables we want, and how to structure them. The most straightforward level to analyze race strength is to look at match outcomes. At its core, the data consists of matches played by teams, commanded by coaches. Furthermore, we expect race strength to change over time, as new strategies are discovered by the players, or new rules get introduced. So the time dimension is important as well.
So, let’s go with a flat data frame with rows for each match, and columns for the various variables associated with each match. These would include:
With this basic structure, we can add as many match related variables in the future, keeping the basic structure (each row is a match) unchanged.
So lets get the match data!
So we are mostly interested in the current ruleset, this is BB2020
. This ruleset became available for play on FUMBBL at september 1st 2021, and two months later, already some 5000 games have been played. We also want to compare with the previous ruleset, where we have much more data available. How far do we go back?
Let’s go for roughly 12 months of BB2016
ruleset matches, and a few months of BB2020
matches.
The easiest way to collect match data over a particular period of time is to just loop over match_id
. The most recent match at the time of writing was 4.347.800, and since roughly 100.000 matches are played each year, we can fiddle about and we find match 4.216.258 played on august 1st, 2020. So that means we need to collect some 130K matches.
VERY IMPORTANT: We do not want to overload the FUMBBL server, so we make only three API requests per second. In this way, the server load is hardly affected and it can continue functioning properly for all the Blood Bowl coaches playing their daily games!
To collect 130K matches, we will need 130000*0.333/3600 = 12 hours.
# estimated hours fetching data
(4347800-4216257)*0.333/3600
12.16773
df_matches = pd.DataFrame(columns=['match_id', 'match_date', 'match_time',
'team1_id', 'team1_coach_id', 'team1_roster_id', 'team1_race_name', 'team1_value',
'team2_id', 'team2_coach_id', 'team2_roster_id', 'team2_race_name', 'team2_value',
'team1_score', 'team2_score'])
target = 'data/df_matches_' + time.strftime("%Y%m%d_%H%M%S") + '.h5'
print(target)
end_match = 4347800
begin_match = 4216258
n_matches = end_match - begin_match
full_run = 0
print(n_matches)
if(full_run):
for i in range(n_matches):
api_string = "https://fumbbl.com/api/match/get/" + str(end_match - i)
# wait 0.33 s on average between each API call
wait_time = (random.uniform(0.5, 1) + 0.25)/3
time.sleep(wait_time)
match = requests.get(api_string)
match = match.json()
if match: # fix for matches that do not exist
match_id = match['id']
match_date = match['date']
match_time = match['time']
team1_id = match['team1']['id']
team2_id = match['team2']['id']
team1_score = match['team1']['score']
team2_score = match['team2']['score']
team1_roster_id = match['team1']['roster']['id']
team2_roster_id = match['team2']['roster']['id']
team1_coach_id = match['team1']['coach']['id']
team2_coach_id = match['team2']['coach']['id']
team1_race_name = match['team1']['roster']['name']
team2_race_name = match['team2']['roster']['name']
team1_value = match['team1']['teamValue']
team2_value = match['team2']['teamValue']
#print(match_id)
df_matches.loc[i] = [match_id, match_date, match_time,
team1_id, team1_coach_id, team1_roster_id, team1_race_name, team1_value,
team2_id, team2_coach_id, team2_roster_id, team2_race_name, team2_value,
team1_score, team2_score]
else:
# empty data for this match, create empty row
match_id = int(end_match - i)
df_matches.loc[i] = [np.NaN, np.NaN, np.NaN,
np.NaN,np.NaN,np.NaN,np.NaN,
np.NaN,np.NaN,np.NaN,np.NaN,
np.NaN,np.NaN, np.NaN, np.NaN] # try np.repeat([np.NaN], 13, axis=0) next time
df_matches.loc[i]['match_id'] = int(match_id)
if i % 100 == 0:
# write tmp data as hdf5 file
print(i, end='')
print(".", end='')
df_matches.to_hdf(target, key='df_matches', mode='w')
# write data as hdf5 file
df_matches.to_hdf(target, key='df_matches', mode='w')
else:
# read from hdf5 file
df_matches = pd.read_hdf('data/df_matches_20211215_212935.h5')
df_matches.shape
data/df_matches_20211230_192705.h5
131542
(131542, 15)
Since we manually filled the pandas
DataFrame, most of the columns are now of object
datatype.
We need to change this to be able to work properly with the data, as well as store it properly.
Here I convert each column manually, however I later found out about DataFrame.infer_objects()
, that can detect the proper dtype automatically.
This I will try next time.
# convert object dtype columns to proper pandas dtypes datetime and numeric
df_matches['match_date'] = pd.to_datetime(df_matches.match_date) # Datetime object
df_matches['match_id'] = pd.to_numeric(df_matches.match_id)
df_matches['team1_id'] = pd.to_numeric(df_matches.team1_id)
df_matches['team1_coach_id'] = pd.to_numeric(df_matches.team1_coach_id)
df_matches['team1_roster_id'] = pd.to_numeric(df_matches.team1_roster_id)
df_matches['team2_id'] = pd.to_numeric(df_matches.team2_id)
df_matches['team2_coach_id'] = pd.to_numeric(df_matches.team2_coach_id)
df_matches['team2_roster_id'] = pd.to_numeric(df_matches.team2_roster_id)
df_matches['team1_score'] = pd.to_numeric(df_matches.team1_score)
df_matches['team2_score'] = pd.to_numeric(df_matches.team2_score)
# calculate match score difference
df_matches['team1_win'] = np.sign(df_matches['team1_score'] - df_matches['team2_score'])
df_matches['team2_win'] = np.sign(df_matches['team2_score'] - df_matches['team1_score'])
# mirror match
df_matches['mirror_match'] = 0
df_matches.loc[df_matches['team1_race_name'] == df_matches['team2_race_name'], 'mirror_match'] = 1
# 5K mirror matches
df_matches.query('mirror_match == 1').shape
(5081, 18)
# Make BB2020 Khorne team name equal to BB2016 to compare them more easily
df_matches.loc[df_matches['team1_race_name'] == "Khorne", 'team1_race_name'] = 'Daemons of Khorne'
df_matches.loc[df_matches['team2_race_name'] == "Khorne", 'team2_race_name'] = 'Daemons of Khorne'
In Blood Bowl, teams can develop themselves over the course of multiple matches. The winnings of each match can be spend on buying new, stronger players, or replace the players that ended up getting injured or even killed. In addition, players receive so-called star player points (SPP) for important events, such as scoring, or inflicting a casualty on the opponent. Therefore, a balancing mechanism is needed when a newly created “rookie” team is facing a highly developed opposing team with lots of extra skills and strong players.
Blood Bowl solves this by calculating for both teams their Current team value. The Team value difference for a match determines the amount of gold that the weaker team can use to buy so-called inducements. These inducements are temporary, and can consists of a famous “star player” who joins the team just for this match. Another popular option is to hire a wizard that can be used to turn one of the opposing players into a frog.
It is well known that the win rates of the teams depend on how developed a team is. For example, Amazons are thought to be strongest at low team value, as they already start out with lots of block and dodge skills, whereas a Chaos team start out with almost no skills. So if we compare win rates, we would like take into account the current team value. Now as this can differ between the two teams in a match up, I reasoned that the highest team value is most informative about the average strength level of both teams, because of the inducement mechanism described above.
In the dataset, we have for each match the current team values of both teams as a text string.
We transform the text string 1100k
into an integer number 1100
, so that we can calculated the difference as tv_diff
, and pick for each match the maximum team value and store it as tv_match
. Finally, we create a team value bin tv_bin
to be able to compare win rates for binned groups of matches where races have comparable team strength / team development.
# convert team value 1100k to 1100 integer and and above / below median (= low / high TV)
df_matches['team1_value'] = df_matches['team1_value'].str.replace('k$', '')
df_matches['team1_value'] = df_matches['team1_value'].fillna(0).astype(np.int64)
df_matches['team2_value'] = df_matches['team2_value'].str.replace('k$', '')
df_matches['team2_value'] = df_matches['team2_value'].fillna(0).astype(np.int64)
df_matches['tv_diff'] = np.abs(df_matches['team2_value'] - df_matches['team1_value'])
df_matches['tv_match'] = df_matches[["team1_value", "team2_value"]].max(axis=1)
df_matches['tv_bin'] = pd.cut(df_matches['tv_match'],
bins = [0, 950, 1250,1550, 1850, float("inf")],
labels=['< 950', '1.1K', '1.4K', '1.7K', '> 1850']
)
Some match_id’s do not have match information attached to them, presumably these matches were not played or some real life event interfered. These match_ids are dropped from the dataset to get rid of the NAs in all the columns.
df_matches = df_matches.dropna(subset=['match_date'])
# 131K matches
len(df_matches)
131509
To see time trends, its useful to aggregate the data by week. For this we add week_number
for each date, and from this week number, we convert back to a date to get a week_date
. This last part is useful for plotting with plotnine
, as this treats dates in a special way. We use the ISO definition of week, this has some unexpected behavior near the beginning / end of each year, that we fix manually.
The data starts in week 36 (september) of 2020, and stops halfway week 44 in 2021.
df_matches['week_number'] = df_matches['match_date'].dt.isocalendar().week
# cannot serialize numpy int OR Int64 when writing HDF5 file, so we go for plain int as all NAs are gone now
df_matches['week_number'] = df_matches['week_number'].fillna(0).astype(int)
# add year based on match date (but want it based on match ISO week)
df_matches['year'] = pd.DatetimeIndex(df_matches['match_date']).year
# manual fix year for ISO week 2020-53 (2020 has 53 ISO weeks, including a few days in jan 2021)
df_matches.loc[(df_matches['year'] == 2021) & (df_matches['week_number'] == 53), 'year'] = 2020
df_matches['week_year'] = df_matches['year'].astype(str) + '-' + df_matches['week_number'].astype(str)
df_matches['week_date'] = pd.to_datetime(df_matches['week_year'].astype("string") + '-1', format = "%Y-%U-%w")
# manual fix of week date (grrrr)
df_matches.loc[(df_matches['week_date'] == '2021-01-04') & (df_matches['week_number'] == 53), 'week_date'] = pd.to_datetime('2020-12-31')
Next, we collect for all the matches in df_matches
the inducements and coach rankings.
This information is not available through the API, but is presented on a HTML page at https://fumbbl.com/FUMBBL.php?page=match&id=4350014 summarizing information for in this case match 4350014.
I highly recommend this tutorial for a great introduction to BeautifulSoup
.
In addition, to clean up the scraped text, I used the re
Python module (Regular expressions), part of the Python standard library to extract the actual inducements from the text string that contains them.
from bs4 import BeautifulSoup
import re
df_inducements = pd.DataFrame(columns=['match_id', 'team1_inducements', 'team2_inducements', 'coach1_ranking', 'coach2_ranking'])
target = 'data/df_inducements_' + time.strftime("%Y%m%d_%H%M%S") + '.h5'
print(target)
end_match = 4347800
begin_match = 4216257
n_matches = end_match - begin_match
full_run = 0
print(n_matches)
if(full_run):
for i in range(n_matches):
match_id = end_match - i
api_string = "https://fumbbl.com/FUMBBL.php?page=match&id=" + str(match_id)
# wait 0.33 s on average between each GET call
wait_time = (random.uniform(0.5, 1) + 0.25)/3
time.sleep(wait_time)
response = requests.get(api_string)
soup = BeautifulSoup(response.content, 'html.parser')
if soup.find("div", {"class": "matchrecord"}) is not None:
# match record is available
inducements = soup.find_all("div", class_="inducements")
pattern = re.compile(r'\s+Inducements: (.*)\n')
match = re.match(pattern, inducements[0].get_text())
if match:
team1_inducements = match.group(1)
else:
team1_inducements = ''
match = re.match(pattern, inducements[1].get_text())
if match:
team2_inducements = match.group(1)
else:
team2_inducements = ''
coach_rankings = soup.find_all("div", class_="coach")
coach1_ranking = coach_rankings[0].get_text()
coach2_ranking = coach_rankings[1].get_text()
df_inducements.loc[i] = [match_id, team1_inducements, team2_inducements, coach1_ranking, coach2_ranking]
if i % 100 == 0:
# write tmp data as hdf5 file
print(i, end='')
print(".", end='')
df_inducements.to_hdf(target, key='df_inducements', mode='w')
# write data as hdf5 file
df_inducements.to_hdf(target, key='df_inducements', mode='w')
else:
# read from hdf5 file
df_inducements = pd.read_hdf('data/df_inducements_20211215_112148.h5')
df_inducements.info()
data/df_inducements_20211230_192709.h5
131543
<class 'pandas.core.frame.DataFrame'>
Int64Index: 131509 entries, 0 to 131508
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 match_id 131509 non-null object
1 team1_inducements 131509 non-null object
2 team2_inducements 131509 non-null object
3 coach1_ranking 131509 non-null object
4 coach2_ranking 131509 non-null object
dtypes: object(5)
memory usage: 6.0+ MB
df_inducements.query("match_id == 4347799")
| match_id | team1_inducements | team2_inducements | coach1_ranking | coach2_ranking | |
|---|---|---|---|---|---|
| 1 | 4347799 | 1 bloodweiser babe, Mercenary Merc Thrall Line… | CR 154.6 (+0.97) Emerging Star Vini | motay666 Emerging Star CR 151.12 (-0.97) |
We want to extract the part CR 152.53
from the scraped coach information field. Just as we matched on Inducements:
, we can match on CR
and grab the contents directly after that, stopping when we encounter a whitespace.
We first play around a bit and test until we discover the proper Regular Expression to use :-)
#pattern = re.compile(r'\s+Inducements: (.*)\n')
pattern = re.compile(r'.*CR (.*)\s\(.*')
match = re.match(pattern, df_inducements.loc[0, 'coach2_ranking'])
if match is not None:
print(match.group(1)) # group(0) is the whole string
else:
print("match is none")
df_inducements.loc[0, 'coach2_ranking']
144.51
'LoxodonP Veteran CR 144.51 (-0.76)'
Got ’m! Now that we have figured it out, we can write the code that extracts the coach rankings:
# Dataprep fix match_id
df_inducements['match_id'] = pd.to_numeric(df_inducements.match_id)
# Dataprep: add the coach rankings as separate cols
df_inducements['coach1_CR'] = df_inducements['coach1_ranking'].str.extract(r'.*CR (.*)\s\(.*')
df_inducements['coach2_CR'] = df_inducements['coach2_ranking'].str.extract(r'.*CR (.*)\s\(.*')
df_inducements['coach1_CR'] = pd.to_numeric(df_inducements['coach1_CR'])
df_inducements['coach2_CR'] = pd.to_numeric(df_inducements['coach2_CR'])
df_inducements['CR_diff'] = np.abs(df_inducements['coach1_CR'] - df_inducements['coach2_CR'])
df_inducements['CR_diff'] = df_inducements['CR_diff'].astype(float)
df_inducements['cr_diff2'] = df_inducements['coach1_CR'] - df_inducements['coach2_CR']
df_inducements['cr_bin'] = pd.cut(df_inducements['cr_diff2'], bins = [-1*float("inf"), -30, -20, -10, -5, 5, 10, 20, 30, float("inf")],
labels=['{-Inf,-30]', '[-30,-20]', '[-20,-10]', '[-10,-5]', '[-5,5]', '[5,10]', '[10,20]', '[20,30]', '[30,Inf]'])
df_inducements.dtypes
match_id int64
team1_inducements object
team2_inducements object
coach1_ranking object
coach2_ranking object
coach1_CR float64
coach2_CR float64
CR_diff float64
cr_diff2 float64
cr_bin category
dtype: object
The next trick is to use pandas
explode()
method (similar to separate_rows()
in tidyverse
R) to give each inducement its own row in the dataset.
This creates a dataframe (inducements
) similar to df_mbt
with each match generating at least two rows.
team1_inducements = df_inducements[['match_id', 'team1_inducements']]
team2_inducements = df_inducements[['match_id', 'team2_inducements']]
# make column names equal
team1_inducements.columns = team2_inducements.columns = ['match_id', 'inducements']
# row bind the two dataframes
inducements = pd.concat([team1_inducements, team2_inducements], ignore_index = True)
# convert comma separated string to list
inducements['inducements'] = inducements['inducements'].str.split(',')
# make each element of the list a separate row
inducements = inducements.explode('inducements')
# strip leading and trailing whitespaces
inducements['inducements'] = inducements['inducements'].str.strip()
# create "star player" label
inducements['star_player'] = 0
inducements.loc[inducements['inducements'].str.contains("Star player"), 'star_player'] = 1
# create "card" label
inducements['special_card'] = 0
inducements.loc[inducements['inducements'].str.contains("Card"), 'special_card'] = 1
Here we add df_inducements
to df_matches
. This contains each players inducements as a single string, not convenient for analysis.
The inducements
dataframe cannot easily be added to df_matches
. We can however, extract information from inducements
at the match level and add this to df_matches
. Here, I show how to add a 1/0 flag has_sp
that codes for if a match included any star player.
df_matches = pd.merge(df_matches, df_inducements, on='match_id', how='left')
df_sp = (inducements
.groupby("match_id")
.agg(has_sp = ("star_player", "max"))
.reset_index()
)
df_matches = pd.merge(df_matches, df_sp, on = "match_id", how = "left")
df_matches['match_id'] = pd.to_numeric(df_matches.match_id)
When analyzing the data, we also like to have a dataframe df_mbt (df_matches_by_team)
that contains, for each match, a separate row for each team participating in that match.
This structure is nicely visualized at the Nufflytics blog.
Such a dataset is suitable for analysis by team, e.g. win rates. We can extend this further by adding, at the match level, data that is specific for each team - coach pair, such as team value, coach rating etc.
For example, we can imagine adding more team level data, such as casualties caused during the match, or team composition at the start of the match etc.
# make two copies, one for each team in the match
team1_data = df_matches[['match_id', 'match_date', 'week_number', 'year', 'week_year', 'week_date', 'team1_id',
'team1_coach_id', 'team1_race_name', 'team1_value', 'team1_win', 'tv_diff', 'tv_match',
'tv_bin', 'mirror_match', 'coach1_CR', 'CR_diff', 'has_sp']].copy()
team2_data = df_matches[['match_id', 'match_date', 'week_number', 'year', 'week_year', 'week_date', 'team2_id',
'team2_coach_id', 'team2_race_name', 'team2_value', 'team2_win', 'tv_diff', 'tv_match',
'tv_bin','mirror_match', 'coach2_CR', 'CR_diff', 'has_sp']].copy()
team1_data.columns = team2_data.columns = ['match_id', 'match_date', 'week_number', 'year', 'week_year', 'week_date', 'team_id',
'coach_id', 'race_name', 'team_value', 'wins', 'tv_diff', 'tv_match',
'tv_bin', 'mirror_match', 'coach_CR', 'CR_diff', 'has_sp']
# combine both dataframes
df_mbt = pd.concat([team1_data, team2_data])
One way to measure team strength is to calculate a win rate. If we want to calculate win rates, we need to decide how to weigh a draw. In Blood Bowl data analysis, it seems that a 2:1:0 (W / D / L) weighting scheme is most commonly used. So if we want to compare with others, it makes sense to adapt this scheme as well. If we divide these weights by two we get something that, if we average it, we can interpret as a win rate.
This scheme has the advantage that the weighted average win percentage over all matches is always 50%, creating a nice reference point allowing conclusions such as “this and that team has an x percent above average win percentage”.
df_mbt.loc[df_mbt['wins'] == 0, 'wins'] = 0.5
df_mbt.loc[df_mbt['wins'] == -1, 'wins'] = 0
# convert to float
df_mbt['wins'] = df_mbt['wins'].astype(float)
At this point, Lets have a look at our dataset again:
df_mbt.query("coach_id == 255851").sort_values('match_date')
| match_id | match_date | week_number | year | week_year | week_date | team_id | coach_id | race_name | team_value | wins | tv_diff | tv_match | tv_bin | mirror_match | coach_CR | CR_diff | has_sp | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 99692 | 4248074 | 2020-11-13 | 46 | 2020 | 2020-46 | 2020-11-16 | 1003452.0 | 255851.0 | Human | 1000 | 0.0 | 0 | 1000 | 1.1K | 0 | 150.00 | 0.80 | 0.0 |
| 77673 | 4270093 | 2021-01-17 | 2 | 2021 | 2021-2 | 2021-01-11 | 1003452.0 | 255851.0 | Human | 1000 | 0.0 | 40 | 1000 | 1.1K | 1 | 149.22 | 3.63 | 0.0 |
| 32991 | 4314794 | 2021-07-01 | 26 | 2021 | 2021-26 | 2021-06-28 | 1003452.0 | 255851.0 | Human | 980 | 0.0 | 10 | 990 | 1.1K | 0 | 147.60 | 1.37 | 0.0 |
| 31599 | 4316193 | 2021-07-10 | 27 | 2021 | 2021-27 | 2021-07-05 | 1035835.0 | 255851.0 | Human | 980 | 0.0 | 20 | 1000 | 1.1K | 0 | 146.62 | 9.49 | 0.0 |
| 25968 | 4321824 | 2021-08-16 | 33 | 2021 | 2021-33 | 2021-08-16 | 1038960.0 | 255851.0 | Human | 970 | 0.5 | 30 | 1000 | 1.1K | 1 | 145.93 | 9.30 | 0.0 |
| 23609 | 4324190 | 2021-09-01 | 35 | 2021 | 2021-35 | 2021-08-30 | 1038960.0 | 255851.0 | Human | 1000 | 0.0 | 10 | 1000 | 1.1K | 0 | 145.90 | 10.19 | 0.0 |
| 21018 | 4326781 | 2021-09-13 | 37 | 2021 | 2021-37 | 2021-09-13 | 1038960.0 | 255851.0 | Human | 1010 | 1.0 | 80 | 1010 | 1.1K | 0 | 144.24 | 6.02 | 0.0 |
| 12941 | 4334858 | 2021-10-11 | 41 | 2021 | 2021-41 | 2021-10-11 | 1038960.0 | 255851.0 | Human | 1110 | 0.0 | 150 | 1260 | 1.4K | 0 | 145.22 | 16.80 | 0.0 |
| 10050 | 4337749 | 2021-10-22 | 42 | 2021 | 2021-42 | 2021-10-18 | 1050267.0 | 255851.0 | Orc | 1080 | 0.0 | 10 | 1090 | 1.1K | 0 | NaN | NaN | 0.0 |
| 9027 | 4338772 | 2021-10-26 | 43 | 2021 | 2021-43 | 2021-10-25 | 1050267.0 | 255851.0 | Orc | 1040 | 1.0 | 50 | 1040 | 1.1K | 0 | NaN | NaN | 0.0 |
| 3783 | 4344017 | 2021-11-15 | 46 | 2021 | 2021-46 | 2021-11-15 | 1050267.0 | 255851.0 | Orc | 1150 | 0.0 | 170 | 1150 | 1.1K | 0 | NaN | NaN | 0.0 |
| 1186 | 4346614 | 2021-11-25 | 47 | 2021 | 2021-47 | 2021-11-22 | 1050267.0 | 255851.0 | Orc | 1020 | 0.5 | 150 | 1170 | 1.1K | 0 | NaN | NaN | 0.0 |
Great! Almost there. There is still something missing though, we need to know, for all the teams in our matches dataset, in what division or league they are playing, and what version of the rules they use. For these we turn to the API again, to fetch more data, now on the team level.
Let grab for all teams in df_mbt
the team division and ruleset.
A limitation of the FUMBBL API is that it shows only the latest version of the teams and leagues data. This hides the fact that leagues have changed their rules since they were first created. For example, the NAF used BB2016 rules up until summer of 2021, and thereafter switched to the new BB2020 ruleset for their latest online tournament. So we have to use our “domain knowledge” here to interpret the data properly.
# make list of all teams that need to be fetched
team_ids = list(df_mbt['team_id'].dropna())
# get unique values by converting to a Python set and back to list
team_ids = list(set(team_ids))
len(team_ids)
46831
So we have to fetch data for 47K different teams.
We use the same approach as above, looping over all team_id
’s and making a separate API call for each team.
IMPORTANT: here too, we limit ourselves to a maximum of 3 API calls per second to avoid overloading the FUMBBL server
df_teams = pd.DataFrame(columns=['team_id', 'division_id', 'division_name', 'league' ,
'ruleset', 'roster_id', 'race_name', 'games_played'])
target = 'data/df_teams_' + time.strftime("%Y%m%d_%H%M%S") + '.h5'
print(target)
fullrun = 0
if fullrun:
print('fetching team data for ', len(team_ids), ' teams')
for t in range(len(team_ids)):
api_string = "https://fumbbl.com/api/team/get/" + str(int(team_ids[t]))
wait_time = (random.uniform(0.5, 1) + 0.25)/3
time.sleep(wait_time)
team = requests.get(api_string)
team = team.json()
# grab fields
team_id = team['id']
division_id = team['divisionId']
division_name = team['division']
ruleset = team['ruleset']
league = team['league']
roster_id = team['roster']['id']
race_name = team['roster']['name']
games_played = team['record']['games']
# add to dataframe
df_teams.loc[t] = [team_id, division_id, division_name, league, ruleset, roster_id, race_name, games_played]
if t % 100 == 0:
# write tmp data as hdf5 file
print(t, end='')
print(".", end='')
df_teams.to_hdf(target, key='df_teams', mode='w')
df_teams.to_hdf(target, key='df_teams', mode='w')
else:
# read from hdf5 file
df_teams = pd.read_hdf('data/df_teams_20211215_211746.h5')
df_teams['roster_name'] = df_teams['roster_id'].astype(str) + '_' + df_teams['race_name']
df_teams.shape
data/df_teams_20211230_192715.h5
(46831, 9)
FUMBBL allows coaches to create their own rulesets to play their own leagues and tournaments with. For example, there is a so-called “Secret League” where coaches can play with “Ninja halflings”, “Ethereal” spirits etc. Instead of plain normal regular “Halflings” and “Shambling Undead” :-)
Since we want the team strength for the official rulesets BB2016 and BB2020, we need to distinguish those matches from the matches that are played under different rules.
Lets have look at the various divisions and leagues, which rulesets are used, and which races are played how often. There are a lot of small leagues being played on FUMBBL. We only look at divisions and leagues with a sufficient volume of matches, or otherwise we do not have sufficient statistics for each race.
So I aggregated the data by division, league and ruleset, and filtered on at least 150 different teams that have played at least once last year.
Apart from the main “Divisions” that are part of FUMBBL, there were a few user-run leagues present in this table, so I looked up their names on FUMBBL and what ruleset is used (BB2016, BB2020 or some other variant). This information (contained in an xlsx) is added to the dataset below.
# add ruleset_version and division_name from xlsx
ruleset_division_names = pd.read_excel('data/ruleset_division_names.xlsx', engine='openpyxl')
df_teams = pd.merge(df_teams, ruleset_division_names, on= ['league', 'ruleset', 'division_id'], how='left')
df_teams['division_name'] = df_teams['new_division_name']
df_teams = df_teams.drop('new_division_name', 1)
df_teams['division_id'] = pd.to_numeric(df_teams.division_id)
df_teams['roster_id'] = pd.to_numeric(df_teams.roster_id)
df_teams['team_id'] = pd.to_numeric(df_teams.team_id)
df_teams['games_played'] = pd.to_numeric(df_teams.games_played)
df_teams['league'] = pd.to_numeric(df_teams.league)
df_teams['ruleset'] = pd.to_numeric(df_teams.ruleset)
(df_teams
.groupby(['ruleset', 'league', 'division_id', 'division_name', 'ruleset_version'], dropna=False)
.agg( n_teams = ('ruleset', 'count')
)
.sort_values('n_teams', ascending = False)
.query('n_teams > 150')['n_teams']
.reset_index()
)
| ruleset | league | division_id | division_name | ruleset_version | n_teams | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 10 | Blackbox | bb2016 | 10439 |
| 1 | 1 | 0 | 1 | Ranked | bb2016 | 7944 |
| 2 | 4 | 0 | 2 | Competitive | bb2020 | 6532 |
| 3 | 6 | 0 | 5 | Regular_league | bb2016 | 5942 |
| 4 | 303 | 10263 | 5 | Secret League | bb2016 | 2554 |
| 5 | 2228 | 9298 | 5 | NAF | mixed | 1466 |
| 6 | 2 | 0 | 3 | Stunty Leeg | bb2016 | 607 |
| 7 | 2198 | 14708 | 5 | SL BB2020 | bb2020 | 452 |
| 8 | 888 | 11676 | 5 | LegaGladio | mixed | 345 |
| 9 | 4 | 14713 | 5 | Test Open League BB2020 | bb2020 | 296 |
| 10 | 1049 | 12026 | 5 | NAF 7s | bb2016 | 196 |
| 11 | 432 | 10455 | 5 | CIBBL | bb2016 | 189 |
For each match in the df_mbt
DataFrame we can now add the team-level information from df_teams
.
As both datasets contain ‘race_name’, we drop one of them.
df_mbt = pd.merge(df_mbt, df_teams.drop('race_name', 1), on='team_id', how='left')
df_matches = pd.merge(df_matches, df_teams.drop(['race_name', 'roster_id', 'roster_name', 'games_played'], 1), left_on='team1_id', right_on = 'team_id', how='left')
df_matches['team1_id'] = pd.to_numeric(df_matches.team1_id)
df_matches = df_matches.drop('team_id', 1)
According to this article from the NAF from 2017, already since 2010 efforts were made to balance things out a bit between the different team strengths. For example, the weaker teams get more gold to spend on players, or get more so-called “Star player points” to spend on skilling players up. According to the NAF, traditionally team tiering consists of three groups, with Tier 1 being the strongest teams, and tier 3 the weakest teams. The GW BB2020 rule book also contains three tier groups, that are similar to the NAF tiers: except for Humans and Old World Alliance. And in november 2021, Games Workshop published an update of the three tier groups, now with High Elves moving from tier 2 to tier 1, and Old World Alliance moving back to tier 2.
This is most naturally added to the df_mbt
dataframe, as it can differ for each team in a match.
race_tiers = pd.read_excel('data/race_tiers_mapping.xlsx', engine='openpyxl')
race_tiers = race_tiers[ ['race_name', 'bb2020_tier', 'naf_tier', 'bb2020_nov21_tier']]
race_tiers = race_tiers.dropna()
# add bb2020 tiers
df_mbt = pd.merge(df_mbt, race_tiers, on='race_name', how='left')
target = 'data/df_inducements_final.h5'
df_inducements.to_hdf(target, key='df_inducements', mode='w', format = 't', complevel = 9)
target = 'data/inducements_final.h5'
inducements.to_hdf(target, key='inducements', mode='w', format = 't', complevel = 9)
target = 'data/df_matches_final.h5'
df_matches.to_hdf(target, key='df_matches', mode='w', format = 't', complevel = 9)
target = 'data/df_mbt_final.h5'
df_mbt.to_hdf(target, key='df_mbt', mode='w', format = 't', complevel = 9)
An important part of making data publicly available is being explicit about what is allowed if people want to use the dataset. However, before we do so, we have to check if we are actually allowed to publish the data. This is explained nicely in a blogpost by Elizabeth Wickes.
Since our data will come from the FUMBBL.com website, we check the Privacy policy where all users, including myself have agreed on when signing up. It contains this part which is specific to the unauthenticated API, which we use to fetch the data, as well as additional public match data, such as which inducements are used in a match, and the Coach rankings of the playing coaches that were current when the match was played.
Content you provide through the website
All the information you provide through the website is processed by FUMBBL. This includes things such as forum posts, private message posts, blog entries, team and player names and biographies and news comments. Data provided this way is visible by other people on the website and in most cases public even to individuals without accounts (not including private messages), and as such are considered of public interest. If direct personal information is posted in public view, you can contact moderators to resolve this. Match records are also considered content in this context, and is also considered of public interest. This data is collected as the primary purpose of the website and it is of course entirely up to you how much of this is provided to FUMBBL.
Third party sharing
Some of the public data is available through a public (*i.e. unauthenticated*) API, which shares some of the information provided by FUMBBL users in a way suitable for third-party websites and services to process.
The data available through the unauthenticated API is considered non-personal as it only reflects information that is public by its nature on the website. The authenticated API will only show information connected to the authenticated account.
I conclude that since the match data is already considered public content, there is no harm in collecting this public data in a structured dataset and placing this data in a public repository. The final step is then to decide what others are allowed to do with this data. In practice, this means choosing a license under which to release the dataset. I decided to choose a CC0 license: this places the data in the public domain, and people can use the dataset as they wish. Citing or mentioning the source of the data would still be appreciated of course.


Plugin Information |
|---|
View TurboScript on the plugin site for more information. |
The TurboScript plugin for Jenkins allows to automatically build Spoon images and push them to the Turbo.net Hub or local repository.
The TurboScript Jenkins plugin includes the following capabilities:
- Build an image with TurboScript
- Push the resulting image to the Turbo.net Hub
- Export an image to the local repository
- Trigger a build job using webhooks
Quick Tour
Build an image with TurboScript
- Create a new Jenkins item and select a Turbo Project as its type.
- Add Execute TurboScript build step.
- By convention, the default name for a TurboScript file is turbo.me. It should be located in the Jenkins project workspace which corresponds to the root directory of a GitHub project.
- Write a TurboScript to define how a new image should be created. For more information about TurboScript refer to the language reference or take a look at sample scripts in GitHub.
- Provide credentials to a Turbo.net account. If no credentials are provided, the TurboScript will be run as the currently logged on user.
- For enterprise deployments you may be interested in building images that target a specific version of the Turbo VM. To gain access to this and other optional settings, click Advanced button. For more information about specific options, click buttons with help content or refer to the online documentation.
- Save your changes and test the script by triggering the job manually. In the next sections you will learn how to push new images to the Turbo.net Hub.
Push an image to the Spoon.net Hub
Pushing images to the Turbo.net Hub is available as post-build action:
There are three options for naming the new remote image:
- Use the same name as the local image.
- Generate the remote image name from the Git information for your project (organization, project, branch, and current head version). Note that you cannot publish images from an organization to which you do not belong. For example, if your Spoon.net account name is JimmyKimmel then you won’t be allowed to push images as OprahWinfrey. If this is required, then overwrite the name of the GitHub organization with your account name.
- Use a fixed remote image name hardcoded in the job definition. Optionally, you may append a suffix from the date and time in order to keep old images available in the Spoon.net Hub.
Export an image to the local repository
Exporting images to the local repository is available as post-build action:
Remove an image from the local repository
New images will remain in the local repository unless they are deleted using the spoon rmi <image_name>
command. This step can be included in the job definition using the post-build action Remove local Turbo image.
Trigger a build job using webhooks
You may decide to build a Turbo container image whenever the source code changes for your project. To facilitate this, a Turbo Jenkins job can be triggered using an HTTP POST request. The request content is required to be compatible with the structure of GitHub webhook events.
Webhook messages are sent to Jenkins_URL/turbo-webhook endpoint as POST with Content-Type
set to application/x-www-form-urlencoded
.
Enjoy and please send any feedback or questions to @turbohq!
Change Log
Version 1.2 (Jan 4, 2016)
- Build and profile streaming models
- Take snapshots using Studio, Vagrant, VirtualBox
Version 1.1 (Oct 10, 2015)
- Rename and update to work with Turbo.net
Version 1.0 (Apr 21, 2014)
- Build an image with TurboScript
- Push the resulting image to the Turbo.net Hub
- Export an image to the local repository
- Trigger a build job using webhooks
- Integration with Credentials plugin
- Integration with Git plugin
Attachments:
jenkins_remove_local_image.png (image/png)
jenkins_push_overwrite_organization.png (image/png)
jenkins_push_fixed_image_name.png (image/png)
jenkins_push.png (image/png)
jenkins_push.png (image/png)
jenkins_project_configure_4.png (image/png)
jenkins_project_configure_4.png (image/png)
jenkins_project_configure_3.png (image/png)
jenkins_project_configure_2.png (image/png)
jenkins_project_configure_1.png (image/png)
jenkins_export_image_outputfile.png (image/png)
jenkins_export_image.png (image/png)
jenkins_configure_5.png (image/png)
jenkins_webhook_endpoint.png (image/png)


The Team
Elvis Ibarra—Project Lead
I am a full stack web engineer who is passionate about new technologies, education, and mission driven work .
Vu Cao-Back-End Engineer
I am full stack software developer with strong background in data analysis. I'm interested in solving interesting and challenging problems
John Humphreys-Data Scientist
"In a past life, clinical pharmacy was my vocation. Now, I seek not only to help care recipients but also to solve computationally-intensive problems—plus get more culture [more football, please!]."
Carlos Guiterrez-Data Scientist
Ryan Clark
Header
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
Peter Gambino-UI Developer
I'm a Full-Stack Engineer student currently attending Lambda School looking to help you come up with the best solutions and implementations for your projects using the latest web-based technologies.