Simulate delayed and dropped packets on Linux

Original is here

Examples
Emulating wide area network delays
This is the simplest example, it just adds a fixed amount of delay to all packets going out of the local Ethernet.

tc qdisc add dev eth0 root netem delay 100ms

Now a simple ping test to host on the local network should show an increase of 100 milliseconds. The delay is limited by the clock resolution of the kernel (Hz). On most 2.4 systems, the system clock runs at 100 Hz which allows delays in increments of 10 ms. On 2.6, the value is a configuration parameter from 1000 to 100 Hz.

Later examples just change parameters without reloading the qdisc

Real wide area networks show variability so it is possible to add random variation.

tc qdisc change dev eth0 root netem delay 100ms 10ms

This causes the added delay to be 100 ± 10 ms. Network delay variation isn’t purely random, so to emulate that there is a correlation value as well.

tc qdisc change dev eth0 root netem delay 100ms 10ms 25%

This causes the added delay to be 100 ± 10 ms with the next random element depending 25% on the last one. This isn’t true statistical correlation, but an approximation.

Delay distribution
Typically, the delay in a network is not uniform. It is more common to use a something like a normal distribution to describe the variation in delay. The netem discipline can take a table to specify a non-uniform distribution.

tc qdisc change dev eth0 root netem delay 100ms 20ms distribution normal

The actual tables (normal, pareto, paretonormal) are generated as part of the iproute2 compilation and placed in /usr/lib/tc; so it is possible with some effort to make your own distribution based on experimental data.

Packet loss
Random packet loss is specified in the ‘tc’ command in percent. The smallest possible non-zero value is:

2−32 = 0.0000000232%

tc qdisc change dev eth0 root netem loss 0.1%

This causes 1/10th of a percent (i.e. 1 out of 1000) packets to be randomly dropped.

An optional correlation may also be added. This causes the random number generator to be less random and can be used to emulate packet burst losses.

tc qdisc change dev eth0 root netem loss 0.3% 25%

This will cause 0.3% of packets to be lost, and each successive probability depends by a quarter on the last one.

Probn = 0.25 × Probn-1 + 0.75 × Random

Alternative

For dropped packets I would simply use iptables and the statistic module.

iptables -A INPUT -m statistic –mode random –probability 0.01 -j DROP
Above will drop an incoming packet with a 1% probability. Be careful, anything above about 0.14 and most of you tcp connections will most likely stall completely.

Undo with -D:

iptables -D INPUT -m statistic –mode random –probability 0.01 -j DROP
Take a look at man iptables and search for “statistic” for more information.

Extracting the RTP packets from PCAP

original is here

On Linux, extracting the RTP packets from PCAP file is possible with tshark together with shell tools tr and xxd, but then you might need other tools to convert to an audio format.

If you have a single call recording in the pcap, so all rtp packets belong to it, try with:

tshark -n -r call.pcap -2 -R rtp -T fields -e rtp.payload | tr -d ‘\n’,’:’ | xxd -r -ps >call.rtp
If the pcap has the recordings from many calls, then you have to identify the calls and their RTP streams by source/destination IPs or SSRC and build the filter accordingly, for example if SSRC is 0x7f029328:

tshark -n -r call.pcap -2 -R rtp -R “rtp.ssrc == 0x7f029328” -T fields -e rtp.payload | tr -d ‘\n’,’:’ | xxd -r -ps >call.rtp
Tools like sox or ffmpeg can be used to convert from call.rtp file to wav format, depending on the codec that was used in the call. If the codec was G711u (PCMU) with sample rate 8000:

sox -t ul -r 8000 -c 1 call.rtp call.wav
The audio formats supported by sox are listed by sox -h. The ffmpeg might be needed for codecs such as G729 or G722, example for G722 with sample rate 16000:

ffmpeg -f g722 -i call.rtp -acodec pcm_s16le -ar 16000 -ac 1 call.wav
These guidelines are from some brief notes I made during the past when I had similar needs, hope they are good and still valid nowadays, or at least provide the right direction to explore further.

Audiocodes with Asterisk DAHDI T1 ISDN

Here is /etc/dahdi/system.conf

