invoking bazi from the internet using the json-rpc protocol · it allows web applications to invoke...

104
Invoking BAZI from the Internet using the JSON-RPC protocol Daniel Bierer (Statistisches Amt Kanton Zürich) August 2018 Contents 1 Introduction 3 2 API Usage 4 2.1 JSON-RPC-Request ....................... 4 2.1.1 Members of the Request Object ............. 4 2.1.2 Members of the Params Object ............. 5 Data source ........................ 5 Algorithm ......................... 6 Number of available mandates per district ....... 6 Number of votes per party and per district ....... 6 2.1.3 Sending the Request Object ............... 8 2.2 JSON-RPC Response ....................... 10 2.2.1 Members of the Response Object ............ 10 2.2.2 Extracting Content of the Response Object ....... 16 2.3 Example Web Application .................... 17 3 Source Code 17 3.1 Modified BAZI entry point .................... 17 3.2 BAZI-RPC ............................ 37 3.2.1 Package ch.zh.baziinternet.input ............. 37 Interface InputData .................... 37 Class InputData_Historical ............... 38 1

Upload: others

Post on 21-Oct-2020

13 views

Category:

Documents


0 download

TRANSCRIPT

  • Invoking BAZI from the Internetusing the JSON-RPC protocol

    Daniel Bierer(Statistisches Amt Kanton Zürich)

    August 2018

    Contents1 Introduction 3

    2 API Usage 42.1 JSON-RPC-Request . . . . . . . . . . . . . . . . . . . . . . . 4

    2.1.1 Members of the Request Object . . . . . . . . . . . . . 42.1.2 Members of the Params Object . . . . . . . . . . . . . 5

    Data source . . . . . . . . . . . . . . . . . . . . . . . . 5Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . 6Number of available mandates per district . . . . . . . 6Number of votes per party and per district . . . . . . . 6

    2.1.3 Sending the Request Object . . . . . . . . . . . . . . . 82.2 JSON-RPC Response . . . . . . . . . . . . . . . . . . . . . . . 10

    2.2.1 Members of the Response Object . . . . . . . . . . . . 102.2.2 Extracting Content of the Response Object . . . . . . . 16

    2.3 Example Web Application . . . . . . . . . . . . . . . . . . . . 17

    3 Source Code 173.1 Modified BAZI entry point . . . . . . . . . . . . . . . . . . . . 173.2 BAZI-RPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

    3.2.1 Package ch.zh.baziinternet.input . . . . . . . . . . . . . 37Interface InputData . . . . . . . . . . . . . . . . . . . . 37Class InputData_Historical . . . . . . . . . . . . . . . 38

    1

  • Class InputData_JSON_RPC . . . . . . . . . . . . . . 42Class InputData_Normal . . . . . . . . . . . . . . . . 46

    3.2.2 Package ch.zh.baziinternet.iobazi . . . . . . . . . . . . 50Class ApportionmentSub_ColumnTitles . . . . . . . . 50Class ApportionmentSub_Votes_Seats_LGDivisors . . 51Class ApportionmentSub_WKDivisors . . . . . . . . . 54Class ApportionmentSub . . . . . . . . . . . . . . . . . 56Class ApportionmentSuper . . . . . . . . . . . . . . . . 59Class BAZI_Input . . . . . . . . . . . . . . . . . . . . 62Class BAZI_Output . . . . . . . . . . . . . . . . . . . 64

    3.2.3 Package ch.zh.baziinternet.main . . . . . . . . . . . . . 66Class MainServlet . . . . . . . . . . . . . . . . . . . . . 66

    3.2.4 Package ch.zh.baziinternet.outputhtml . . . . . . . . . 72Class HtmlForm . . . . . . . . . . . . . . . . . . . . . . 72Class HtmlMain . . . . . . . . . . . . . . . . . . . . . . 77

    3.2.5 Package ch.zh.baziinternet.outputjson . . . . . . . . . . 79Class Output_JSON_RPC_ApportionmentSub . . . . 79Class Output_JSON_RPC_ApportionmentSuper . . . 82Class Output_JSON_RPC . . . . . . . . . . . . . . . 85

    3.2.6 Package ch.zh.baziinternet.request . . . . . . . . . . . . 87Class Request_JSON_RPC . . . . . . . . . . . . . . . 87Class Request_Normal . . . . . . . . . . . . . . . . . . 92Interface Request . . . . . . . . . . . . . . . . . . . . . 95

    3.2.7 Package ch.zh.baziinternet.util . . . . . . . . . . . . . . 98Class DataReader . . . . . . . . . . . . . . . . . . . . . 98Class OutputReader . . . . . . . . . . . . . . . . . . . 102

    2

  • 1 IntroductionA new API, called BAZI-RPC, is provided to the public since August 2018by the Statistical Office of the Canton of Zurich under the following URL:

    https://www.web.statistik.zh.ch:8443/baziinternet/app

    It allows web applications to invoke BAZI (see BAZI at the University ofAugsburg) by the JSON-RPC protocol. The JSON-RPC protocol is a state-less, light-weight RPC protocol (see JSON-RPC 2.0 Specification):

    WebApp BAZI-RPCch.zh.baziinternet

    BAZIde.uni.augsburg.bazi

    JSON-RPCProtocol

    Java ClassInteraction

    Figure 1: Calling BAZI using the RPC protocol

    The source code of the BAZI-RPC web service is free software: you can re-distribute it and/or modify it under the terms of the GNU General PublicLicense as published by the Free Software Foundation, either version 3 of theLicense, or (at your option) any later version.

    The source code can be found in this document (see Section 3) as well asunder the following URL:

    https://www.web.statistik.zh.ch:8443/baziinternet/doc

    The motivation for providing BAZI-RPC is that there is a demand for offer-ing Zurich’s new apportionment procedure (see Chapter 2.12 of BAZI UserManual) to the public as a web service in such a way that the same divisors(from the range of possible divisors) are provided as in WABSTI1.

    1WABSTI is the software which is officially used by the Canton of Zurich in order tocalculate the apportionment of the seats for the parlament of the Canton of Zurich.

    3

    https://www.web.statistik.zh.ch:8443/baziinternet/apphttps://www.math.uni-augsburg.de/emeriti/pukelsheim/bazi/https://www.math.uni-augsburg.de/emeriti/pukelsheim/bazi/https://www.jsonrpc.org/specificationhttps://www.web.statistik.zh.ch:8443/baziinternet/dochttps://www.math.uni-augsburg.de/emeriti/pukelsheim/bazi/manual200710en.pdfhttps://www.math.uni-augsburg.de/emeriti/pukelsheim/bazi/manual200710en.pdf

  • It should be noted here that the developers of WABSTI have communicated(after a request at the end of June 2018) that WABSTI does not use anymoreBAZI in the background because they have now implemented their own pro-cedure (developed in corporation with the BAZI team in Augsburg).

    The inclusion of WABSTI source code into the BAZI-RPC web service isnot possible because the WABSTI source code is closed (in contrast to thesource code of BAZI). Nevertheless, the WABSTI developers have providedthe information how to parameterize BAZI in order to get the same divisorsas in WABSTI.

    2 API UsageIn section it is outlined how the BAZI-RPC web service can be consumed byweb application developers.

    2.1 JSON-RPC-RequestIn the following it is explained how to construct a JSON-RPC request object.In this context it is important to note that only information on such partiesshould be included into the request object that are really permitted to getseats. In the case of the Zurich Canton Parliament, for instance, parties withless than five percent of the votes over the whole Canton have to be excludedfrom the procedure.

    2.1.1 Members of the Request Object

    A RPC call consists in sending a request object to the BAZI-RPC WebService. The request object comprises the following members:

    4

  • Member Value Explanationjsonrpc 2.0 Version of JSON-RPCmethod seats API Method to get the super-

    and sub-apportionmentparams params Parameter object

    (see explanation below)id Any ID (for instance 123) BAZI-RPC will respond with

    the same value

    Table 1: Members of the request object

    2.1.2 Members of the Params Object

    The params object (see above) comprises the following information:

    • Information on the data source to be used

    • Information on the algorithm to be used

    • Information on how many mandates are available per district

    • Information on the number of votes of every party in every district

    The corresponding name conventions are outlined in the following.

    Data source

    Apart from requesting apportionments for any matrix of number of votes, theBAZI-RPC service also provides the possibility to request the historical datafrom 2015 and 2011. Therefore the source parameter has been introduced:

    Parameter Values Explanationsource form Usage of user’s matrix of number of votes

    data2015 Usage of the number of votes from 2015data2011 Usage of the number of votes from 2011

    Table 2: Possible values of parameter ”source”

    5

  • Algorithm

    In order to specify the algorithm (see BAZI User Manual) to be used forfinding the seat apportionment, the following values can be used:

    Parameter Possible Value Expected to produce thesame divisors as WABSTI

    bp asmdpt Yesasrand Noasextr Nottflpt Nottinte Noh_asmdpt_ttflpt Noh_asrand_ttflpt Noh_asextpr_ttflpt Noh_asmdpt_ttinte Noh_asrand_ttinte Noh_asextpr_ttinte Noh_ipfp_ttflpt Noh_ipfp_ttinte No

    Table 3: Possible values of parameter ”bp”

    Number of available mandates per district

    In order to specify the number of available mandates per district, the follow-ing naming convention for the parameters has been adopted:

    Member Example Value Explanationwk1mandates 4 Mandates of district (”Wahlkreis”) No. 1wk2mandates 12 Mandates of district (”Wahlkreis”) No. 2wkimandates ... Mandates of district (”Wahlkreis”) No. j

    Table 4: Specifying the mandates vector

    Number of votes per party and per district

    6

    https://www.math.uni-augsburg.de/emeriti/pukelsheim/bazi/manual200710en.pdf

  • In order to specify the number of votes per district and party, the followingnaming convention for the parameters has been adopted:

    Parameters Example Value Explanation

    wk1lg1 5234 Number of votes withhinthe district (”Wahlkreis”) No. 1of party (”Listengruppe”) No. 1

    wk1lg2 7936 Number of votes withhinthe district (”Wahlkreis”) No. 1of party (”Listengruppe”) No. 2

    ...

    wk2lg1 7936 Number of votes withhinthe district (”Wahlkreis”) No. 2of party (”Listengruppe”) No. 1

    ...

    wkilgj ... Number of votes withhinthe district (”Wahlkreis”) No. iof party (”Listengruppe”) No. j

    Table 5: Parameters for specifying the input matrix

    7

  • 2.1.3 Sending the Request Object

    The follwing JavaScript function shows how to send a request to the BAZI-RPC web service:

    1 function call_remote_procedure()2 {34 //Preparing parameters from form5 var ar = $('#formular').serializeArray();6 var laenge = ar.length;7 var params = "{";8 for(var i=0;i

  • 48 if (response.hasOwnProperty("result"))49 {50 show_response(response);51 }5253 //Falls kein Result−Objekt geliefert wird,54 //muss zwingend ein Error−Objekt vorhanden sein.55 //vgl. https://www.jsonrpc.org/specification56 else57 {585960 var jsonrpc = response.jsonrpc;61 var error_code = response.error.code;62 var error_message = response.error.message;63 var id = response.id;6465 var text = "An error occured.

    ";66 text = text + "";67 text = text + "";68 text = text + "JSONRPC:"+jsonrpc+"";69 text = text + "";70 text = text + "";71 text = text + "Error code:"+error_code+"";72 text = text + "";73 text = text + "";74 text = text + "Error message:"+error_message+"";75 text = text + "";76 text = text + "";77 text = text + "ID:"+id+"";78 text = text + "";79 text = text + "";8081 $('#response').html("");82 $('#response').append(text);8384 }85 },86 error : function()87 {88 $('#response').html("An error occured.

    ");89 }90 });9192 }

    Listing 1: JavaScript function ”call_remote_procedure()”

    9

  • 2.2 JSON-RPC Response2.2.1 Members of the Response Object

    The following example JSON-RPC response object shows the available mem-bers:

    1 2 <

    pre>{3 "jsonrpc":"2.0",4 "result":{"superapportionment":{5 "sum_voters": 284522,6 "sum_seats": 180,7 "divisor": 1580,8 "lgs": [9 {"lg_id":1,

    10 "lg_voters":86036,11 "lg_seats":5412 },13 {"lg_id":2,14 "lg_voters":56375,15 "lg_seats":3616 },17 {"lg_id":3,18 "lg_voters":49655,19 "lg_seats":3120 },21 {"lg_id":4,22 "lg_voters":20687,23 "lg_seats":1324 },25 {"lg_id":5,26 "lg_voters":21887,27 "lg_seats":1428 },29 {"lg_id":6,30 "lg_voters":13981,31 "lg_seats":932 },33 {"lg_id":7,34 "lg_voters":12242,35 "lg_seats":836 },37 {"lg_id":8,38 "lg_voters":7497,39 "lg_seats":540 },41 {"lg_id":9,42 "lg_voters":7629,43 "lg_seats":544 },45 {"lg_id":10,46 "lg_voters":8533,47 "lg_seats":548 }

    10

  • 49 ]50 },51 "subapportionment":{52 "wks":[53 {"wk_id":1,54 "wk_divisor":6000,55 "lgs": [56 {"lg_id":1,"lg_votes":5254,"lg_divisor":1.03,"lg_seats":1},57 {"lg_id":2,"lg_votes":7936,"lg_divisor":1.055,"lg_seats":1},58 {"lg_id":3,"lg_votes":6627,"lg_divisor":1,"lg_seats":1},59 {"lg_id":4,"lg_votes":3558,"lg_divisor":1,"lg_seats":1},60 {"lg_id":5,"lg_votes":2594,"lg_divisor":1.078,"lg_seats":0},61 {"lg_id":6,"lg_votes":1398,"lg_divisor":1,"lg_seats":0},62 {"lg_id":7,"lg_votes":498,"lg_divisor":0.97,"lg_seats":0},63 {"lg_id":8,"lg_votes":0,"lg_divisor":0.66,"lg_seats":0},64 {"lg_id":9,"lg_votes":247,"lg_divisor":0.69,"lg_seats":0},65 {"lg_id":10,"lg_votes":1672,"lg_divisor":0.8,"lg_seats":0}66 ]67 },68 {"wk_id":2,69 "wk_divisor":16000,70 "lgs": [71 {"lg_id":1,"lg_votes":40938,"lg_divisor":1.03,"lg_seats":2},72 {"lg_id":2,"lg_votes":59704,"lg_divisor":1.055,"lg_seats":4},73 {"lg_id":3,"lg_votes":24457,"lg_divisor":1,"lg_seats":2},74 {"lg_id":4,"lg_votes":21153,"lg_divisor":1,"lg_seats":1},75 {"lg_id":5,"lg_votes":15292,"lg_divisor":1.078,"lg_seats":1},76 {"lg_id":6,"lg_votes":10345,"lg_divisor":1,"lg_seats":1},77 {"lg_id":7,"lg_votes":5471,"lg_divisor":0.97,"lg_seats":0},78 {"lg_id":8,"lg_votes":1811,"lg_divisor":0.66,"lg_seats":0},79 {"lg_id":9,"lg_votes":1260,"lg_divisor":0.69,"lg_seats":0},80 {"lg_id":10,"lg_votes":16831,"lg_divisor":0.8,"lg_seats":1}81 ]82 },83 {"wk_id":3,84 "wk_divisor":6120,85 "lgs": [86 {"lg_id":1,"lg_votes":3083,"lg_divisor":1.03,"lg_seats":0},87 {"lg_id":2,"lg_votes":10421,"lg_divisor":1.055,"lg_seats":2},88 {"lg_id":3,"lg_votes":3057,"lg_divisor":1,"lg_seats":0},89 {"lg_id":4,"lg_votes":5124,"lg_divisor":1,"lg_seats":1},90 {"lg_id":5,"lg_votes":3306,"lg_divisor":1.078,"lg_seats":1},91 {"lg_id":6,"lg_votes":728,"lg_divisor":1,"lg_seats":0},92 {"lg_id":7,"lg_votes":324,"lg_divisor":0.97,"lg_seats":0},93 {"lg_id":8,"lg_votes":254,"lg_divisor":0.66,"lg_seats":0},94 {"lg_id":9,"lg_votes":185,"lg_divisor":0.69,"lg_seats":0},95 {"lg_id":10,"lg_votes":5917,"lg_divisor":0.8,"lg_seats":1}96 ]97 },98 {"wk_id":4,99 "wk_divisor":15600,

    100 "lgs": [101 {"lg_id":1,"lg_votes":24108,"lg_divisor":1.03,"lg_seats":2},102 {"lg_id":2,"lg_votes":43212,"lg_divisor":1.055,"lg_seats":3},103 {"lg_id":3,"lg_votes":23290,"lg_divisor":1,"lg_seats":1},104 {"lg_id":4,"lg_votes":14986,"lg_divisor":1,"lg_seats":1},105 {"lg_id":5,"lg_votes":12614,"lg_divisor":1.078,"lg_seats":1},

    11

  • 106 {"lg_id":6,"lg_votes":5605,"lg_divisor":1,"lg_seats":0},107 {"lg_id":7,"lg_votes":3157,"lg_divisor":0.97,"lg_seats":0},108 {"lg_id":8,"lg_votes":1884,"lg_divisor":0.66,"lg_seats":0},109 {"lg_id":9,"lg_votes":868,"lg_divisor":0.69,"lg_seats":0},110 {"lg_id":10,"lg_votes":13162,"lg_divisor":0.8,"lg_seats":1}111 ]112 },113 {"wk_id":5,114 "wk_divisor":11500,115 "lgs": [116 {"lg_id":1,"lg_votes":12107,"lg_divisor":1.03,"lg_seats":1},117 {"lg_id":2,"lg_votes":18251,"lg_divisor":1.055,"lg_seats":2},118 {"lg_id":3,"lg_votes":20260,"lg_divisor":1,"lg_seats":2},119 {"lg_id":4,"lg_votes":7934,"lg_divisor":1,"lg_seats":1},120 {"lg_id":5,"lg_votes":6166,"lg_divisor":1.078,"lg_seats":0},121 {"lg_id":6,"lg_votes":3421,"lg_divisor":1,"lg_seats":0},122 {"lg_id":7,"lg_votes":1681,"lg_divisor":0.97,"lg_seats":0},123 {"lg_id":8,"lg_votes":579,"lg_divisor":0.66,"lg_seats":0},124 {"lg_id":9,"lg_votes":334,"lg_divisor":0.69,"lg_seats":0},125 {"lg_id":10,"lg_votes":3571,"lg_divisor":0.8,"lg_seats":0}126 ]127 },128 {"wk_id":6,129 "wk_divisor":12000,130 "lgs": [131 {"lg_id":1,"lg_votes":42103,"lg_divisor":1.03,"lg_seats":3},132 {"lg_id":2,"lg_votes":43393,"lg_divisor":1.055,"lg_seats":3},133 {"lg_id":3,"lg_votes":18551,"lg_divisor":1,"lg_seats":2},134 {"lg_id":4,"lg_votes":12862,"lg_divisor":1,"lg_seats":1},135 {"lg_id":5,"lg_votes":12147,"lg_divisor":1.078,"lg_seats":1},136 {"lg_id":6,"lg_votes":10313,"lg_divisor":1,"lg_seats":1},137 {"lg_id":7,"lg_votes":5687,"lg_divisor":0.97,"lg_seats":0},138 {"lg_id":8,"lg_votes":3382,"lg_divisor":0.66,"lg_seats":0},139 {"lg_id":9,"lg_votes":2430,"lg_divisor":0.69,"lg_seats":0},140 {"lg_id":10,"lg_votes":6889,"lg_divisor":0.8,"lg_seats":1}141 ]142 },143 {"wk_id":7,144 "wk_divisor":11400,145 "lgs": [146 {"lg_id":1,"lg_votes":52052,"lg_divisor":1.03,"lg_seats":4},147 {"lg_id":2,"lg_votes":25020,"lg_divisor":1.055,"lg_seats":2},148 {"lg_id":3,"lg_votes":28696,"lg_divisor":1,"lg_seats":3},149 {"lg_id":4,"lg_votes":5283,"lg_divisor":1,"lg_seats":0},150 {"lg_id":5,"lg_votes":8038,"lg_divisor":1.078,"lg_seats":1},151 {"lg_id":6,"lg_votes":11961,"lg_divisor":1,"lg_seats":1},152 {"lg_id":7,"lg_votes":5487,"lg_divisor":0.97,"lg_seats":0},153 {"lg_id":8,"lg_votes":2288,"lg_divisor":0.66,"lg_seats":0},154 {"lg_id":9,"lg_votes":1620,"lg_divisor":0.69,"lg_seats":0},155 {"lg_id":10,"lg_votes":1792,"lg_divisor":0.8,"lg_seats":0}156 ]157 },158 {"wk_id":8,159 "wk_divisor":10000,160 "lgs": [161 {"lg_id":1,"lg_votes":21870,"lg_divisor":1.03,"lg_seats":2},162 {"lg_id":2,"lg_votes":12297,"lg_divisor":1.055,"lg_seats":1},

    12

  • 163 {"lg_id":3,"lg_votes":12280,"lg_divisor":1,"lg_seats":1},164 {"lg_id":4,"lg_votes":4737,"lg_divisor":1,"lg_seats":0},165 {"lg_id":5,"lg_votes":5557,"lg_divisor":1.078,"lg_seats":1},166 {"lg_id":6,"lg_votes":2599,"lg_divisor":1,"lg_seats":0},167 {"lg_id":7,"lg_votes":5882,"lg_divisor":0.97,"lg_seats":1},168 {"lg_id":8,"lg_votes":0,"lg_divisor":0.66,"lg_seats":0},169 {"lg_id":9,"lg_votes":1510,"lg_divisor":0.69,"lg_seats":0},170 {"lg_id":10,"lg_votes":691,"lg_divisor":0.8,"lg_seats":0}171 ]172 },173 {"wk_id":9,174 "wk_divisor":23700,175 "lgs": [176 {"lg_id":1,"lg_votes":109374,"lg_divisor":1.03,"lg_seats":4},177 {"lg_id":2,"lg_votes":62568,"lg_divisor":1.055,"lg_seats":3},178 {"lg_id":3,"lg_votes":80566,"lg_divisor":1,"lg_seats":3},179 {"lg_id":4,"lg_votes":22022,"lg_divisor":1,"lg_seats":1},180 {"lg_id":5,"lg_votes":27859,"lg_divisor":1.078,"lg_seats":1},181 {"lg_id":6,"lg_votes":30240,"lg_divisor":1,"lg_seats":1},182 {"lg_id":7,"lg_votes":15687,"lg_divisor":0.97,"lg_seats":1},183 {"lg_id":8,"lg_votes":10657,"lg_divisor":0.66,"lg_seats":1},184 {"lg_id":9,"lg_votes":5684,"lg_divisor":0.69,"lg_seats":0},185 {"lg_id":10,"lg_votes":4659,"lg_divisor":0.8,"lg_seats":0}186 ]187 },188 {"wk_id":10,189 "wk_divisor":26000,190 "lgs": [191 {"lg_id":1,"lg_votes":101578,"lg_divisor":1.03,"lg_seats":4},192 {"lg_id":2,"lg_votes":47955,"lg_divisor":1.055,"lg_seats":2},193 {"lg_id":3,"lg_votes":93626,"lg_divisor":1,"lg_seats":4},194 {"lg_id":4,"lg_votes":16325,"lg_divisor":1,"lg_seats":1},195 {"lg_id":5,"lg_votes":25014,"lg_divisor":1.078,"lg_seats":1},196 {"lg_id":6,"lg_votes":14596,"lg_divisor":1,"lg_seats":1},197 {"lg_id":7,"lg_votes":7170,"lg_divisor":0.97,"lg_seats":0},198 {"lg_id":8,"lg_votes":6390,"lg_divisor":0.66,"lg_seats":0},199 {"lg_id":9,"lg_votes":8963,"lg_divisor":0.69,"lg_seats":0},200 {"lg_id":10,"lg_votes":3734,"lg_divisor":0.8,"lg_seats":0}201 ]202 },203 {"wk_id":11,204 "wk_divisor":22000,205 "lgs": [206 {"lg_id":1,"lg_votes":83273,"lg_divisor":1.03,"lg_seats":4},207 {"lg_id":2,"lg_votes":30668,"lg_divisor":1.055,"lg_seats":1},208 {"lg_id":3,"lg_votes":32729,"lg_divisor":1,"lg_seats":1},209 {"lg_id":4,"lg_votes":14655,"lg_divisor":1,"lg_seats":1},210 {"lg_id":5,"lg_votes":15830,"lg_divisor":1.078,"lg_seats":1},211 {"lg_id":6,"lg_votes":13017,"lg_divisor":1,"lg_seats":1},212 {"lg_id":7,"lg_votes":13598,"lg_divisor":0.97,"lg_seats":1},213 {"lg_id":8,"lg_votes":8358,"lg_divisor":0.66,"lg_seats":1},214 {"lg_id":9,"lg_votes":15419,"lg_divisor":0.69,"lg_seats":1},215 {"lg_id":10,"lg_votes":3009,"lg_divisor":0.8,"lg_seats":0}216 ]217 },218 {"wk_id":12,219 "wk_divisor":24000,

    13

  • 220 "lgs": [221 {"lg_id":1,"lg_votes":127780,"lg_divisor":1.03,"lg_seats":5},222 {"lg_id":2,"lg_votes":67381,"lg_divisor":1.055,"lg_seats":3},223 {"lg_id":3,"lg_votes":59884,"lg_divisor":1,"lg_seats":2},224 {"lg_id":4,"lg_votes":21491,"lg_divisor":1,"lg_seats":1},225 {"lg_id":5,"lg_votes":34535,"lg_divisor":1.078,"lg_seats":1},226 {"lg_id":6,"lg_votes":17936,"lg_divisor":1,"lg_seats":1},227 {"lg_id":7,"lg_votes":11775,"lg_divisor":0.97,"lg_seats":1},228 {"lg_id":8,"lg_votes":21761,"lg_divisor":0.66,"lg_seats":1},229 {"lg_id":9,"lg_votes":9767,"lg_divisor":0.69,"lg_seats":1},230 {"lg_id":10,"lg_votes":4414,"lg_divisor":0.8,"lg_seats":0}231 ]232 },233 {"wk_id":13,234 "wk_divisor":12000,235 "lgs": [236 {"lg_id":1,"lg_votes":32872,"lg_divisor":1.03,"lg_seats":3},237 {"lg_id":2,"lg_votes":14694,"lg_divisor":1.055,"lg_seats":1},238 {"lg_id":3,"lg_votes":13295,"lg_divisor":1,"lg_seats":1},239 {"lg_id":4,"lg_votes":5325,"lg_divisor":1,"lg_seats":0},240 {"lg_id":5,"lg_votes":6425,"lg_divisor":1.078,"lg_seats":0},241 {"lg_id":6,"lg_votes":2662,"lg_divisor":1,"lg_seats":0},242 {"lg_id":7,"lg_votes":7570,"lg_divisor":0.97,"lg_seats":1},243 {"lg_id":8,"lg_votes":2768,"lg_divisor":0.66,"lg_seats":0},244 {"lg_id":9,"lg_votes":4142,"lg_divisor":0.69,"lg_seats":1},245 {"lg_id":10,"lg_votes":759,"lg_divisor":0.8,"lg_seats":0}246 ]247 },248 {"wk_id":14,249 "wk_divisor":26200,250 "lgs": [251 {"lg_id":1,"lg_votes":68076,"lg_divisor":1.03,"lg_seats":3},252 {"lg_id":2,"lg_votes":75188,"lg_divisor":1.055,"lg_seats":3},253 {"lg_id":3,"lg_votes":39016,"lg_divisor":1,"lg_seats":1},254 {"lg_id":4,"lg_votes":28613,"lg_divisor":1,"lg_seats":1},255 {"lg_id":5,"lg_votes":25746,"lg_divisor":1.078,"lg_seats":1},256 {"lg_id":6,"lg_votes":16907,"lg_divisor":1,"lg_seats":1},257 {"lg_id":7,"lg_votes":23650,"lg_divisor":0.97,"lg_seats":1},258 {"lg_id":8,"lg_votes":8784,"lg_divisor":0.66,"lg_seats":1},259 {"lg_id":9,"lg_votes":7089,"lg_divisor":0.69,"lg_seats":0},260 {"lg_id":10,"lg_votes":11802,"lg_divisor":0.8,"lg_seats":1}261 ]262 },263 {"wk_id":15,264 "wk_divisor":13000,265 "lgs": [266 {"lg_id":1,"lg_votes":37310,"lg_divisor":1.03,"lg_seats":3},267 {"lg_id":2,"lg_votes":11911,"lg_divisor":1.055,"lg_seats":1},268 {"lg_id":3,"lg_votes":12989,"lg_divisor":1,"lg_seats":1},269 {"lg_id":4,"lg_votes":4711,"lg_divisor":1,"lg_seats":0},270 {"lg_id":5,"lg_votes":8133,"lg_divisor":1.078,"lg_seats":1},271 {"lg_id":6,"lg_votes":2914,"lg_divisor":1,"lg_seats":0},272 {"lg_id":7,"lg_votes":6458,"lg_divisor":0.97,"lg_seats":1},273 {"lg_id":8,"lg_votes":4181,"lg_divisor":0.66,"lg_seats":0},274 {"lg_id":9,"lg_votes":2847,"lg_divisor":0.69,"lg_seats":0},275 {"lg_id":10,"lg_votes":777,"lg_divisor":0.8,"lg_seats":0}276 ]

    14

  • 277 },278 {"wk_id":16,279 "wk_divisor":7000,280 "lgs": [281 {"lg_id":1,"lg_votes":13225,"lg_divisor":1.03,"lg_seats":2},282 {"lg_id":2,"lg_votes":4875,"lg_divisor":1.055,"lg_seats":1},283 {"lg_id":3,"lg_votes":5740,"lg_divisor":1,"lg_seats":1},284 {"lg_id":4,"lg_votes":2972,"lg_divisor":1,"lg_seats":0},285 {"lg_id":5,"lg_votes":1739,"lg_divisor":1.078,"lg_seats":0},286 {"lg_id":6,"lg_votes":597,"lg_divisor":1,"lg_seats":0},287 {"lg_id":7,"lg_votes":1007,"lg_divisor":0.97,"lg_seats":0},288 {"lg_id":8,"lg_votes":1939,"lg_divisor":0.66,"lg_seats":0},289 {"lg_id":9,"lg_votes":1224,"lg_divisor":0.69,"lg_seats":0},290 {"lg_id":10,"lg_votes":302,"lg_divisor":0.8,"lg_seats":0}291 ]292 },293 {"wk_id":17,294 "wk_divisor":26000,295 "lgs": [296 {"lg_id":1,"lg_votes":151323,"lg_divisor":1.03,"lg_seats":6},297 {"lg_id":2,"lg_votes":67966,"lg_divisor":1.055,"lg_seats":2},298 {"lg_id":3,"lg_votes":66897,"lg_divisor":1,"lg_seats":3},299 {"lg_id":4,"lg_votes":20355,"lg_divisor":1,"lg_seats":1},300 {"lg_id":5,"lg_votes":25543,"lg_divisor":1.078,"lg_seats":1},301 {"lg_id":6,"lg_votes":16196,"lg_divisor":1,"lg_seats":1},302 {"lg_id":7,"lg_votes":18532,"lg_divisor":0.97,"lg_seats":1},303 {"lg_id":8,"lg_votes":14239,"lg_divisor":0.66,"lg_seats":1},304 {"lg_id":9,"lg_votes":16968,"lg_divisor":0.69,"lg_seats":1},305 {"lg_id":10,"lg_votes":3608,"lg_divisor":0.8,"lg_seats":0}306 ]307 },308 {"wk_id":18,309 "wk_divisor":14740,310 "lgs": [311 {"lg_id":1,"lg_votes":72703,"lg_divisor":1.03,"lg_seats":5},312 {"lg_id":2,"lg_votes":23304,"lg_divisor":1.055,"lg_seats":1},313 {"lg_id":3,"lg_votes":22143,"lg_divisor":1,"lg_seats":2},314 {"lg_id":4,"lg_votes":8982,"lg_divisor":1,"lg_seats":1},315 {"lg_id":5,"lg_votes":10429,"lg_divisor":1.078,"lg_seats":1},316 {"lg_id":6,"lg_votes":5574,"lg_divisor":1,"lg_seats":0},317 {"lg_id":7,"lg_votes":4184,"lg_divisor":0.97,"lg_seats":0},318 {"lg_id":8,"lg_votes":2739,"lg_divisor":0.66,"lg_seats":0},319 {"lg_id":9,"lg_votes":9461,"lg_divisor":0.69,"lg_seats":1},320 {"lg_id":10,"lg_votes":875,"lg_divisor":0.8,"lg_seats":0}321 ]322 }323 ]324 }},325 "id":"123"326 }327328 329330

    Listing 2: Extracting a JSON Response Object

    15

  • 2.2.2 Extracting Content of the Response Object

    The response object can be extracted in the following way:1 function show_response(response)23 {45 $('#response').html("");67 //−−−−−−−−−−−−−−−−−−−−−//8 // Super−Apportionment //9 //−−−−−−−−−−−−−−−−−−−−−//

    10 var text = "Super−Apportionment:

    ";11 var super_lgs = response["result"]["superapportionment"].lgs;12 for(var i=0;i

  • 53 var lg_divisor = lgs[j]["lg_divisor"];54 var lg_seats = lgs[j]["lg_seats"];5556 var id = "wk"+wk_id+"lg"+lg_id;57 document.getElementById(id+"_divisor").value = lg_divisor;58 document.getElementById(id+"_seats").value = lg_seats;596061 text = text + "";62 text = text + ""+lg_id+"";63 text = text + ""+lg_votes+"";64 text = text + ""+lg_divisor+"";65 text = text + ""+lg_seats+"";66 text = text + "";6768 }6970 text = text + "";7172 $('#response').html("");73 $('#response').html(text);7475 }7677 }

    Listing 3: JavaScript function ”show_response()”

    2.3 Example Web ApplicationAn example of a minimalistic web application can be found under the fol-lowing URL:

    https://www.web.statistik.zh.ch:8443/baziinternet/frontend.html

    3 Source Code

    3.1 Modified BAZI entry pointIt was necessary to modify the BAZI entry point in order to make BAZIaccessible by the BAZI RPC service. The source code of the modified classde.uni.augsburg.bazi.driver.Calculation is shown below:

    1 /** @(#)Calculation.java 3.2 09/10/05

    3 ** Copyright (c) 2000−2009 Lehrstuhl für Stochastik und ihre Anwendungen

    17

    https://www.web.statistik.zh.ch:8443/baziinternet/frontend.html

  • 5 * Institut für Mathematik, Universität Augsburg

    * D−86135 Augsburg, Germany7 */

    9package de.uni.augsburg.bazi.driver;

    11import java.io.File;

    13 import java.math.BigDecimal;import java.util.Hashtable;

    15 import java.util.Vector;

    17 import org.apache.log4j.ConsoleAppender;import org.apache.log4j.Level;

    19 import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;

    21 import org.apache.log4j.SimpleLayout;

    23 import de.uni.augsburg.bazi.Resource;import de.uni.augsburg.bazi.VersionControl;

    25 import de.uni.augsburg.bazi.gui.RoundFrame;import de.uni.augsburg.bazi.lib.Convert;

    27 import de.uni.augsburg.bazi.lib.Divisor;import de.uni.augsburg.bazi.lib.DivisorException;

    29 import de.uni.augsburg.bazi.lib.ExtendedPowerMean;import de.uni.augsburg.bazi.lib.ExtendedStationary;

    31 import de.uni.augsburg.bazi.lib.IterationListener;import de.uni.augsburg.bazi.lib.MethodListener;

    33 import de.uni.augsburg.bazi.lib.ParameterOutOfRangeException;import de.uni.augsburg.bazi.lib.PermutationsCommunicator;

    35 import de.uni.augsburg.bazi.lib.PowerMean;import de.uni.augsburg.bazi.lib.Signpost;

    37 import de.uni.augsburg.bazi.lib.Stationary;import de.uni.augsburg.bazi.lib.Weight;

    39 import de.uni.augsburg.bazi.lib.vector.Method;

    41 /** Die folgende Zeile wurde von Daniel Bierer am 27.6.2018 eingefügt. */import java.io.InputStreamReader;

    43/** Title: Klasse Calculation

    45 * Description: Steuert den kompletten Berechnungsablauf und

    * stellt die Kommandozeilenversion des Bazi zur Verfügung
    47 * Copyright: Copyright (c) 2005−2010

    * Company: Universität Augsburg
    49 *

    * @version 3.251 * @author Florian Kluge, Robert Bertossi, Christian Brand, Marco Schumacher */

    public class Calculation53 {

    55 /** Copyright */public static final String COPYRIGHT = "2000−2011";

    57 /* Weitere Copyrightangaben:

    * − bazi.properties: bazi.gui.info59 * − Startbild

    * − gnupl.txt */61

    18

  • /** Zeichen, dass für Kommentare in der Ausgabe benutzt wird */63 public static final char COMMENT = '*';

    65 /** Standard Fu ß zeile der Ausgabe */public static final String APPENDIX = COMMENT + "BAZI " + VersionControl.

    getVersion() +67 " − Made in Augsburg University";

    69 /** Trennzeile in der Ausgabe (eine Zeile nur mit COMMENTs) */private static String outputBoundary = null;

    71/** Parameter bei einem Kommandozeilen Aufruf */

    73 private static Hashtable params = new Hashtable();

    75 /** bei Kommandozeilen Aufruf wird dieser Wert gesetzt */public static boolean isCommandLineBazi = false;

    77/** Eingelesene Eingabedaten */

    79 private AbstractInputData aid = null;

    81 /** IterationListener (für Kommandozeile) */private IterationListener il = null;

    83/** MethodListener (für Kommandozeile) */

    85 private MethodListener ml = null;

    87 /** PermutationsCommunicator (für Kommandozeile) */private PermutationsCommunicator pc = null;

    89/** Erstellt ein neues Calculation Objekt mit den übergebenen Eingabedaten

    91 * @param aid Eingabedaten */public Calculation(AbstractInputData aid)

    93 {this.aid = aid;

    95 if (ml == null){

    97 ml = new DummyMethodListener();}

    99 }

    101 /** main−Methode für Commandline−BAZI* @param args Parameter */

    103

    105 /** Die folgende Zeile wurde am 9.7.2018 von Daniel Bierer (Statistisches Amtdes Kantons Zürich)

    * auskommentiert und durch eine neue Zeile ersetzt.*/107 //public static void main(String[] args)

    109/**

    111 * BAZI entry point which returns BAZI output.

    *113 * @param args Parameters to be passed to BAZI.

    * @param isr BAZI input.115 * @return BAZI output.

    19

  • */117 public static String main(String[] args,InputStreamReader isr)

    {119

    Calculation.isCommandLineBazi = true;121

    File propertyFile = new File(".\\de\\uni\\augsburg\\bazi\\log4j.properties");

    123 if (!propertyFile.exists()){

    125 Logger.getRootLogger().addAppender(new ConsoleAppender(newSimpleLayout(), ConsoleAppender.SYSTEM_OUT));

    Logger.getRootLogger().setLevel(Level.OFF);127 }

    else129 {

    PropertyConfigurator.configure(".\\de\\uni\\augsburg\\bazi\\log4j.properties");

    131 }

    133parseParams(args);

    135

    137 /** Der folgende Block wurde am 27.6.2018 durch Daniel Biererauskommentiert. */

    /*139 // Datei mu ß angegeben werden!

    String file = params.get("file");141 if (file == null)

    {143 System.out.println("File to calculate must be stated");

    printUsageMessage();145 }*/

    147 String lang = params.get("lang");if (lang != null)

    149 {Resource.setLang(lang);

    151 }// System.out.println("lang: " + lang);

    153 // System.out.println("file: " + file);

    155 /** Der folgende Block wurde am 27.6.2018 durch Daniel Biererauskommentiert. */

    /*File f = new File(file);157 if (!f.exists())

    {159 System.out.println("File " + file + " does not exist!");

    System.exit(0);161 }

    */163

    // Einlesen der Datei165 FileIO fileio = new FileIO();

    20

  • 167 /** Die folgende Zeile wurde von Daniel Bierer am 27.6.2018 ausgeschaltet. */

    //AbstractInputData aid = fileio.open(f);169

    /** Die folgende Zeile wurde von Daniel Bierer am 27.6.2018 eingefügt171 * und am 9.7.2018 wiederum auskommentiert, da der InputStreamReader

    jetzt

    * als Parameter der main−Methode uebergeben wird. */173 //InputStreamReader isr = us.nasm.Input.get_isr();

    AbstractInputData aid = fileio.open(isr);175

    if (aid instanceof DistrictInputData)177 {

    DistrictInputData did = (DistrictInputData) aid;179 String alt = params.get("bp");

    if (alt != null)181 {

    if (alt.equals("11") || alt.equals("h_asmdpt_ttflpt"))183 did.bipropAlt = DistrictInputData.H_ASMDPT_TTFLPT;

    else if (alt.equals("13") || alt.equals("asmdpt"))185 did.bipropAlt = DistrictInputData.ASMDPT;

    187 else if (alt.equals("21") || alt.equals("h_asextr_ttflpt"))did.bipropAlt = DistrictInputData.H_ASEXTR_TTFLPT;

    189 else if (alt.equals("23") || alt.equals("asextr"))did.bipropAlt = DistrictInputData.ASEXTR;

    191else if (alt.equals("h_asmdpt_ttinte"))

    193 did.bipropAlt = DistrictInputData.H_ASMDPT_TTINTE;else if (alt.equals("h_asextr_ttinte"))

    195 did.bipropAlt = DistrictInputData.H_ASEXTR_TTINTE;else if (alt.equals("h_asrand_ttinte"))

    197 did.bipropAlt = DistrictInputData.H_ASRAND_TTINTE;

    199 else if (alt.equals("31") || alt.equals("h_asrand_ttflpt"))did.bipropAlt = DistrictInputData.H_ASRAND_TTFLPT;

    201 else if (alt.equals("33") || alt.equals("asrand"))did.bipropAlt = DistrictInputData.ASRAND;

    203else if (alt.equals("41") || alt.equals("h_ipfp_ttflpt"))

    205 did.bipropAlt = DistrictInputData.H_IPFP_TTFLPT;else if (alt.equals("42") || alt.equals("h_ipfp_ttinte"))

    207 did.bipropAlt = DistrictInputData.H_IPFP_TTINTE;

    209 else if (alt.equals("51") || alt.equals("ttflpt"))did.bipropAlt = DistrictInputData.TTFLPT;

    211 else if (alt.equals("52") || alt.equals("ttinte"))did.bipropAlt = DistrictInputData.TTINTE;

    213 }}

    215 Calculation calc = new Calculation(aid);calc.setIterationListener(new DummyIterationListener());

    217 calc.setMethodListener(new DummyMethodListener());calc.setPermutationsCommunicator(new DummyPermutationsCommunicator());

    219/** Die folgende Zeile wurde am 9.7.2018 von Daniel Bierer auskommentiert

    . */

    21

  • 221 //System.out.println(calc.calculate());

    223 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−//// Ergaenzung von Daniel Bierer //

    225 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−///** Die folgende Zeile wurde von Daniel Bierer am 27.6.2018 eingefuegt

    und227 * am 9.7.2018 wieder auskommentiert.*/

    //String nasm_resultate = calc.calculate();229

    /** Die folgende Zeile wurde am 9.7.2018 von Daniel Bierer eingefuegt. */231 return calc.calculate();

    //233 /** Die folgende Zeile wurde am 9.7.2018 von Daniel Bierer auskommentiert

    . *///System.exit(0);

    235 }

    237 /** Liefert die Trennzeile für die Ausgabe. Beim ersten Aufruf wird dieTrennzeile generiert, so dass sie die gleiche Länge hat wie die Fu ß zeile.

    * @return Trennzeile */239 public static String getOutputBoundary()

    {241 if (outputBoundary == null)

    {243 outputBoundary = "";

    for (int i = 0; i < APPENDIX.length(); i++)245 {

    outputBoundary += Calculation.COMMENT;247 }

    outputBoundary += "\n";249 }

    return outputBoundary;251 }

    253 /** Prints a usage message and exits */private static void printUsageMessage()

    255 {System.out.println("\n" +

    257 "//// Usage/////////////////////////////////////////////////////////\n"+

    "To print version:\n" +259 "java −cp bazi.jar de.uni.augsburg.bazi.driver.Calculation −−

    version\n" +"\n" +

    261 "To process a bazi input file:\n" +"java −cp bazi.jar de.uni.augsburg.bazi.driver.Calculation" +

    263 " [−bp ] [−l ] −f \n" +"\n" +

    265 "\tbp: possible values are {asmdpt|asrand|asextr|ttflpt|ttinte\n"+

    "\t |h_asmdpt_ttflpt|h_asrand_ttflpt|h_asextr_ttflpt|h_asmdpt_ttinte\n" +

    267 "\t |h_asextr_ttinte|h_asrand_ttinte|h_ipfp_ttflpt|h_ipfp_ttinte}\n" +

    22

  • "\tl : possible values are {de|en|es|fr|it}\n" +269 "\tf : followed by the path of the input file\n" +

    "//////////////////////////////////////////////////////////////////////\n");

    271 System.exit(0);}

    273/** Prints version information and exits */

    275 private static void printVersionMessage(){

    277 System.out.println("Bazi CommandLine Version " + VersionControl.getVersion());

    System.exit(0);279 }

    281 /** Liest die Eingabeparameter aus und füllt die Hashtable paramsentsprechend.

    * @param args Parameter */283 private static void parseParams(String[] args)

    {285 if (args.length == 1)

    {287 if (args[0].equals("−−version"))

    {289 printVersionMessage();

    }291 else

    {293 printUsageMessage();

    }295 }

    297 int i = 0;while (i < args.length)

    299 {String tmp = args[i];

    301 if (tmp.equals("−l")){

    303 i++;if (i == args.length)

    305 {printUsageMessage();

    307 }String lang = args[i];

    309 if (lang.equals("de") || lang.equals("en") || lang.equals("es")|| lang.endsWith("fr") || lang.equals("it"))

    311 {params.put("lang", lang);

    313 }else

    315 {System.out.println("Invalid language");

    317 printUsageMessage();}

    319 }if (tmp.equals("−f"))

    23

  • 321 {i++;

    323 if (i == args.length){

    325 printUsageMessage();}

    327 String file = args[i];params.put("file", file);

    329 }if (tmp.equals("−bp"))

    331 {i++;

    333 if (i == args.length){

    335 printUsageMessage();}

    337 String bp = args[i];if (!bp.equals("11") && !bp.equals("h_asmdpt_ttflpt") &&

    339 !bp.equals("13") && !bp.equals("asmdpt") &&!bp.equals("21") && !bp.equals("h_asextr_ttflpt") &&

    341 !bp.equals("23") && !bp.equals("asextr") &&!bp.equals("31") && !bp.equals("h_asrand_ttflpt") &&

    343 !bp.equals("33") && !bp.equals("asrand") &&!bp.equals("41") && !bp.equals("h_ipfp_ttflpt") &&

    345 !bp.equals("42") && !bp.equals("h_ipfp_ttinte") &&!bp.equals("51") && !bp.equals("ttflpt") &&

    347 !bp.equals("52") && !bp.equals("ttinte") &&!bp.equals("h_asmdpt_ttinte") &&

    349 !bp.equals("h_asextr_ttinte") &&!bp.equals("h_asrand_ttinte"))

    351 printUsageMessage();params.put("bp", bp);

    353 }i++;

    355 }}

    357/** Setzt den IterationListener

    359 * @param l IterationListener */public void setIterationListener(IterationListener l)

    361 {il = l;

    363 }

    365 /** Setzt den MethodListener

    *367 * @param l MethodListener */

    public void setMethodListener(MethodListener l)369 {

    ml = l;371 }

    373 /** Setzt den PermutationsCommunicator

    * @param c PermutationsCommunicator */375 public void setPermutationsCommunicator(PermutationsCommunicator c)

    {377 pc = c;

    24

  • }379

    public String calculate()381 {

    if (aid.pow)383 return new Calculation_Pow().calculate(aid);

    385 if (aid.outputFormat.condition == OutputFormat.CONDITION_MIN_PLUS|| aid.outputFormat.condition == OutputFormat.CONDITION_MIN_VPV)

    387 return new Calculation_LevelingSeats().calculate(aid);

    389 return calculate2();}

    391/** Berechnet die Zuteilung und gibt diese aus (formatiert als String)

    393 * @return Zuteilung */public String calculate2()

    395 {String output = getOutputBoundary();

    397// monoproportional => einfach ;−)

    399 if (aid instanceof InputData){

    401 InputData id = (InputData) aid;CalculationMonoprop c = new CalculationMonoprop(id, ml);

    403 output += c.start();for (int i = 0; i < id.listData.length; i++)

    405 {String listOutput = new CalculationMonoprop(id.listData[i], ml).

    start();407 output += listOutput;

    }409 }

    411 // mit Distriktenelse if (aid instanceof DistrictInputData)

    413 {output += Calculation.COMMENT + aid.title + "\n";

    415 DistrictInputData did = (DistrictInputData) aid;switch (did.method)

    417 {case DistrictInputData.SEPARATE:

    419 {output += calcSeparate(did);

    421 break;}

    423 case DistrictInputData.BIPROP:case DistrictInputData.NZZ:

    425 output += calcBiprop(did);break;

    427 }}

    429if (!output.endsWith("\n"))

    431 {output += "\n";

    433 }

    25

  • output += APPENDIX + "\n" + outputBoundary;435 ml.printMessage(APPENDIX + "\n");

    return output;437 }

    439 /** Berechnet die Zuteilung für die übergebenen Eingabedaten. (Seperate

    * Distriktauswertung)441 * @param did Eingabedaten mit mehreren Distrikten

    * @return Die Zuteilung als String formatiert */443 public String calcSeparate(DistrictInputData did)

    {445 did.prepare();

    String output = new CalculationSeparate(did).start();447 return output;

    }449

    /** Berechnet die Zuteilung für die übergebenen Eingabedaten. (Biproportionale

    451 * Berechnung)

    * @param did Eingabedaten mit mehreren Distrikten453 * @return Die Zuteilung als String formatiert */

    public String calcBiprop(DistrictInputData did)455 {

    did.prepare();457 String output = new CalculationBiprop(did, il, ml, pc).start();

    return output;459 }

    461 private static class DummyMethodListener implements MethodListener{

    463 @Overridepublic void printMessage(String msg)

    465 {// Leerer Method Listener

    467 // System.out.println(msg);}

    469 }

    471 private static class DummyIterationListener implements IterationListener{

    473 @Overridepublic void initialize(String[] methods)

    475 {}

    477 @Overridepublic void iterationChanged(int cnt, boolean finished)

    479 {}

    481 @Overridepublic void iterationFinished()

    483 {}}

    485private static class DummyPermutationsCommunicator implements

    PermutationsCommunicator487 {

    @Override

    26

  • 489 public boolean calcAllPermutations(){

    491 return false;}

    493@Override

    495 public void permutationChanged(int cnt){}

    497 }

    499 /** Formatiert die gesamte Lösung, d.h. die Ausrichtung wird festgelegt unddie

    * Spaltenbreite wird angepasst.501 * @param v Ein Vektor Array mit den Spalten bzw. Zeilen (je nach

    * Ausrichtung) der Ausgabe503 * @param now Anzahl der Gewichte

    * @param align Ausrichtung (aus OutputFormat)505 * @return Formatierte Ausgabe */

    public static String writeSolution(Vector v, int now, int align)507 {

    int numberOfWeights = now;509 // System.out.println(now);

    // System.out.println("now: " + now);511 // Titel ausgeben

    // StringBuffer sOutput = new StringBuffer("#" + title + "\n");513 StringBuffer sOutput = new StringBuffer();

    515 if (align == OutputFormat.ALIGN_HORIZONTAL){

    517 // String mit maximaler Länge in jeder Spalte suchen// Maximum: 16

    519 int columnLength[] = new int[numberOfWeights + 1];for (int m = 0; m < numberOfWeights + 1; m++)

    521 {columnLength[m] = 0;

    523 }for (int i = 0; i < v.size(); i++)

    525 {// System.out.print("\ni: " + i + " −−− ");

    527 String s[] = v.elementAt(i);for (int k = 0; k < numberOfWeights + 1; k++)

    529 {// System.out.print("k: " + k + "; " + s[k] + " ;; ");

    531 int temp = s[k].length();if (temp > columnLength[k])

    533 {columnLength[k] = temp;

    535 }}

    537 }

    539 // jeder Vectoreintrag ist eine Zeile der Ausgabefor (int i = 0; i < v.size(); i++)

    541 {String s[] = v.elementAt(i);

    543 for (int k = 0; k < numberOfWeights + 1; k++){

    27

  • 545 int temp = s[k].length();if (k == 0)

    547 {sOutput.append(s[k]);

    549 }for (int n = 0; n < (columnLength[k] − temp); n++)

    551 {sOutput.append(" ");

    553 }if (k != 0)

    555 {sOutput.append(" " + s[k]);

    557 }}

    559 sOutput.append(" \n");}

    561 }else

    563 { // Vertikale Ausgabe// String mit maximaler Länge in jeder Spalte suchen

    565 int columnLength[] = new int[v.size()];for (int m = 0; m < v.size(); m++)

    567 {columnLength[m] = 0;

    569 }for (int i = 0; i < v.size(); i++)

    571 {String s[] = v.elementAt(i);

    573 for (int k = 0; k < numberOfWeights + 1; k++){

    575 int temp = s[k].length();if (temp > columnLength[i])

    577 {columnLength[i] = temp;

    579 }}

    581 }

    583 // jeder Vectoreintrag ist eine Spalte der Ausgabefor (int k = 0; k < numberOfWeights + 1; k++)

    585 {for (int i = 0; i < v.size(); i++)

    587 {String s[] = v.elementAt(i);

    589 int temp = s[k].length();if (i == 0)

    591 {sOutput.append(s[k]);

    593 }for (int n = 0; n < (columnLength[i] − temp); n++)

    595 {sOutput.append(" ");

    597 }if (i != 0)

    599 {sOutput.append(" " + s[k]);

    601 }

    28

  • }603 sOutput.append(" \n");

    }605 }

    607 return sOutput.toString();}

    609

    611 public static String[] getQuotientenspalte(Weight[] wa, double divisor,MethodData d, AbstractInputData data)

    {613 Signpost sp = getSignpost(d);

    615 String[] out = new String[wa.length + 3];out[0] = Resource.getString("bazi.gui.output.quotient");

    617for (int i = 0; i < wa.length; i++)

    619 {String base = data.BMM ? data.base + RoundFrame.BASE_SEPERATOR : "";

    621 out[i + 1] = base + outputRoundQuotient(wa[i].weight / divisor, sp);if (wa[i].weight / divisor < sp.s(wa[i].rdWeight − 1)

    623 || wa[i].weight / divisor > sp.s(wa[i].rdWeight))out[i + 1] += ".";

    625 }

    627 String div = Convert.doubleToString(divisor);out[wa.length + 1] = String.format("(%s)", div);

    629 out[wa.length + 2] = "";return out;

    631 }

    633 public static String getQuotientenFeld(double weight, int rd, double divisor,MethodData d)

    {635 Signpost sp = getSignpost(d);

    String s = outputRoundQuotient(weight / divisor, sp) + "";637 if (weight / divisor < sp.s(rd − 1) || weight / divisor > sp.s(rd))

    s += ".";639 return s;

    }641

    public static Signpost getSignpost(MethodData d)643 {

    Signpost sp = null;645 try

    {647 if (d.method == MethodData.RSTATION)

    {649 if (d.paramString != null)

    {651 sp = new ExtendedStationary(d.paramString);

    }653 else

    {655 sp = new Stationary(d.param);

    }

    29

  • 657}

    659 else if (d.method == MethodData.PMEAN){

    661 if (d.paramString != null){

    663 sp = new ExtendedPowerMean(d.paramString);}

    665 else{

    667 sp = new PowerMean(d.param);}

    669 }else

    671 sp = new Stationary(0.5);}

    673 catch (ParameterOutOfRangeException ooREx){}

    675return sp;

    677 }

    679 private static class RString{

    681public final String value;

    683public RString(String value)

    685 {while (value.startsWith("0"))

    687 value = value.substring(1);if (value.indexOf(".") == −1)

    689 value += ".0";else

    691 while (value.endsWith("0"))value = value.substring(0, value.length() − 1);

    693 if (value.indexOf(".") == value.length() − 1)value += "0";

    695 if (value.indexOf(".") == 0)value = "0" + value;

    697 this.value = value;}

    699public RString(double value)

    701 {this(new BigDecimal(value).toString());

    703 }

    705 public RString(char[] value){

    707 this(new String(value));}

    709private int pre()

    711 {return value.indexOf(".");

    713 }

    30

  • 715 private int post(){

    717 return value.length() − value.indexOf(".") − 1;}

    719private String normalize(int pre, int post)

    721 {String out = value;

    723 for (int i = 0; i < pre − pre(); i++)out = "0" + out;

    725 for (int i = 0; i < post − post(); i++)out += "0";

    727 return out.replace(".", "");}

    729public int compare(RString o)

    731 {int pre = Math.max(pre(), o.pre());

    733 int post = Math.max(post(), o.post());String s0 = normalize(pre, post), s1 = o.normalize(pre, post);

    735for (int i = 0; i < s0.length(); i++)

    737 {int diff = s0.charAt(i) − s1.charAt(i);

    739 if (diff < 0)return −1;

    741 if (diff > 0)return 1;

    743 }return 0;

    745 }

    747 public boolean equals(RString o){

    749 return compare(o) == 0;}

    751public RString round(int digits)

    753 {if (post() '4')

    761 {int i = digits;

    763 if (i == 0)i = −1;

    765 while (out[p + i] == '9'){

    767 out[p + i] = '0';i−−;

    769 if (i == 0)i = −1;

    31

  • 771 if (p + i < 0){

    773 out = ("0" + new String(out)).toCharArray();i++;

    775 }}

    777 out[p + i]++;}

    779 return new RString(out);}

    781public RString floor(int digits)

    783 {if (value.indexOf(".") + digits + 1 < value.length())

    785 return new RString(value.substring(0, value.indexOf(".") + digits+ 1));

    return this;787 }

    789 public RString ceil(int digits){

    791 char[] temp = value.toCharArray();if (value.indexOf(".") + digits + 1 < value.length())

    793 temp[value.indexOf(".") + digits + 1] = '9';return new RString(temp).round(digits);

    795 }

    797 public RString rest(){

    799 return new RString(value.substring(value.indexOf(".")));}

    801public double toDouble()

    803 {return Double.parseDouble(value);

    805 }

    807 @Overridepublic String toString()

    809 {return value;

    811 }

    813 public String pad(int digits){

    815 String s = value;for (int i = 0; i < digits − post(); i++)

    817 s += "0";return s;

    819 }

    821 public String without0(){

    823 if (value.startsWith("0"))return value.substring(1);

    825 return value;}

    32

  • 827public RString withRest(RString rest)

    829 {String s0 = value.substring(0, pre());

    831 String s1 = rest.toString();s1 = s1.substring(Math.min(rest.pre() + 1, s1.length()));

    833 return new RString(s0 + "." + s1);}

    835 }

    837 public static String[] getQuotientenspalteOR(Weight[] wa, double quota,MethodData d, AbstractInputData data)

    {839 boolean WTA = isWTA(d);

    boolean gR1 = !WTA && isGR1(d);841 RString one = new RString(1);

    843 String[] out = new String[wa.length + 3];out[0] = Resource.getString("bazi.gui.output.quotient");

    845RString[] q = new RString[wa.length];

    847 for (int i = 0; i < wa.length; i++)q[i] = new RString(wa[i].weight / quota);

    849 if (q.length == 1)q[0] = new RString(wa[0].rdWeight);

    851RString nice;

    853 if (WTA)nice = one;

    855 elsenice = getSplit(wa, quota, gR1);

    857int niceDigits = 3;

    859 for (int i = 0; i < wa.length; i++)if (wa[i].multiple.isEmpty())

    861 {RString rest = q[i].rest();

    863 int correct = rest.compare(nice);while (rest.compare(nice.round(niceDigits)) != correct)

    865 niceDigits++;}

    867 nice = nice.round(niceDigits);

    869 for (int i = 0; i < wa.length; i++){

    871 String base = data.BMM ? data.base + RoundFrame.BASE_SEPERATOR : "";RString rest = q[i].rest(), round;

    873if (WTA || (gR1 && q[i].compare(one) < 0))

    875 {int digits = 3;

    877 do{

    879 round = rest.round(digits);digits++;

    881 }while (round.equals(one));

    33

  • 883 round = q[i].withRest(round);}

    885 else if (!wa[i].multiple.isEmpty()){

    887 round = q[i].withRest(nice);}

    889 else{

    891 int digits = 3, correct = rest.compare(nice);do

    893 {round = rest.round(digits);

    895 digits++;}

    897 while (round.compare(nice) != correct || round.equals(one));round = q[i].withRest(round);

    899 }out[i + 1] = base + round.pad(3);

    901if (gR1 && q[i].compare(one) < 0)

    903 out[i + 1] += ".";else

    905 {RString min = new RString(wa[i].min), max = new RString(wa[i].max

    ), seats = q[i].floor(0);907 if (seats.compare(min) < 0 || seats.compare(max) >= 0)

    out[i + 1] += ".";909 }

    }911

    if (WTA)913 out[wa.length + 1] = "(NA)";

    else915 {

    String s = nice + "";917 s = s.substring(s.indexOf("."));

    out[wa.length + 1] = String.format("(%s)", s);919 }

    921 out[wa.length + 2] = "";return out;

    923 }

    925 public static boolean isWTA(MethodData d){

    927 double method = d.param;return Method.isMethod(method, Method.DROOPQUOTE_VAR02)

    929 || Method.isMethod(method, Method.DROOPQUOTE_VAR12)|| Method.isMethod(method, Method.DROOPQUOTE_VAR22)

    931 || Method.isMethod(method, Method.DROOPQUOTE_VAR32)|| Method.isMethod(method, Method.HAREQUOTE_VAR02)

    933 || Method.isMethod(method, Method.HAREQUOTE_VAR12)|| Method.isMethod(method, Method.HAREQUOTE_VAR22);

    935 }

    937 public static boolean isGR1(MethodData d){

    34

  • 939 double method = d.param;return Method.isMethod(method, Method.DROOPQUOTE_VAR01)

    941 || Method.isMethod(method, Method.DROOPQUOTE_VAR11)|| Method.isMethod(method, Method.DROOPQUOTE_VAR21)

    943 || Method.isMethod(method, Method.DROOPQUOTE_VAR31)|| Method.isMethod(method, Method.HAREQUOTE_VAR01)

    945 || Method.isMethod(method, Method.HAREQUOTE_VAR11)|| Method.isMethod(method, Method.HAREQUOTE_VAR21);

    947 }

    949 public static RString getSplit(Weight[] wa, double quota, boolean gR1){

    951 RString[] iv = getSplitInterval(wa, quota, gR1);RString low = iv[0], high = iv[1];

    953 RString mid = new RString(0.5);

    955 if (low.compare(mid) < 0 && high.compare(mid) > 0)return mid;

    957 else{

    959 Divisor div = new Divisor();try

    961 {div.setDivisorInterval(low.toDouble(), high.toDouble());

    963 return new RString(div.getDivisor());}

    965 catch (DivisorException e){}

    967 return low;}

    969 }

    971 public static String getSplitString(Weight[] wa, double quota, MethodData d){

    973 if (isWTA(d))return "NA";

    975 return String.format("%s", getSplit(wa, quota, isGR1(d)).round(3).without0());

    }977

    public static RString[] getSplitInterval(Weight[] wa, double quota, booleangR1)

    979 {RString low = new RString(0), high = new RString(1);

    981 RString n = new RString(0);

    983 for (Weight w : wa){

    985 RString q = new RString(w.weight / quota);RString seats = q.floor(0);

    987 RString rest = q.rest();RString min = new RString(w.min), max = new RString(w.max);

    989 RString rdWeight = new RString(w.rdWeight);

    991 if (gR1 && seats.equals(n))continue;

    35

  • 993 if (seats.equals(rdWeight) && max.compare(rdWeight) > 0 && low.compare(rest) < 0)low = rest;

    995 if (seats.compare(rdWeight) < 0 && min.compare(rdWeight) < 0 && high.compare(rest) > 0)high = rest;

    997 }if (low.compare(high) > 0)

    999 low = high;return new RString[] { low, high };

    1001 }

    1003 public static String getSplitIntervalString(Weight[] wa, double quota,MethodData d)

    {1005 if (isWTA(d))

    return "NA";1007 RString[] iv = getSplitInterval(wa, quota, isGR1(d));

    RString low = iv[0], high = iv[1], rLow, rHigh;1009 if (low.equals(high))

    return String.format("[%s;%s]", low.round(3).without0(), high.round(3).without0());

    1011 int digits = 3;do

    1013 {rLow = low.ceil(digits);

    1015 rHigh = high.floor(digits);digits++;

    1017 }while (rLow.compare(rHigh) >= 0);

    1019 return String.format("[%s;%s]", rLow.without0(), rHigh.without0());}

    1021private static String outputRoundQuotient(double q, Signpost sp)

    1023 {double s1 = sp.s((int) q − 1), s2 = sp.s((int) q), s3 = sp.s((int) q + 1)

    ;1025 int stellen = 1;

    double faktor = 10.0;1027 double x = q − (int) q;

    int max = Double.toString(x).length() − 1;1029 double gerundet = 0;

    1031 while (stellen

  • }

    Listing 4: Class Calculation (modified entry point of BAZI)

    3.2 BAZI-RPC3.2.1 Package ch.zh.baziinternet.input

    Interface InputData

    /*2 * This file is part of the source code of the BAZI−RPC web service.

    * The BAZI−RPC web service is an API which allows to access BAZI4 * (see www.uni−augsburg.de/bazi/) by web applications.

    *6 * BAZI−RPC is free software: you can redistribute it and/or modify

    * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or

    * (at your option) any later version.10 *

    * BAZI−RPC is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.

    16 * You should have received a copy of the GNU General Public License

    * along with BAZI−RPC. If not, see .18 *

    */20

    package ch.zh.baziinternet.input;22

    24 /*** This interface specifies the methods provided by input data objects.

    26 ** @author Statistical Office of the Canton of Zurich

    28 * @version 1.0

    */30 public interface InputData

    32 {

    34 /*** Returns the number of mandates of a certain district.

    36 * @param wk Number of the district of interest.

    * @return Number of mandates of a certain district.38 */

    public Integer get_mandates(Integer wk);40

    /**42 * Returns the number of votes of a party in a certain district.

    * @param wk Number of the district.

    37

  • 44 * @param lg Number of the party.

    * @return Number of votes of a party in a certain district.46 * */

    public Integer get_votes(Integer wk,Integer lg);48

    /**50 * Returns the lowest district number.

    * @return Lowest district number.52 */

    public Integer get_min_wk();54

    /**56 * Returns the lowest party number.

    * @return Lowest district number.58 */

    public Integer get_min_lg();60

    /**62 * Returns the highest district number.

    * @return Highest district number.64 */

    public Integer get_max_wk();66

    /**68 * Returns the highest party number.

    * @return Highest party number.70 */

    public Integer get_max_lg();72

    74 }

    Listing 5: Interface InputData

    Class InputData_Historical

    /*2 * This file is part of the source code of the BAZI−RPC web service.

    * The BAZI−RPC web service is an API which allows to access BAZI4 * (see www.uni−augsburg.de/bazi/) by web applications.

    *6 * BAZI−RPC is free software: you can redistribute it and/or modify

    * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or

    * (at your option) any later version.10 *

    * BAZI−RPC is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.

    16 * You should have received a copy of the GNU General Public License

    * along with BAZI−RPC. If not, see .18 *

    38

  • */20 package ch.zh.baziinternet.input;

    22 import java.io.*;import java.util.*;

    24

    26 /*** This class is used to construct input data objects containing data of a past

    election.28 *

    * @author Statistical Office of the Canton of Zurich30 * @version 1.0

    *32 */

    public class InputData_Historical implements InputData34

    {36

    /** Number of mandates of every district. */38 private final HashMap hashmap_mandates = new HashMap<

    Integer,Integer>();

    40 /*** Number of votes per district and party.

    42 * Number of votes is assigned to every "wk:lg"−pair.*/

    44 private final HashMap hashmap_votes = new HashMap();

    46 /** Lowest district number. */private final Integer min_wk;

    48 /** Lowest party number. */private final Integer min_lg;

    50 /** Highest district number. */private final Integer max_wk;

    52 /** Highest party number. */private final Integer max_lg;

    54

    56 /** {@inheritDoc} */public Integer get_mandates(Integer wk) {return this.

    hashmap_mandates.get(wk);}58

    /** {@inheritDoc} */60 public Integer get_votes(Integer wk,Integer lg) {return this.

    hashmap_votes.get(wk.toString()+":"+lg.toString());}

    62 /** {@inheritDoc} */public Integer get_min_wk() {return this.min_wk;}

    64/** {@inheritDoc} */

    66 public Integer get_min_lg() {return this.min_lg;}

    68 /** {@inheritDoc} */public Integer get_max_wk() {return this.max_wk;}

    70

    39

  • /** {@inheritDoc} */72 public Integer get_max_lg() {return this.max_lg;}

    74/**

    76 * Constructs an input data object containing data of a past election.

    * @param file BAZI input file.78 */

    public InputData_Historical(String file)80 {

    82 try{

    84FileReader in = new FileReader(file);

    86 BufferedReader br = new BufferedReader(in);

    88 String line;Integer wk = −1;

    90 Integer mandate = −1;while ((line=br.readLine()) != null)

    92 {

    94 if (line.contains("DISTRIKT=")){

    96wk = convert(line.split("=")[2].trim());

    98mandate = Integer.valueOf(br.readLine().replace("=MANDATE=","

    ").trim());100 this.hashmap_mandates.put(wk,mandate);

    }102

    if (line.contains("\""))104 {

    106 int start = line.indexOf("\"");int liste = Integer.valueOf(line.substring(start+1,start+3)

    );108 int stimmen = Integer.valueOf(line.split("\"")[2].trim());

    110 this.hashmap_votes.put(wk+":"+liste,stimmen);

    112

    114 }

    116}

    118 in.close();}

    120 catch(Exception e){

    122 e.printStackTrace();}

    124

    40

  • 126 //Herausfinden der MaximalwerteArrayList keys = new ArrayList(hashmap_votes.keySet

    ());128 ArrayList wks = new ArrayList();

    ArrayList lgs = new ArrayList();130

    132 for(int i=0;i

  • 182 return r;

    184 }

    186 }

    Listing 6: Class InputData_Historical

    Class InputData_JSON_RPC

    /*2 * This file is part of the source code of the BAZI−RPC web service.

    * The BAZI−RPC web service is an API which allows to access BAZI4 * (see www.uni−augsburg.de/bazi/) by web applications.

    *6 * BAZI−RPC is free software: you can redistribute it and/or modify

    * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or

    * (at your option) any later version.10 *

    * BAZI−RPC is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.

    16 * You should have received a copy of the GNU General Public License

    * along with BAZI−RPC. If not, see .18 *

    */20

    package ch.zh.baziinternet.input;22

    import java.util.*;24

    26 /*** This class is used to construct input data objects for JSON−RPC requests.

    28 ** @author Statistical Office of the Canton of Zurich

    30 * @version 1.0

    */32 public class InputData_JSON_RPC implements InputData

    34 {

    36 /** Number of mandates of every district. */private final HashMap mandates = new HashMap();38

    /**40 * Number of votes per district and party.

    * Number of votes is assigned to every "wk:lg"−pair.42 */

    42

  • private final HashMap votes = new HashMap();

    44/** Lowest district number. */

    46 private final Integer min_wk;/** Lowest party number. */

    48 private final Integer min_lg;/** Highest district number. */

    50 private final Integer max_wk;/** Highest party number. */

    52 private final Integer max_lg;

    54/**

    56 * Constructs an input data object with data from a JSON−RPC request.* @param params Parameters from JSON−RPC request.

    58 */public InputData_JSON_RPC(HashMap params)

    60{

    62//Abfuellung der Werte

    64 Integer wk_startwert = 0;Integer lg_startwert = 0;

    66 boolean startwert_wurde_bestimmt = false;

    68 Iterator iterator = params.keySet().iterator();while (iterator.hasNext())

    70 {String paramName = iterator.next();

    72 String paramValue = params.get(paramName);

    74 boolean contains_mandate = paramName.contains("wk") && paramName.contains("mandates");

    boolean contains_wk = paramName.contains("wk");76 boolean contains_lg = paramName.contains("lg");

    78 if (contains_mandate){

    80 try{

    82 Integer wk = Integer.valueOf(paramName.replace("wk","").replace("mandates","").trim());

    Integer mandate = Integer.valueOf(paramValue);84 this.mandates.put(wk,mandate);

    }86 catch(NumberFormatException e)

    {88 //Um das Logfile nicht zu fuellen, sollte hier keineswegs

    eine Ausgabe erfolgen,//da die NumberFormatException sehr haeufig auftritt.

    Naemlich immer dann, wenn90 //unausgefuellte Felder uebergeben werden.

    }92

    }94 else if (contains_wk && contains_lg)

    43

  • {96 int index_of_lg = paramName.indexOf("lg");

    98 try{

    100 Integer wk = Integer.valueOf(paramName.substring(0,index_of_lg).replace("wk",""));

    Integer lg = Integer.valueOf(paramName.substring(index_of_lg).replace("lg",""));

    102if (!startwert_wurde_bestimmt)

    104 {wk_startwert = wk;

    106 lg_startwert = lg;startwert_wurde_bestimmt = true;

    108 }

    110 Integer stimmen = Integer.valueOf(paramValue);String id = wk.toString()+":"+lg.toString();

    112 this.votes.put(id,stimmen);}

    114 catch(NumberFormatException e){

    116 //Um das Logfile nicht zu fuellen, sollte hier keineswegseine Ausgabe erfolgen,

    //da die NumberFormatException sehr haeufig auftritt.Naemlich immer dann, wenn

    118 //unausgefuellte Felder uebergeben werden.}

    120}

    122 }

    124//Bestimmung der Maximalwerte

    126if (startwert_wurde_bestimmt)

    128 {Integer min_wk = wk_startwert;

    130 Integer min_lg = lg_startwert;Integer max_wk = wk_startwert;

    132 Integer max_lg = lg_startwert;

    134 Iterator it = votes.entrySet().iterator();while (it.hasNext())

    136 {Map.Entry pair = it.next();

    138 String id = pair.getKey();

    140 String[] split = id.split(":");Integer wk = Integer.valueOf(split[0]);

    142 Integer lg = Integer.valueOf(split[1]);

    144 if (wk.compareTo(min_wk)0) {max_lg = lg;}

    44

  • 148 }

    150 this.min_wk = min_wk;this.min_lg = min_lg;

    152 this.max_wk = max_wk;this.max_lg = max_lg;

    154 }else

    156 {this.min_wk = null;

    158 this.min_lg = null;this.max_wk = null;

    160 this.max_lg = null;}

    162}

    164/** {@inheritDoc} */

    166 public Integer get_mandates(Integer wk){

    168 return this.mandates.get(wk);}

    170/** {@inheritDoc} */

    172 public Integer get_votes(Integer wk,Integer lg){

    174 Integer rueckgabewert = 0;String id = wk.toString()+":"+lg.toString();

    176if (this.votes.get(id)!=null)

    178 {rueckgabewert = this.votes.get(id);

    180 }else

    182 {rueckgabewert = null;

    184 }

    186 return rueckgabewert;}

    188/** {@inheritDoc} */

    190 public Integer get_min_wk() {return this.min_wk;}

    192 /** {@inheritDoc} */public Integer get_min_lg() {return this.min_lg;}

    194/** {@inheritDoc} */

    196 public Integer get_max_wk() {return this.max_wk;}

    198 /** {@inheritDoc} */public Integer get_max_lg() {return this.max_lg;}

    200}

    Listing 7: Class InputData_JSON_RPC

    45

  • Class InputData_Normal

    1 /** This file is part of the source code of the BAZI−RPC web service.

    3 * The BAZI−RPC web service is an API which allows to access BAZI* (see www.uni−augsburg.de/bazi/) by web applications.

    5 ** BAZI−RPC is free software: you can redistribute it and/or modify

    7 * it under the terms of the GNU General Public License as published by

    * the Free Software Foundation, either version 3 of the License, or9 * (at your option) any later version.

    *11 * BAZI−RPC is distributed in the hope that it will be useful,

    * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    * GNU General Public License for more details.15

    * You should have received a copy of the GNU General Public License17 * along with BAZI−RPC. If not, see .

    *19 */

    21 package ch.zh.baziinternet.input;

    23 import java.util.*;import javax.servlet.http.HttpServletRequest;

    25/**

    27 * This class is used to construct input data objects for HTML requests.

    *29 * @author Statistical Office of the Canton of Zurich

    * @version 1.031 */

    public class InputData_Normal implements InputData33

    {35

    /** Number of mandates of every district. */37 private final HashMap mandates = new HashMap();

    39 /*** Number of votes per district and party.

    41 * Number of votes is assigned to every "wk:lg"−pair.*/

    43 private final HashMap votes = new HashMap();

    45 /** Lowest district number. */private final Integer min_wk;

    47/** Lowest party number. */

    49 private final Integer min_lg;

    51 /** Highest district number. */private final Integer max_wk;

    46

  • 53/** Highest party number. */

    55 private final Integer max_lg;

    57

    59 /*** Constructs an input data object with data from a HTML request.

    61 * @param req Servlet request object.

    */63 public InputData_Normal(HttpServletRequest req)

    65 {

    67 @SuppressWarnings("unchecked")Enumeration parameterNames = req.getParameterNames();

    69//Abfuellung der Werte

    71 Integer wk_startwert = 0;Integer lg_startwert = 0;

    73 boolean startwert_wurde_bestimmt = false;

    75 while (parameterNames.hasMoreElements()){

    77String paramName = parameterNames.nextElement();

    79 String paramValue = req.getParameter(paramName);

    81 boolean contains_mandate = paramName.contains("wk") && paramName.contains("mandates");

    boolean contains_wk = paramName.contains("wk");83 boolean contains_lg = paramName.contains("lg");

    85 if (contains_mandate){

    87 try{

    89 Integer wk = Integer.valueOf(paramName.replace("wk","").replace("mandates","").trim());

    Integer mandate = Integer.valueOf(paramValue);91 this.mandates.put(wk,mandate);

    }93 catch(NumberFormatException e)

    {95 //Um das Logfile nicht zu fuellen, sollte hier keineswegs

    eine Ausgabe erfolgen,//da die NumberFormatException sehr haeufig auftritt.

    Naemlich immer dann, wenn97 //unausgefuellte Felder uebergeben werden.

    }99

    }101 else if (contains_wk && contains_lg)

    {103 int index_of_lg = paramName.indexOf("lg");

    105 try

    47

  • {107 Integer wk = Integer.valueOf(paramName.substring(0,

    index_of_lg).replace("wk",""));Integer lg = Integer.valueOf(paramName.substring(index_of_lg)

    .replace("lg",""));109

    if (!startwert_wurde_bestimmt)111 {

    wk_startwert = wk;113 lg_startwert = lg;

    startwert_wurde_bestimmt = true;115 }

    117 Integer stimmen = Integer.valueOf(paramValue);String id = wk.toString()+":"+lg.toString();

    119 this.votes.put(id,stimmen);}

    121 catch(NumberFormatException e){

    123 //Um das Logfile nicht zu fuellen, sollte hier keineswegseine Ausgabe erfolgen,

    //da die NumberFormatException sehr haeufig auftritt.Naemlich immer dann, wenn

    125 //unausgefuellte Felder uebergeben werden.}

    127}

    129 }

    131//Bestimmung der Maximalwerte

    133if (startwert_wurde_bestimmt)

    135 {Integer min_wk = wk_startwert;

    137 Integer min_lg = lg_startwert;Integer max_wk = wk_startwert;

    139 Integer max_lg = lg_startwert;

    141 Iterator it = this.votes.entrySet().iterator();

    while (it.hasNext())143 {

    Map.Entry pair = it.next();145 String id = pair.getKey();

    147 String[] split = id.split(":");Integer wk = Integer.valueOf(split[0]);

    149 Integer lg = Integer.valueOf(split[1]);

    151 if (wk.compareTo(min_wk)0) {max_lg = lg;}

    155 }

    157 this.min_wk = min_wk;

    48

  • this.min_lg = min_lg;159 this.max_wk = max_wk;

    this.max_lg = max_lg;161 }

    else163 {

    this.min_wk = null;165 this.min_lg = null;

    this.max_wk = null;167 this.max_lg = null;

    }169 }

    171 /** {@inheritDoc} */public Integer get_mandates(Integer wk)

    173 {return this.mandates.get(wk);

    175 }

    177 /** {@inheritDoc} */public Integer get_votes(Integer wk,Integer lg)

    179 {Integer rueckgabewert = 0;

    181 String id = wk.toString()+":"+lg.toString();

    183 if (this.votes.get(id)!=null){

    185 rueckgabewert = this.votes.get(id);}

    187 else{

    189 rueckgabewert = null;}

    191return rueckgabewert;

    193 }

    195 /** {@inheritDoc} */public Integer get_min_wk() {return this.min_wk;}

    197/** {@inheritDoc} */

    199 public Integer get_min_lg() {return this.min_lg;}

    201 /** {@inheritDoc} */public Integer get_max_wk() {return this.max_wk;}

    203/** {@inheritDoc} */

    205 public Integer get_max_lg() {return this.max_lg;}

    207 }

    Listing 8: Class InputData_Normal

    49

  • 3.2.2 Package ch.zh.baziinternet.iobazi

    Class ApportionmentSub_ColumnTitles

    1 /** This file is part of the source code of the BAZI−RPC web service.

    3 * The BAZI−RPC web service is an API which allows to access BAZI* (see www.uni−augsburg.de/bazi/) by web applications.

    5 ** BAZI−RPC is free software: you can redistribute it and/or modify

    7 * it under the terms of the GNU General Public License as published by

    * the Free Software Foundation, either version 3 of the License, or9 * (at your option) any later version.

    *11 * BAZI−RPC is distributed in the hope that it will be useful,

    * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    * GNU General Public License for more details.15

    * You should have received a copy of the GNU General Public License17 * along with BAZI−RPC. If not, see .

    *19 */

    21 package ch.zh.baziinternet.iobazi;

    23 import java.util.*;

    25 /*** This class is used to fill up the hashmap which assigns to every column number

    its title.27 *

    * @author Statistical Office of the Canton of Zurich29 * @version 1.0

    */31 public class ApportionmentSub_ColumnTitles

    33 {

    35 /*** Fills up the hashmap which assigns to every column number its title:

    37 *

    * 0 → "Listengruppe"39 * 1 → "Total"

    * 2 → "\"wk1\""41 * 3 → "DivStd"

    * ...43 *

    * Invisible columns (due to whitespace characters) are not taken intoaccount,

    45 * i.e. the column numbers are determined in the following way:

    * 47 * COL0 COL1 COL2 COL3

    * "wk1" DivStd49 * 180 4

    * "lg1" 54 5254 1

    50

  • 51 * "lg2" 36 7936 1

    * "lg3" 31 6627 153 * "lg4" 13 3558 1

    * "lg5" 14 2594 055 * ....

    * Divisor 600057 *

    *59 * @param column_titles The hashmap which should be filled up.

    * @param line The line which contains the column titles.61 */

    protected static void fillup(HashMap column_titles,Stringline)

    63 {

    65 //Die Datenlinien beginnen schon zwei Spalten vorher.column_titles.put(0,"Listengruppe");

    67 column_titles.put(1,"Totale");

    69 String[] spalten = line.split("\\s+");

    71 //Um nur die wirklichen sichtbaren Spalten zu beruecksichtigen,//werden in der nachfolgenden Liste nicht−relevante Spalten

    73 //nicht beruecksichtigt.ArrayList spalten_liste = new ArrayList();

    75spalten_liste.add("Listengruppe");

    77 spalten_liste.add("Totale");for(int i=0;i0) //Die erste Spalte ist eine unsichtbare Spalte und wird

    nicht beruecksichtigt.81 {

    spalten_liste.add(spalten[i]);83 }

    85 }

    87 //Abfuellung der HashMapfor(int i=0;i

  • /*2 * This file is part of the source code of the BAZI−RPC web service.

    * The BAZI−RPC web service is an API which allows to access BAZI4 * (see www.uni−augsburg.de/bazi/) by web applications.

    *6 * BAZI−RPC is free software: you can redistribute it and/or modify

    * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or

    * (at your option) any later version.10 *

    * BAZI−RPC is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.

    16 * You should have received a copy of the GNU General Public License

    * along with BAZI−RPC. If not, see .18 *

    */20

    package ch.zh.baziinternet.iobazi;22

    import java.util.*;24

    26 /*** This class is used to fill up the hashmap which assigns to every pair "wk:lg"

    the corresponding number of seats.28 *

    * @author Statistical Office of the Canton of Zurich30 * @version 1.0

    */32 public class ApportionmentSub_Votes_Seats_LGDivisors

    34 {

    36 /*** Fills up the hashmap which assigns to every pair "wk:lg" the corresponding

    number of seats:
    38 *

    * "1:1" → 140 * "2:1" → 2

    * "3:1" → 042 * "4:1" → 2

    * "5:1" → 144 * ...

    * 46 *

    * In order to achieve correct assignments, the following should beremembered:

    48 * Invisible columns (due to whitespace characters) are not taken intoaccount,

    * i.e. the column numbers are determined in the following way:50 *

    * COL0 COL1 COL2 COL352 * "wk1" DivStd

    * 180 4

    52

  • 54 * "lg1" 54 5254 1

    * "lg2" 36 7936 156 * "lg3" 31 6627 1

    * "lg4" 13 3558 158 * "lg5" 14 2594 0

    * ....60 * Divisor 6000

    *62 *

    *64 * @param column_titles Column titles.

    * @param votes Numbers of votes to be filled up.66 * @param seats Numbers of seats to be filled up.

    * @param lg_divisors Party divisors to be filled up.68 * @param line The line which contains the column titles.

    */70 protected static void fillup

    (72 HashMap column_titles,

    HashMap votes,74 HashMap seats,

    HashMap lg_divisors,76 String line

    )78 {

    //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−//80 // Extraktion der Listengruppe //

    //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−//82 int start = line.indexOf("lg")+2;

    int i=start;84 while (true)

    {86 if (line.charAt(i)=='"')

    {88 break;

    }90 i++;

    }92 int ende = i;

    94 String lg = line.substring(start,ende);

    96 //−−−−−−−−−−−−−−−−−−−−−−//// Abfuellung der Sitze //

    98 //−−−−−−−−−−−−−−−−−−−−−−//String[] spalten = line.split("\\s+");

    100 for(int j=0;j

  • 108 String number_of_voters = spalten[j]; //Herausfinden derAnzahl Sitze

    votes.put(wk+":"+lg,number_of_voters); //Abspeichern derAnzahl Sitze in der HashMap

    110String number_of_seats = spalten[j+1]; //Herausfinden der

    Anzahl Sitze112 seats.put(wk+":"+lg,number_of_seats); //Abspeichern der

    Anzahl Sitze in der HashMap

    114 }

    116 }

    118 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−//// Abfuellung der LG−Divisoren //

    120 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−//String lg_divisor = spalten[spalten.length−1];

    122 lg_divisors.put(lg,lg_divisor);

    124 }

    126}

    Listing 10: Class ApportionmentSub_Votes_Seats_LGDivisors

    Class ApportionmentSub_WKDivisors

    1 /** This file is part of the source code of the BAZI−RPC web service.

    3 * The BAZI−RPC web service is an API which allows to access BAZI* (see www.uni−augsburg.de/bazi/) by web applications.

    5 ** BAZI−RPC is free software: you can redistribute it and/or modify

    7 * it under the terms of the GNU General Public License as published by

    * the Free Software Foundation, either version 3 of the License, or9 * (at your option) any later version.

    *11 * BAZI−RPC is distributed in the hope that it will be useful,

    * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    * GNU General Public License for more details.15

    * You should have received a copy of the GNU General Public License17 * along with BAZI−RPC. If not, see .

    *19 */

    package ch.zh.baziinternet.iobazi;21

    import java.util.*;23

    /**

    54

  • 25 * This class is used to fill up the hashmap which assigns to every wk itsdivisor.

    *27 * @author Statistical Office of the Canton of Zurich

    * @version 1.029 */

    public class ApportionmentSub_WKDivisors31

    {33

    /**35 * Fills up the hashmap which assigns to every wk its divisor:

    * 37 * 1 → 6000

    * 2 → 1600039 * 3 → 6120

    * ...41 *

    * In order to achieve correct assignments, the following should beremembered:

    43 * Invisible columns (due to whitespace characters) are not taken intoaccount,

    * i.e. the column numbers are determined in the following way:45 *

    * COL0 COL1 COL2 COL347 * "wk1" DivStd

    * 180 449 * "lg1" 54 5254 1

    * "lg2" 36 7936 151 * "lg3" 31 6627 1

    * "lg4" 13 3558 153 * "lg5" 14 2594 0

    * ....55 * Divisor 6000

    * 57 * @param column_titles The hashmap with the column titles.

    * @param wk_divisors The hashmap which should be filled up.59 * @param line The line which contains the column titles.

    */61

    protected static void fillup63 (

    HashMap column_titles,65 HashMap wk_divisors,

    String line67 )

    69 {

    71 //SitzeString[] spalten = line.split("\\s+");

    73//Um Uebereinstimmung mit den Spalten−Nummern der Titelzeile zu erreichen

    ,75 //werden nachfolgend leere Spalten eingefuellt.

    ArrayList spalten_liste = new ArrayList();77 for(int j=0;j

  • {79 spalten_liste.add(spalten[j]);

    if (spalten[j].equals("Divisor"))81 {

    //Nach der Divisor−Spalte kommen zwei sichtbare Spalten ohneWerte.

    83 spalten_liste.add("leere Spalte");spalten_liste.add("leere Spalte");

    85 }else

    87 {//Nach jeder DivStd−Spalte kommt eine sichtbare Spalte ohne Wert.

    89 spalten_liste.add("leere Spalte");}

    91 }

    93 //Abfuellung der HashMapfor(int j=0;j

  • */20 package ch.zh.baziinternet.iobazi;

    22 import java.util.ArrayList;import java.util.HashMap;

    24/**

    26 * This class is used to construct sub−apportionment objects.*

    28 * @author Statistical Office of the Canton of Zurich

    * @version 1.030 */

    public class ApportionmentSub32

    {34

    /** Column titles from the BAZI output. */36 private final HashMap column_titles = new HashMap();

    38 /** Number of votes for every "wk:lg"−pair from the BAZI output. */private final HashMap votes = new HashMap();40

    /** Number of seats for every "wk:lg"−pair from the BAZI output. */42 private final HashMap seats = new HashMap();

    44 /** LG−Divisors (i.e. party divisors) from the BAZI output. */private final HashMap lg_divisors = new HashMap();46

    /** WK−Divisors (i.e. district divisors) from the BAZI output. */48 private final HashMap wk_divisors = new HashMap();

    50 /*** Returns the number of votes of a party in a certain district.

    52 * @param wk Number of the district.

    * @param lg Number of the party.54 * @return Number of votes of a party in a certain district.

    * */56 public String get_votes(Integer wk,Integer lg) {return this.votes.get(wk

    +":"+lg);}

    58 /*** Returns the number of seats of a party in a certain district.

    60 * @param wk Number of the district.

    * @param lg Number of the party.62 * @return Number of seats of a party in a certain district.

    * */64 public String get_seats(Integer wk,Integer lg) {return this.seats.get(wk

    +":"+lg);}

    66 /*** Returns the party divisor of a certain party.

    68 * @param lg Number of the party.

    57

  • * @return Party divisor.70 * */

    public String get_lg_divisor(Integer lg) {return this.lg_divisors.get(lg.toString());}

    72/**

    74 * Returns the district divisor of a certain district.

    * @param wk Number of the district.76 * @return District divisor.

    * */78 public String get_wk_divisor(Integer wk) {return this.wk_divisors.

    get(wk.toString());}

    80/**

    82 * Constructs a sub−apportionment object.* @param lines Lines of the BAZI Output.

    84 */protected ApportionmentSub(ArrayList lines)

    86 {

    88 boolean scanning_activated = false;for(int i=0;i

  • }122

    124 }

    126 }

    128

    130}

    Listing 12: Class ApportionmentSub

    Class ApportionmentSuper

    1 /** This file is part of the source code of the BAZI−RPC web service.

    3 * The BAZI−RPC web service is an API which allows to access BAZI* (see www.uni−augsburg.de/bazi/) by web applications.

    5 ** BAZI−RPC is free software: you can redistribute it and/or modify

    7 * it under the terms of the GNU General Public License as published by

    * the Free Software Foundation, either version 3 of the License, or9 * (at your option) any later version.

    *11 * BAZI−RPC is distributed in the hope that it will be useful,

    * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    * GNU General Public License for more details.15

    * You should have received a copy of the GNU General Public License17 * along with BAZI−RPC. If not, see .

    *19 */

    21 package ch.zh.baziinternet.iobazi;

    23 import java.util.*;

    25 /*** This class is used to construct super−apportionment objects.

    27 ** @author Statistical Office of the Canton of Zurich

    29 * @version 1.0

    */31 public class ApportionmentSuper

    33 {

    35 /** Number of voters for every party. */private final HashMap voters = new HashMap();37

    59

  • /** Number of seats for every party. */39 private final HashMap seats = new HashMap();

    41 /** Total number of seats. */private final String sum_seats;

    43/** Total number of voters. */

    45 private final String sum_voters;

    47 /** Divisor for finding the super−apportionment. */private final String divisor;

    49/**

    51 * Returns the number of voters of a certain party.

    *53 * @param lg Number of the party of interest.

    * @return Number of voters.55 */

    public String get_voters(Integer lg)57 {

    return this.voters.get(lg.toString());59 }

    61 /*** Returns the number of seats of a certain party.

    63 ** @param lg Number of the party of interest.

    65 * @return Number of seats.

    */67 public String get_seats(Integer lg)

    {69 return this.seats.get(lg.toString());

    }71

    /**73 * Returns the total number of voters.

    * @return Total number of voters.75 */

    public String get_sum_voters() {return this.sum_voters;}77

    79 /*** Returns the total number of seats.

    81 * @return Total number of seats.

    */83 public String get_sum_seats() {return this.sum_seats;}

    85/**

    87 * Returns the divisor used for getting the super−apportionment.*

    89 * @return The divisor used for getting the super−apportionment.*/

    91 public String get_divisor() {return this.divisor;}

    93

    60

  • /**95 * Constructs an super−apportionment object. *

    * @param lines BAZI output lines.97 */

    protected ApportionmentSuper(ArrayList lines)99

    {101 String sum_voters = "0";

    String sum_seats = "0";103 String divisor = "1";

    boolean scanning_activated = false;105 for(int i=0;i

  • Class BAZI_Input

    /*2 * This file is part of the source code of the BAZI−RPC web service.

    * The BAZI−RPC web service is an API which allows to access BAZI4 * (see www.uni−augsburg.de/bazi/) by web applications.

    *6 * BAZI−RPC is free software: you can redistribute it and/or modify

    * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or

    * (at your option) any later version.10 *

    * BAZI−RPC is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.

    16 * You should have received a copy of the GNU General Public License

    * along with BAZI−RPC. If not, see .18 *

    */20 package ch.zh.baziinternet.iobazi;

    22 import ch.zh.baziinternet.input.*;import ch.zh.baziinternet.request.*;

    24/**

    26 * This class is used for constructing BAZI input file content.

    *28 * @author Statistical Office of the Canton of Zurich

    * @version 1.030 */

    public class BAZI_