Bugzilla – Attachment 115062 Details for
Bug 20212
Improve performance of acquisitions receive page
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 20212: Use the DT column filtering provided by the wrapper
Bug-20212-Use-the-DT-column-filtering-provided-by-.patch (text/plain), 28.21 KB, created by
Jonathan Druart
on 2021-01-12 10:10:37 UTC
(
hide
)
Description:
Bug 20212: Use the DT column filtering provided by the wrapper
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2021-01-12 10:10:37 UTC
Size:
28.21 KB
patch
obsolete
>From 2522df93c714b65450714dea0757f8cce3667562 Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >Date: Mon, 11 Jan 2021 15:42:18 +0100 >Subject: [PATCH] Bug 20212: Use the DT column filtering provided by the > wrapper > >Bug 27402 is adding it, we do not longer need the query_from_filters JS >function. > >This patch also remove the filters on the left. As we have DT >remembering the filter on the table we don't need them anymore. > >Technical note: >Prior to this patch, the search on biblio.author, biblio.title and >biblio.isbn was done by adding hidden columns. Now we are using: > "data": "biblio.author:biblio.title:biblio.isbn" >to tell the wrapper we are going to build a search on these 3 >attributes. > >Another trick is to pass a default_filters parameters to the wrapper, to >tell it we want to filter on the orders of a given vendor (this is a >bugfix, the original implementation was returning all the orders). >However We should not use /acq/orders?vendor_id=42 but /acq/vendor/42/orders instead (which does not exist yet), >otherwise (with bug 27353 ) we are going to display the wrong number of non-filtering rows. > >The change in Orders.pm is only formatting to match what's done in > Bug 27353: Set X-Base-Total-Count header for REST API >--- > Koha/REST/V1/Acquisitions/Orders.pm | 20 +- > acqui/finishreceive.pl | 2 +- > acqui/parcel.pl | 20 -- > .../prog/en/modules/acqui/orderreceive.tt | 2 +- > .../prog/en/modules/acqui/parcel.tt | 251 ++---------------- > koha-tmpl/intranet-tmpl/prog/js/datatables.js | 46 +++- > 6 files changed, 68 insertions(+), 273 deletions(-) > >diff --git a/Koha/REST/V1/Acquisitions/Orders.pm b/Koha/REST/V1/Acquisitions/Orders.pm >index 4cb0fe982f..5419ce5c45 100644 >--- a/Koha/REST/V1/Acquisitions/Orders.pm >+++ b/Koha/REST/V1/Acquisitions/Orders.pm >@@ -143,19 +143,15 @@ sub list { > > # Perform search > my $orders = $orders_rs->search( $filtered_params, $attributes ); >+ my $total = $orders_rs->search->count; > >- if ($orders->is_paged) { >- $c->add_pagination_headers({ >- total => $orders->pager->total_entries, >- params => $args, >- }); >- } >- else { >- $c->add_pagination_headers({ >- total => $orders->count, >- params => $args, >- }); >- } >+ $c->add_pagination_headers( >+ { >+ total => ($orders->is_paged ? $orders->pager->total_entries : $orders->count), >+ base_total => $total, >+ params => $args, >+ } >+ ); > > return $c->render( > status => 200, >diff --git a/acqui/finishreceive.pl b/acqui/finishreceive.pl >index 0ed88506c7..961e3d566f 100755 >--- a/acqui/finishreceive.pl >+++ b/acqui/finishreceive.pl >@@ -190,4 +190,4 @@ if ($suggestion_id) { > $suggestion->update( { reason => $reason } ) if $suggestion; > } > >-print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=$invoiceid&sticky_filters=1"); >+print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=$invoiceid"); >diff --git a/acqui/parcel.pl b/acqui/parcel.pl >index 9e4974ba90..1e42ed9174 100755 >--- a/acqui/parcel.pl >+++ b/acqui/parcel.pl >@@ -109,25 +109,6 @@ unless( $invoiceid and $invoice->{invoiceid} ) { > exit; > } > >-my $sticky_filters = $input->param('sticky_filters') || 0; >- >-if ($sticky_filters) { >- my $search = $input->cookie("filter_parcel_summary"); >- my $ean = $input->cookie("filter_parcel_ean"); >- my $basketname = $input->cookie("filter_parcel_basketname"); >- my $orderno = $input->cookie("filter_parcel_orderno"); >- my $basketgroupname = $input->cookie("filter_parcel_basketgroupname"); >- >- $template->param( >- summaryfilter => $search, >- eanfilter => $ean, >- basketfilter => $basketname, >- orderfilter => $orderno, >- basketgroupnamefilter => $basketgroupname, >- ); >-} >- >- > my $booksellerid = $invoice->{booksellerid}; > my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid ); > >@@ -211,6 +192,5 @@ $template->param( > total_tax_excluded => $total_tax_excluded, > total_tax_included => $total_tax_included, > subtotal_for_funds => $subtotal_for_funds, >- sticky_filters => $sticky_filters, > ); > output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt >index 578a08ae65..61468aff99 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt >@@ -370,7 +370,7 @@ > </div> > </div><div class="row"><fieldset class="action"> > <input type="submit" value="Save" class="button" accesskey="w" /> >- <a class="cancel" href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid | html %]&sticky_filters=1">Cancel</a> >+ <a class="cancel" href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid | html %]">Cancel</a> > </fieldset></div> </form> > [% ELSE %] > This ordernumber does not exist. >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt >index 99d6459c94..4b19420edf 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt >@@ -105,9 +105,6 @@ > <th>Basket</th> > <th>Basket group</th> > <th>Order line</th> >- <th class="hidden">Title</th> >- <th class="hidden">Author</th> >- <th class="hidden">ISBN</th> > <th>Summary</th> > <th>More</th> > <th>Replacement price</th> >@@ -118,24 +115,6 @@ > <th> </th> > <th> </th> > </tr> >- <tr> >- <th><div class="input-group input-group-sm"><input id="basket_name_column_search" type="text" class="form-control column-filter" data-search-fields='["basket.name"]'></div></th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["basket.basket_group.name"]'></div></th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.order_id"]'></div></th> >- <th class="hidden"> </th> >- <th class="hidden"> </th> >- <th class="hidden"> </th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.internal_note","me.vendor_note","biblio.title","biblio.author","biblio.isbn","biblio.publisher","biblio.publication_year","biblio.copyright_date","biblio.suggestions.suggester.surname","biblio.suggestions.suggester.firstname"]'></div></th> >- <th> </th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.replacement_price"]'></div></th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.quantity"]'></div></th> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.ecost"]'></div></th> >- <th> </th> >- <!--th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["order_cost"]'></div></th--> >- <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["fund.name"]'></div></th> >- <th> </th> >- <th> </th> >- </tr> > </thead> > </table> > </div> >@@ -340,41 +319,6 @@ > <div class="col-sm-2 col-sm-pull-10"> > <aside> > >-<form action="/cgi-bin/koha/acqui/parcel.pl" id="filterform" method="post"> >- <fieldset class="brief"> >- <h4>Filter</h4> >- <ol> >- <li> >- <label for="summaryfilter">ISBN, author or title:</label> >- <input type="text" name="summaryfilter" id="summaryfilter" value="[% summaryfilter | html %]"/> >- </li> >- <li> >- <label for="basketfilter">Basket name:</label> >- <input type="text" name="basketfilter" id="basketfilter" value="[% basketfilter | html %]"/> >- </li> >- <li> >- <label for="basketgroupnamefilter">Basket group name:</label> >- <input type="text" name="basketgroupnamefilter" id="basketgroupnamefilter" value="[% basketgroupnamefilter | html %]" /> >- </li> >- <li> >- <label for="orderfilter">Order line:</label> >- <input type="text" name="orderfilter" id="orderfilter" value="[% orderfilter | html %]"/> >- </li> >- [% IF (UNIMARC) %] >- <li> >- <label for="eanfilter">EAN:</label> >- <input type="text" name="eanfilter" id="eanfilter" value="[% eanfilter | html %]"/> >- </li> >- [% END %] >- </ol> >- <fieldset class="action"> >- <input type="hidden" value="search" name="op" /> >- <input type="hidden" value="[% invoiceid | html %]" name="invoiceid" /> >- <input type="submit" value="Filter" /> >- <a href="#" id="clear_form_filters">Clear</a> >- </fieldset> >- </fieldset> >-</form> > [% INCLUDE 'acquisitions-menu.inc' %] > </aside> > </div> <!-- /.col-sm-2.col-sm-pull-10 --> >@@ -388,86 +332,8 @@ > <style>#dataPreview { width : 80%; } @media (max-width: 767px) { #dataPreview { margin: 0; width : auto; } }</style> > <script> > dt_overwrite_html_sorting_localeCompare(); >- var sticky_filters = [% sticky_filters | html %]; > var columns_filter = {}; > >- function query_from_filters( base_query ) { >- >- var query_and = []; >- >- var summary = $("#summaryfilter").val(); >- var basket_group = $("#basketgroupnamefilter").val(); >- var basket_name = $("#basketfilter").val(); >- var order_id = $("#orderfilter").val(); >- var ean = $("#eanfilter").val(); >- >- // ean == undefined if the HTML doesn't have it >- ean = (ean === undefined) ? '' : ean; >- >- if ( basket_name != "" ) { >- query_and.push( { "basket.name": { "like": '%'+basket_name+'%' } } ); >- } >- if (basket_group != "") { >- query_and.push( { "basket.basket_group.name": { "like": '%'+basket_group+'%' } } ); >- } >- if (summary != "") { >- query_and.push( { "-or": [{"biblio.title": { "like": '%'+summary+'%' } }, >- {"biblio.author": { "like": '%'+summary+'%' } }, >- {"biblio.isbn": { "like": '%'+summary+'%' } } ] } ); >- } >- if (ean != "") { >- query_and.push( { "biblio.ean": ean } ); >- } >- >- $(".column-filter").each(function () { >- var search_fields = $(this).data('search-fields'); >- var value = this.value; >- >- if ( value != '' && >- value != undefined ) { // skip if empty >- >- var columns_filters = []; >- >- search_fields.forEach( function (item) { >- if ( item === "me.order_id" || >- item === "me.replacement_price" || >- item === "me.quantity" || >- item === "me.ecost" ) { >- // For numbers, we do 'starts with' >- var object = {}; >- object[item] = { "like": value+'%' }; >- columns_filters.push( object ); >- } >- else { >- var object = {}; >- object[item] = { "like": '%'+value+'%' }; >- columns_filters.push( object ); >- } >- }); >- >- if ( columns_filters.length > 1 ) { >- query_and.push( { "-or": columns_filters } ); >- } >- else if ( columns_filters.length > 0 ) { >- query_and.push( columns_filters[0] ); >- } >- } >- }); >- >- var query_params = []; >- >- if ( query_and.length > 0 ) { >- query_and.push(base_query); >- query_params.push('q=' + encodeURIComponent(JSON.stringify({ "-and": query_and }))); >- } >- >- if ( order_id != "" ) { >- query_params.push("order_id="+order_id); >- } >- >- return query_params; >- } >- > function _escape_str(s){ > return s != null ? s.escapeHtml() : ""; > } >@@ -480,7 +346,6 @@ > if ( $("#receivedt").length ) { > var receivedt = $("#receivedt").dataTable($.extend(true, {}, dataTablesDefaults, { > "bStateSave": true, >- "iCookieDuration": 60*60*24*1000, // 1000 days > "iDisplayLength": 10, > "aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]], > "aoColumnDefs": [ >@@ -505,15 +370,9 @@ > })); > } > >- var base_query = { "basket.vendor_id": [% booksellerid | html %] }; >- var query_params = query_from_filters( base_query ); >- >- var THE_query = query_params.join("&"); >- >- var pending_orders_url = '/api/v1/acquisitions/orders?only_active=1'; > var pending_orders_table = $("#pending_orders").api({ > "ajax": { >- "url": pending_orders_url + '&' + THE_query >+ "url": '/api/v1/acquisitions/orders?only_active=1' > }, > "header_filter": true, > "embed": [ >@@ -527,8 +386,6 @@ > "items" > ], > "stateSave": true, // remember state on page reload >- "orderCellsTop": true, // tell the datatable sorting is done on the top row >- 'dom': 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>', > "drawCallback": function (settings) { > $(".previewData").on("click", function(e){ > e.preventDefault(); >@@ -539,20 +396,9 @@ > $('#dataPreview').modal({show:true}); > }); > }, >- "columnDefs": [ { >- "targets": [3,4,5,9], >- "render": function (data, type, row, meta) { >- return _escape_str(data); >- } >- }, >- { >- "targets": [8,10], >- "render": function (data, type, row, meta) { >- return _escape_price(data); >- } >- } ], > "columns": [ > { "data": "basket.name", >+ "searchable": true, > "orderable": true, > "render": function(data, type, row, meta) { > if (type != 'display') return _escape_str(data); >@@ -584,27 +430,10 @@ > } > }, > { >- "data": "biblio.author", >- "visible": false, >- "searchable": true, >- "orderable": false >- }, >- { >- "data": "biblio.title", >- "visible": false, >- "searchable": true, >- "orderable": false >- }, >- { >- "data": "biblio.isbn", >- "visible": false, >- "searchable": true, >- "orderable": false >- }, >- { >- "data": function(row, type, val, meta) { >+ "data": "biblio.author:biblio.title:biblio.isbn", >+ "render": function(data, type, row, meta) { > var result = ''; >- if ( row.biblio_id != null ) { >+ if ( row && row.biblio_id != null ) { > result = "<p><a href=\"/cgi-bin/koha/catalogue/detail.pl?biblionumber="+encodeURIComponent(row.biblio_id)+"\">"+row.biblio.title.escapeHtml()+"</a>"; > if ( row.biblio.author != null ) > result += _(" by ") + row.biblio.author.escapeHtml(); >@@ -672,16 +501,18 @@ > > return result; > }, >- "orderable": false >+ "orderable": false, > }, > { >- "data": function( row, type, val, meta) { >+ "data": "", >+ "render": function(data, type, row, meta) { > var result = '<a href="/cgi-bin/koha/acqui/showorder.pl?ordernumber=' + encodeURIComponent(row.order_id) + '" class="previewData">' + _("Order") + '</a><br>' > + '<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=' + encodeURIComponent(row.biblio_id) + '" class="previewData">' + _("MARC") + '</a><br>' > + '<a href="/cgi-bin/koha/catalogue/showmarc.pl?viewas=card&id=' + encodeURIComponent(row.biblio_id) + '" class="previewData">' + _("Card") + '</a>'; > return result; > }, >- "orderable": false >+ "orderable": false, >+ "searchable": false > }, > { > "data": "replacement_price" >@@ -694,10 +525,12 @@ > "data": "ecost" > }, > { >- "data": function ( row, type, val, meta ) { >+ "data": "", >+ "render": function(data, type, row, meta) { > return (row.quantity * row.ecost).format_price(); > }, >- "orderable": false // FIXME: How can we do it in DBIC? >+ "orderable": false, // FIXME: How can we do it in DBIC? >+ "searchable": false > }, > { > "data": "fund.name", >@@ -707,17 +540,20 @@ > } > }, > { >- "data": function( row, type, val, meta ) { >+ "data": "", >+ "render": function(data, type, row, meta) { > return '<a href="orderreceive.pl?ordernumber=' > + encodeURIComponent(row.order_id) + '&invoiceid=[% invoiceid | uri %]' + '">' > + _("Receive") + '</a><br/>' > + '<a href="#" onclick="transfer_order_popup(' + row.order_id.escapeHtml() + '); return false;">' > + _("Transfer") + '</a>'; > }, >- "orderable": false >+ "orderable": false, >+ "searchable": false > }, > { >- "data": function( row, type, val, meta ) { >+ "data": "", >+ "render": function(data, type, row, meta) { > var result = ""; > > if ( row.current_holds_count > 0 ) { >@@ -775,52 +611,11 @@ > > return result; > }, >- "orderable": false >+ "orderable": false, >+ "searchable": false > } > ] >- }); >- >- // column filter events handling >- $(".column-filter").each(function () { >- $(this).on( 'keyup change', function () { >- // recalculate the query >- var query_params = query_from_filters( base_query ); >- // refresh the datatable as appropriate >- if ( query_params.length > 0 ) { >- pending_orders_table.api().ajax.url( pending_orders_url + '&' + query_params.join("&") ); >- } >- else { >- pending_orders_table.api().ajax.url( pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query)) ); >- } >- pending_orders_table.api().ajax.reload( null, false ); >- }); >- }); >- >- $("#filterform").on("submit", function(e) { >- e.preventDefault(); >- >- // Save the filters in the cookie >- $.cookie("filter_parcel_summary", $("#summaryfilter").val()); >- $.cookie("filter_parcel_basketname", $("#basketfilter").val()); >- $.cookie("filter_parcel_orderno", $("#orderfilter").val()); >- $.cookie("filter_parcel_basketgroupname", $("#basketgroupnamefilter").val()); >- $.cookie("filter_parcel_ean", $("#eanfilter").val()); >- >- var query_params = query_from_filters( base_query ); >- >- if ( query_params.length > 0 ) { >- pending_orders_table.api().ajax.url( pending_orders_url + '&' + query_params.join("&") ); >- } >- else { >- pending_orders_table.api().ajax.url( pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query)) ); >- } >- pending_orders_table.api().ajax.reload( null, false ); >- }); >- >- $('#clear_form_filters').on("click", function(){ >- $(this).closest('form').find("input[type=text], textarea").val(""); >- pending_orders_table.api().ajax.url(pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query))).draw(); >- }); >+ }, {}, 1, {"basket.vendor_id": [% booksellerid | html %]}); > > $(".previewData").on("click", function(e){ > e.preventDefault(); >diff --git a/koha-tmpl/intranet-tmpl/prog/js/datatables.js b/koha-tmpl/intranet-tmpl/prog/js/datatables.js >index be2da8c976..33a21d8287 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/datatables.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/datatables.js >@@ -509,7 +509,7 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { > > (function($) { > >- $.fn.api = function(options, columns_settings, add_filters) { >+ $.fn.api = function(options, columns_settings, add_filters, default_filters) { > var settings = null; > > if ( add_filters ) { >@@ -563,6 +563,22 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { > _per_page: length > }; > >+ >+ function build_query(col){ >+ var parts = []; >+ var attributes = col.data.split(':'); >+ for (var i=0;i<attributes.length;i++){ >+ var part = {}; >+ var attr = attributes[i]; >+ var value = data.columns[col.idx].search.value; >+ part[!attr.includes('.')?'me.'+attr:attr] = options.criteria === 'exact' >+ ? value >+ : {like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'') + value + (['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; >+ parts.push(part); >+ } >+ return parts; >+ } >+ > var filter = data.search.value; > // Build query for each column filter > var and_query_parameters = settings.aoColumns >@@ -570,10 +586,10 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { > return col.bSearchable && typeof col.data == 'string' && data.columns[col.idx].search.value != '' > }) > .map(function(col) { >- var part = {}; >- var value = data.columns[col.idx].search.value; >- part[!col.data.includes('.')?'me.'+col.data:col.data] = options.criteria === 'exact'?value:{like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'')+value+(['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; >- return part; >+ return build_query(col) >+ }) >+ .map(function r(e){ >+ return ($.isArray(e) ? $.map(e, r) : e); > }); > > // Build query for the global search filter >@@ -582,12 +598,15 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { > return col.bSearchable && typeof col.data == 'string' && data.columns[col.idx].search.value == '' && filter != '' > }) > .map(function(col) { >- var part = {}; >- value = filter; >- part[!col.data.includes('.')?'me.'+col.data:col.data] = options.criteria === 'exact'?value:{like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'')+value+(['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; >- return part; >+ return build_query(col) >+ }) >+ .map(function r(e){ >+ return ($.isArray(e) ? $.map(e, r) : e); > }); > >+ if ( default_filters ) { >+ and_query_parameters.push(default_filters); >+ } > query_parameters = and_query_parameters; > query_parameters.push(or_query_parameters); > if(query_parameters.length) { >@@ -748,8 +767,13 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { > var is_searchable = table_dt.settings()[0].aoColumns[i].bSearchable; > if ( is_searchable ) { > var title = $(this).text(); >- var search_title = _("Search %s").format(title); >- $(this).html( '<input type="text" placeholder="%s" />'.format(search_title) ); >+ var existing_search = table_dt.column(i).search(); >+ if ( existing_search ) { >+ $(this).html( '<input type="text" value="%s" style="width: 100%" />'.format(existing_search) ); >+ } else { >+ var search_title = _("Search %s").format(title); >+ $(this).html( '<input type="text" placeholder="%s" style="width: 100%" />'.format(search_title) ); >+ } > > $( 'input', this ).on( 'keyup change', function () { > if ( table_dt.column(i).search() !== this.value ) { >-- >2.20.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 20212
:
97545
|
97546
|
97547
|
97629
|
97630
|
97633
|
97634
|
97635
|
97745
|
98226
|
98230
|
98241
|
99724
|
99725
|
99727
|
100142
|
100475
|
100476
|
100477
|
100478
|
100552
|
100553
|
100554
|
100555
|
100600
|
100601
|
100602
|
100603
|
100605
|
100606
|
100643
|
101320
|
103684
|
103685
|
103686
|
103687
|
103688
|
109861
|
109862
|
109863
|
109864
|
109866
|
109867
|
109868
|
109869
|
109870
|
109936
|
110229
|
110234
|
110478
|
110482
|
111568
|
111569
|
112310
|
112521
|
112522
|
112523
|
112524
|
112686
|
112695
|
112698
|
112699
|
112700
|
112702
|
112703
|
112704
|
112705
|
112706
|
112868
|
112882
|
112987
|
113278
|
113279
|
114607
|
114608
|
114609
|
114610
|
114611
|
114612
|
114613
|
114614
|
114615
|
114616
|
114617
|
114942
|
114953
|
114954
|
114956
|
114959
|
114963
|
115050
|
115056
|
115057
|
115060
|
115062
|
115107
|
115108
|
115109
|
115817
|
115818
|
115819
|
115820
|
115821
|
115822
|
115886
|
115887
|
115888
|
115889
|
115890
|
115891
|
115892
|
115893
|
115894
|
115895
|
115896
|
115897
|
115898
|
115899
|
115900
|
115901
|
115902
|
115903
|
115904
|
115905
|
115906
|
115920
|
115921
|
115940
|
115941
|
115943
|
115944
|
115945
|
115946
|
115947
|
115948
|
115949
|
115950
|
115951
|
115952
|
115953
|
115954
|
115955
|
115956
|
115957
|
115958
|
115959
|
115960
|
115961
|
115962
|
115963
|
115964
|
115965
|
116139