# Autogenerated by /usr/sbin/dahdi_genconf on Tue Jan 24 21:46:33 2023
# If you edit this file and execute /usr/sbin/dahdi_genconf again,
# your manual changes will be LOST.
# Dahdi Configuration File
#
# This file is parsed by the Dahdi Configurator, dahdi_cfg
#
# Span 1: TE4/0/1 "T4XXP (PCI) Card 0 Span 1" (MASTER) 
span=1,1,1,esf,b8zs
# termtype: te
bchan=1-23
dchan=24
echocanceller=mg2,1-23

# Span 2: TE4/0/2 "T4XXP (PCI) Card 0 Span 2" 
span=2,2,0,esf,b8zs
# termtype: te
bchan=25-47
dchan=48
echocanceller=mg2,25-47

# Span 3: TE4/0/3 "T4XXP (PCI) Card 0 Span 3" 
span=3,3,0,ccs,hdb3,crc4
# termtype: te
bchan=49-63,65-79
dchan=64
echocanceller=mg2,49-63,65-79

# Span 4: TE4/0/4 "T4XXP (PCI) Card 0 Span 4" 
span=4,4,1,ccs,hdb3,crc4
# termtype: te
bchan=80-94,96-110
dchan=95
echocanceller=mg2,80-94,96-110

# Global data

loadzone	= us
defaultzone	= us

Here is /etc/dahdi/assigned-spans.conf

#
# Autogenerated by /usr/sbin/dahdi_span_assignments on Tue 24 Jan 2023 09:46:33 PM +04
# Map devices + local spans to span + base channel number

# Device: [] @Board_ID_Switch_0 /sys/devices/pci0000:00/0000:00:1c.6/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0
/sys/devices/pci0000:00/0000:00:1c.6/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 1:1:1
/sys/devices/pci0000:00/0000:00:1c.6/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 2:2:25
/sys/devices/pci0000:00/0000:00:1c.6/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 3:3:49
/sys/devices/pci0000:00/0000:00:1c.6/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 4:4:80

Here is /etc/dahdi/modules.conf

# Autogenerated by /usr/sbin/dahdi_genconf (Dahdi::Config::Gen::Modules) on Tue Jan 24 08:43:41 2023
# If you edit this file and execute /usr/sbin/dahdi_genconf again,
# your manual changes will be LOST.
wct4xxp

Here is /etc/dahdi/span-types.conf

#
# /etc/dahdi/spantype.conf: Set E1/T1/J1 per-device
#
# Built as a table of two columns:
#  <id>    <local_spanno>:<type>
#
# Where:
#  * The <id> field may be either:
#         hardware_id
#         @location
#         devpath (in sysfs)
#  * The <local_spanno> is the relative span number 
#    in the device (starting from 1)
#    In this filed globbing rules apply. E.g:
#        - * are all the spans in this device
#        - [12] are the first two spans in this device
#  * The <type> may be E1, T1 or J1
#
# Examples:
#  Set the first two spans of a specific Astribank to T1
#usb:000156 [12]:T1

#  Set all spans of another Astribank to T1
#usb:INT03165		*:E1

#  Set the first two spans of an Astribank to T1. The
#  Astribanks is specified by its location instead of hardware_id
#@usb-0000:00:1d.7-3 [12]:T1

pci:0000:05:08.0	[12]:T1
pci:0000:05:08.0	[34]:E1

/etc/asterisk/dahdi-channels.conf

; Autogenerated by /usr/sbin/dahdi_genconf on Tue Jan 24 21:46:33 2023
; If you edit this file and execute /usr/sbin/dahdi_genconf again,
; your manual changes will be LOST.
; Dahdi Channels Configurations (chan_dahdi.conf)
;
; This is not intended to be a complete chan_dahdi.conf. Rather, it is intended
; to be #include-d by /etc/chan_dahdi.conf that will include the global settings
;

; Span 1: TE4/0/1 "T4XXP (PCI) Card 0 Span 1" (MASTER) 
group=0,11
context=from-pstn
switchtype = national
signalling = pri_cpe
channel => 1-23
context = default
group = 63

; Span 2: TE4/0/2 "T4XXP (PCI) Card 0 Span 2" 
group=0,12
context=from-pstn
switchtype = national
signalling = pri_net
channel => 25-47
context = default
group = 63

; Span 3: TE4/0/3 "T4XXP (PCI) Card 0 Span 3" 
group=0,13
context=from-pstn
switchtype = euroisdn
signalling = pri_net
channel => 49-63,65-79
context = default
group = 63

; Span 4: TE4/0/4 "T4XXP (PCI) Card 0 Span 4" 
group=0,14
context=from-pstn
switchtype = euroisdn
signalling = pri_cpe
channel => 80-94,96-110
context = default
group = 63

The line “signalling=pri_net” indicates that this card is simulating the service provider (network) and providing the master clock.

Mera MVTS II Helpful commands

run console /bin/mp_shell.x

>sh ca

6343493, 79036697752, 74992903015, 172.16.0.26:5060, 77.50.0.34:5060, 973, 689, 586, 568, 705

#>show stat
Mera VoIP Transit Softswitch ( 5000 Advanced )
Release 3.1.3 build 3103-0044 (Aug  7 2007 01:16:42) HASP
Redundancy type: Shared Ip
———————- Common statistics ———————-
 Host : 213.134.200.58
  Start time        : 02/09/2019 12:45:54
  Up time           : 9 days 2 hours 6 minutes
  Stat start time   : 02/09/2019 12:45:54
  Stat duration     : 9 days 2 hours 6 minutes
  Max load          : 69 calls
  Calls duration    : 117549 minute(s)
  Active calls      : 36
  Active AVG 1m (5m): 34.58 (32.61)
  Call rate 1m (5m) : 0.24 (0.35) (unlimited)
  Call rate maximum : 1.26 at 09/09/2019 10:13:36
  Full CR   1m (5m) : 0.24 (0.35)
  Full CR   maximum : 1.26 at 09/09/2019 10:13:36
  Received calls    : 75997
  Normal   calls    : 68939
  Failed   calls    : 7018
  Rejected calls    : 0
  Received Kb       : 138401707
  Written  Kb       : 138392200

>help

List of commands:
start [cfgfile] – starts proxy server
stop [gr[acious]] – stops proxy server [after all active call finish]
re[load] co[nfig] [-d] – reloads new configuration from config files [show debug info]
re[set] st[at] [full] – resets all statistic data
re[set] st[at] src|dst|gw|dp objectname|all
– resets statistics of a category (or an object) specified.
categories are originators, terminators, gateways and dialpeers
info – shows info about proxy server procceses
kill – kills all proxy server procceses
help – shows this help
sh[ow] ca[ll] [ta[ble]] [na[me]]
– shows all active calls [in table form] [using gw names]
sh[ow] ca[ll] [-src oct.oct.oct.oct] [-dst -src oct.oct.oct.oct]
– shows selected active calls
sh[ow] ca[ll] call_number – shows full call info about call with call_number
sh[ow] dc – shows statistics of disconnect codes
sh[ow] dial called_number [[[calling_number] group] src_ip_address]
– simulates call
sh[ow] dp [sub_string] – shows dialpeers info with [sub_string]
sh[ow] ep [EP_NUMBER] – shows info about all|selected registered endpoints
sh[ow] gk [CFG_RAS_CLIENT_NAME]
– shows info about all|selected RAS clients
sh[ow] gw [oct.oct.oct.oct|CFG_GW_NAME]
– shows info about all|selected gateways
sh[ow] in[coming] – shows registered endpoints from IP address
sh[ow] route [oct.oct.oct.oct]
– shows all route table or route to the host
sh[ow] st[at] [full] – shows common statistics [or by categories]
sh[ow] st[at] src|dst|gw|dp [objectname]
– shows statistics of a category (an object)
sh[ow] user [EP_NAME] – shows info about all|selected RAS users
di[sable] gatekeeper|gk [gk1], [gk2], …
– disables gatekeeper(s) mentioned
te[rminate] ca[ll] call_number – terminates call with call_number
te[rminate] ca[ll] [-src oct.oct.oct.oct] [-dst -src oct.oct.oct.oct]
– terminates selected calls
un[register] endpoint|ep (all|id endpoint_id |addr endpoint_call_addr[:port] |num ep_number)
– unregisters selected endpoints
quit – quits from the console
(for more detailed information see the system administrator guide)

>sh dc

Disconnect reason statistics:

Reason : Text : Quantity

  1 : CallerNormal            : 3436545
  2 : CalledNormal            : 7148625
  3 : CallerDropTCP           : 4895
  4 : CalledDropTCP           : 24
101 : TimeoutTCPConnectH225   : 100
102 : TimeoutConnectMsg       : 19
103 : TimeoutRBT              : 47054
112 : FailedTCPConnectH225    : 13
120 : TimeoutRouteAttempt     : 926
126 : MaxCapacityExceed       : 44
129 : NotAllowedPrefix        : 930
134 : GatewayUnaccessible     : 64
136 : TermGwCapacityFull      : 5704
137 : GatewayNullReached      : 38953
138 : HuntStopped             : 18719
139 : NoApproprDialpeerFound  : 296654
202 : SourceGatewayUnknown    : 7
206 : RadiusAdmissionTimeout  : 1
208 : RadiusAdmRouteReject    : 563
300 : MaxSessionTime exceed   : 133
301 : DanglingCall            : 1378

MVTS

ALOE Systems is a new identity of MERA Systems

MVTS (MERA VoIP Transit Softswitch) – это полнофункциональный пограничный контроллер сессий, предназначенный для гибкого управления VoIP-трафиком в сетях операторского класса. Основная задача MVTS — концентрация и коммутация VoIP-потоков, трансляция их между сетями с разнородной сигнализацией.

  • Вывести из командной строки версии всех модулей MVTS$ echo “select product,version,product_title from version;” | mysql -uroot mvtspro product version product_title logic 2.0.0-77 Logic mvtspro 1.5.0-81 MVTS Pro ts 4.0.1-51 TS webdb 1.5.0-65 WEB+DB webengine 1.5.0-45 WEBENGINE

Использование регулярных выражений в MVTS

Регулярные выражения используются при задании значений следующим конфигурационным параметрам:

dialpeer.cfg:

  • – dst_pattern=, src_pattern=,
  • – dst_translate=, src_translate=
  • – dst_bill_translate=, src_bill_translate=
  • – user_translate=
  • – display_ie_translate=

user.cfg; gateway.cfg

  • – dst_pattern=, src_pattern=,
  • – dst_translate=, src_translate=,
  • – in_dst_translate=, in_src_translate=

При необходимости указания пустого номера в описании объектов набора (dialpeer) используется ключевое слово «empty».

  • Пример: При значении параметра src_translate=empty/123456, MVTS преобразует полученный пустой номер вызывающего абонента в номер 123456. Данное ключевое слово также может использоваться для трансформации информационного элемента «display» (параметр display_ie_translate=), в случае, если оно отсутствует в получаемом пакете SETUP. MVTS проверяет регулярные выражения в правилах преобразования номеров на присутствие запрещенных символов и при обнаружении удаляет их.

При возникновении ошибки (недопустимый символ в регулярном выражении) результат проверки выводится в трассировочный журнал, который записывается в файл с названием mp.kernel.sh.log-<date>Регулярные выражения допускают использование следующих символов: ^0123456789*#\&

  • ПРЕФИКСЫ ПОЛЕЙ DST_PATTERN И SRC_PATTERN

Наиболее часто используемые конструкции:

dst_pattern=777[0-9]+

Комментарий: номера, начинающиеся с 777 и состоящие далее любого количества цифр от 0 до 9. удачные примеры: 77711, 777922 неудачные примеры: 77811, 7767

dst_pattern=777[0-5]{1}[0-9]+

Комментарий: номера начинающиеся с 777, далее следует любая цифра в диапазоне от 0 до 5 и затем любое количество цифр от 0 до 9. удачные примеры: 77711, 777422 неудачные примеры: 777, 77811, 77761, 7775

dst_pattern=...... или dst_pattern=.{6}

Комментарий: шесть любых знаков, включая все разрешенные цифры и знаки – например, символ # удачные примеры: 123456, 976065, 123#56 неудачные примеры: 1111111, 111, 123456#

Трансляция номеров

Основной целью преобразования (трансляции) является приведение телефонных номеров к определенному формату. Для трансляции номеров наиболее часто используются такие операции как добавление, удаление или замена отдельных частей телефонного номера. Регулярные выражения, используемые для преобразования номеров, состоят из буквенно-числовых символов и метасимволов, описание которых приведено ниже:

  • символ «/» делит регулярное выражение трансляции на две части: шаблон поиска и строка замены. Все, что находится слева от символа «/» является шаблоном поиска (все номера, подходящие под шаблон поиска, подлежат дальнейшему преобразованию). Все, что находится справа от символа «/», является строкой замены (т.е. тем, на что будет заменен номер, подошедший под шаблон в левой части выражения).
  • символ «|» делит шаблон поиска на несколько логических частей
  • символ «\» ставится в правой части регулярного выражения. Следующая за этим знаком цифра обозначает какую часть шаблона, разделенного символами «|» следует использовать для формирования нового номера
  • символ «&» обозначает все выражение, подошедшее под шаблон поиска. Данный символ употребляется в правой части выражения.
  • символ «.» означает любой знак (включая цифры, буквы и символы)
  • выражение в квадратных скобках [] используется только в шаблоне поиска и означает одну любую цифру из заданного в скобках интервала или последовательности цифр. Например: [0-9] означает одну любую цифру от 0 до 9. [1234] означает одну цифру от 1 до 4, [1236-9] означает одну любую цифру из следующих: 1,2,3,6,7,8,9.
  • Число в фигурных скобках означает количество повторений предшествующего символа (цифры, буквы, символа или выражения). Например: .{4} означает четыре любых символа. [0-9]{2} означает два повторения выражения [0-9], т.е. [0-9] [0-9]
  • символ «*» означает любое количество повторений предшествующего символа (включая цифры, буквы или выражения). Например: [0-9]* означает любое количество цифр от 0 до 9. .* означает любое количество любых знаков.

Примеры преобразования номеров

  • Операции добавления

Задача 1: добавить префикс 78 к номеру 12345:

dst_translate = 12345/78&

результат: 12345 → 7812345

Задача 2: добавить префикс 78312 к любому шестизначному номеру:

dst_pattern=.{6}
dst_translate =.{6}/78312&

результат: 123456 → 78312 123456 результат: 654321 → 78312 654321

Задача 3: добавить префикс 78312 к номеру, начинающемуся с 777:

dst_pattern=<.*>
dst_translate=777.*/78312&

результат: 777123456 → 78312777123456 результат: 777121212 → 78312777121212

Задача 4: добавить последовательность символов 77 в конец строки

dst_translate=.*/&77

результат: 1234 → 123477

  • Операции удаления

Задача 1: из любого номера с префиксом 095 удалять префикс

dst_pattern=.*
dst_translate=095|.*/\2

результат: 095123456# → 095 | 123456# → 123456#

Комментарий: выражение 095|.*/ в данном случае является шаблоном поиска, поэтому преобразованию подлежат только номера, начинающиеся с 095 + любое количество любых символов. Символ «|» делит шаблон поиска на две логические части. Строка замены состоит лишь из выражения «\2», что означает «взять вторую логическую часть из разделенного шаблона поиска».

Задача 2: из любого номера с префиксом 8182 удалять префикс

dst_pattern= .*
dst_translate=8182|[0-9]*/\2

результат: 8182123456 → 8182 | 123456 → 123456

Задача 3: удалять символ # из середины строки

dst_translate=[0-9]*|#|[0-9]*/\1\3

результат: 123#45 → 123 | # | 45 → 12345

Комментарий: в данном регулярном выражении шаблон поиска делится двумя символами «|» на три части: [0-9]* – любое количество цифр от 0 до 9. # – символ «решетка». [0-9]* – любое количество цифр от 0 до 9. Из синтаксиса строки замены данного регулярного выражения видно, что для создания нового номера берется только первая и третья логические части из трех выделенных в шаблоне поиска.

  • Операции замены

Задача 1: заменять префикс 8182 в любых номерах с таким префиксом на 777

dst_pattern= .*
dst_translate=8182|[0-9]*/777\2

результат: 8182123456 → 8182 | 123456 → 777 123456

Комментарий: как и в предыдущих случаях, шаблон поиска делится на две логические части символом «|» (8182 – первая логическая часть, [0-9]* – вторая логическая часть). В данном случае строка замены содержит дополнительную подстроку (777), которая будет подставлена перед второй логической частью ([0-9]*), т.е. фактически вместо первой логической части (8182). Таким образом, мы осуществляем замену первой логической части шаблона дополнительной подстрокой.

Задача 2 заменять префикс 1212 в любых номерах с таким префиксом на 1718

dst_pattern= .*
bill_translate=1212|.*/1718\2

результат: 121212345 → 1212 | 12345 → 1718 | 12345 → 171812345

Задача 3: заменять символ # в середине строки на последовательность цифр 555

dst_translate=[0-9]*|#|[0-9]*/\1 555\3

результат: 123#45 → 123 | # | 45 → 123 | 555 | 45 →12355545

Примечание: обратите внимание на пробел между \1 и 555. Отсутствие пробела будет воспринято системой как выражение \1555 – «взять одна тысяча пятьсот пятьдесят пятую логическую часть из шаблона поиска»

Задача 4: заменять символ # в конце строки на последовательность цифр 123

dst_bill_translate=[0-9]*|#/\1 123

результат: 123456# → 123456 | # → 123456123

Комментарий: Символ «|» делит шаблон поиска на две логические части, причем символ «решетка» находится во второй. Строка замены использует только первую логическую часть и добавляет к ней 123.

Примечание: обратите внимание на пробел между \1 и 123. Отсутствие пробела будет воспринято системой как выражение \1123 – «взять одна тысяча сто двадцать третью логическую часть из строки поиска».

Примеры

Задача. Добавить префикс к исходящему номеру.

Out DST translate - на выходе со свича. В таком виде терминатор получает B-номер.
dst_translate=[0-9]*/0030#&

, где

  • символ «/» делит регулярное выражение трансляции на две части: шаблон поиска и строка замены. Все, что находится слева от символа «/» является шаблоном поиска (все номера, подходящие под шаблон поиска, подлежат дальнейшему преобразованию). Все, что находится справа от символа «/», является строкой замены (т.е. тем, на что будет заменен номер, подошедший под шаблон в левой части выражения).
  • символ «&» обозначает все выражение, подошедшее под шаблон поиска. Данный символ употребляется в правой части выражения.
  • выражение в квадратных скобках [] используется только в шаблоне поиска и означает одну любую цифру из заданного в скобках интервала или последовательности цифр. Например: [0-9] означает одну любую цифру от 0 до 9. [1234] означает одну цифру от 1 до 4, [1236-9] означает одну любую цифру из следующих: 1,2,3,6,7,8,9.
  • символ «*» означает любое количество повторений предшествующего символа (включая цифры, буквы или выражения). Например: [0-9]* означает любое количество цифр от 0 до 9. .* означает любое количество любых знаков.

Задача. Нужно удалить префикс 0030# из входящего номера.

Первый вариант
In DST translate - входящий звонок на Меру
dst_translate=0030#|.*/\2

результат: 0030#123456# → 0030# | 123456# → 123456#

Комментарий: выражение 0030#|.*/ в данном случае является шаблоном поиска, поэтому преобразованию подлежат только номера, начинающиеся с 0030# + любое количество любых символов. Символ «|» делит шаблон поиска на две логические части. Строка замены состоит лишь из выражения «\2», что означает «взять вторую логическую часть из разделенного шаблона поиска».

Второй вариант. Более правильный так как в преобразованном номере разрещает только цифры.
In DST translate
dst_translate=0030#|[0-9]*/\2

yii2 email configuration

Here is the content of my /common/config/main-local.php:





<?php

return [

    'components' => [


        ...


        'mailer' => [

			'class' => 'yii\swiftmailer\Mailer',

			'useFileTransport'=>false,

			'transport' => [

				'class' => 'Swift_SmtpTransport',

				'host' => 'smtp.gmail.com',

				'username' => 'xxxxxx@gmail.com',

				'password' => 'yyyyyyyy',

				'port' => '465',

				'encryption' => 'ssl',

				],

		],

yii2 kartik gridview

installation

http://demos.krajee.com/export#installation

composer require kartik-v/yii2-export “dev-master”

frontend/config/main.php

 

after components

put this

‘modules’ => [
‘gridview’ => [‘class’ => ‘kartik\grid\Module’]
],

 

in a view after create button

 

<?php
$gridColumns = [
[‘class’ => ‘kartik\grid\SerialColumn’],
‘id’,
‘name’,
[
‘attribute’=>’author_id’,
‘label’=>’Author’,
‘vAlign’=>’middle’,
‘width’=>’190px’,
‘value’=>function ($model, $key, $index, $widget) {
return Html::a($model->author->name, ‘#’, []);
},
‘format’=>’raw’
],
‘color’,
‘publish_date’,
‘status’,
[‘attribute’=>’buy_amount’,’format’=>[‘decimal’,2], ‘hAlign’=>’right’, ‘width’=>’110px’],
[‘attribute’=>’sell_amount’,’format’=>[‘decimal’,2], ‘hAlign’=>’right’, ‘width’=>’110px’],
[‘class’ => ‘kartik\grid\ActionColumn’, ‘urlCreator’=>function(){return ‘#’;}]
];

echo ExportMenu::widget([
‘dataProvider’ => $dataProvider,
‘columns’ => $gridColumns,
]);

?>