feat: media monitoring and issue management statistic

This commit is contained in:
myqnrrhmn 2025-07-08 10:03:39 +07:00
parent 5da913d677
commit 51c1447ff7
11 changed files with 662 additions and 6 deletions

View File

@ -0,0 +1,188 @@
<?php
namespace App\Http\Controllers\Dashboard;
use App\Http\Controllers\Controller;
use App\Models\IssueManagement;
use App\Models\MediaMonitoring;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class StatisticController extends Controller
{
public function index(Request $request){
$statistics = [
[
'name' => 'Aktivitas Login',
'category' => 'login-activities',
'is_available' => false
],
[
'name' => 'Jurnalis',
'category' => 'journalists',
'is_available' => false
],
[
'name' => 'Kerja Sama Media',
'category' => 'media-cooperations',
'is_available' => false
],
[
'name' => 'Laporan Bukti Tayang',
'category' => 'reports',
'is_available' => false
],
[
'name' => 'Media',
'category' => 'media',
'is_available' => false
],
[
'name' => 'Monitoring Media & Manajemen Isu',
'category' => 'media-monitorings-issue-management',
'is_available' => true
],
[
'name' => 'Penyelesaian Kerja Sama',
'category' => 'cooperation-completions',
'is_available' => false
],
[
'name' => 'Pengguna',
'category' => 'users',
'is_available' => false
],
[
'name' => 'Perusahaan',
'category' => 'companies',
'is_available' => false
],
[
'name' => 'Rekap Konten',
'category' => 'content-recaps',
'is_available' => false
],
[
'name' => 'Pengunjung Website',
'category' => 'website-visitors',
'is_available' => false
],
];
return view('dashboard.statistics.index', [
'title' => 'Statistik',
'statistics' => $statistics
]);
}
public function show(Request $request, $category){
$data = [
'category' => $category,
'year' => $request->input('year') ? $request->input('year') : null,
'from_month' => $request->input('from_month') ? $request->input('from_month') : null,
'to_month' => $request->input('to_month') ? $request->input('to_month') : null,
];
$upComings = [
'login-activities',
'journalists',
'media-cooperations',
'reports',
'media',
'cooperation-completions',
'users',
'companies',
'content-recaps',
'website-visitors',
];
if(in_array($category, $upComings)){
return redirect()->back()->with('waiting-status', 'Dalam pegembangan');
}
$year = $request->input('year') ? $request->input('year') : Carbon::now()->year;
switch($category){
case 'media-monitorings-issue-management':
$data['title'] = 'Statistik Monitoring Media & Manajemen Isu';
// Statistik Isu
$issues = IssueManagement::with(['mediaMonitoring']);
$mediaMonitorings = MediaMonitoring::with(['issue']);
if($year !== 'all'){
$issues->whereYear('created_at', $year);
$mediaMonitorings->whereYear('created_at', $year);
}
$issues = $issues->get();
$mediaMonitorings = $mediaMonitorings->get();
$issueCounts = $issues->groupBy('issue')->map(function ($group) {
return $group->count();
});
$data['crisisIssue'] = $issueCounts->get('krisis', 0);
$data['negativeIssue'] = $issueCounts->get('negatif', 0);
$data['neutralIssue'] = $issueCounts->get('netral', 0);
$data['positiveIssue'] = $issueCounts->get('positif', 0);
// Akhir Statistik Isu
// Statistik Monitoring Media
$mediaMonitoringCount = $mediaMonitorings->groupBy('channel')->map(function ($group) {
return $group->count();
});
$data['facebookMediaMonitoring'] = $mediaMonitoringCount->get('facebook', 0);
$data['twitterMediaMonitoring'] = $mediaMonitoringCount->get('twitter', 0);
$data['websiteMediaMonitoring'] = $mediaMonitoringCount->get('website', 0);
$data['youtubeMediaMonitoring'] = $mediaMonitoringCount->get('youtube', 0);
$data['instagramMediaMonitoring'] = $mediaMonitoringCount->get('instagram', 0);
$data['tiktokMediaMonitoring'] = $mediaMonitoringCount->get('tiktok', 0);
$data['cetakMediaMonitoring'] = $mediaMonitoringCount->get('cetak', 0);
// Akhir Statistik Monitoring Media
// Media Monitoring 2 (pakai koleksi yang sudah ada)
$mediaMonitoringMonthly = array_fill(0, 12, 0); // Init array 12 bulan
$mediaMonitorings->groupBy(function ($item) {
return (int) $item->created_at->format('m'); // bulan sebagai int
})->each(function ($group, $month) use (&$mediaMonitoringMonthly) {
$mediaMonitoringMonthly[$month - 1] = $group->count();
});
// Issue Management 2 (pakai koleksi yang sudah ada)
$issueManagementMonthly = array_fill(0, 12, 0);
$issues->groupBy(function ($item) {
return (int) $item->created_at->format('m');
})->each(function ($group, $month) use (&$issueManagementMonthly) {
$issueManagementMonthly[$month - 1] = $group->count();
});
$mediaMonitoringWithoutIssue = MediaMonitoring::doesntHave('issue')
->when($year !== 'all', function ($query) use ($year) {
$query->whereYear('created_at', $year);
})
->get();
$mediaMonitoringWithIssue = MediaMonitoring::has('issue')
->when($year !== 'all', function ($query) use ($year) {
$query->whereYear('created_at', $year);
})
->get();
$data['mediaMonitoringWithoutIssueCount'] = $mediaMonitoringWithoutIssue->count();
$data['mediaMonitoringWithIssueCount'] = $mediaMonitoringWithIssue->count();
$data['mediaMonitoringMonthly'] = $mediaMonitoringMonthly;
$data['issueManagementMonthly'] = $issueManagementMonthly;
return view('dashboard.statistics.show.media-monitoring-issue-management', $data);
case 'issue-managements':
$data['title'] = 'Statistik Manajemen Isu';
break;
}
}
}

View File

@ -171,3 +171,7 @@ .file-not-filled{
.link-show{
width: 68% !important;
}
.not-available-text{
color: rgb(195, 195, 195) !important;
}

View File

@ -24,7 +24,7 @@
}]
};
var barChartMultiple = {
labels: ["Jan", "Feb", "Mar", "Apr", "Mey", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
dataUnit: 'Data',
datasets: [{
label: "Monitoring Media",

View File

@ -0,0 +1,126 @@
<script>
"use strict";
!function (NioApp, $) {
"use strict";
@if(is_role(['1']))
var issueStatistics = {
labels: ["Krisis", "Negatif", "Netral", "Positif"],
dataUnit: 'Data',
legend: false,
datasets: [{
borderColor: "#fff",
background: ["#FE4F2D", "#E50046", "#5CB338", "#3572EF"],
data: ["{{$crisisIssue}}", "{{$negativeIssue}}", "{{$neutralIssue}}", "{{$positiveIssue}}"]
}]
};
var mediaMonitoringStatistics = {
labels: ["Facebook", "Twitter", "Website", "YouTube", "Intagram", "TikTok", "Cetak"],
dataUnit: 'Data',
legend: false,
datasets: [{
borderColor: "#fff",
background: ["#1877F2", "#1DA1F2", "#28A745", "#FF0000", "#E4405F", "#00F2EA", "#333333"],
data: ["{{ $facebookMediaMonitoring }}", "{{ $twitterMediaMonitoring }}", "{{ $websiteMediaMonitoring }}", "{{ $youtubeMediaMonitoring }}", "{{ $instagramMediaMonitoring }}", "{{ $tiktokMediaMonitoring }}", "{{ $cetakMediaMonitoring }}"]
}]
};
var mediaMonitoringIssuesStatus = {
labels: ["Belum Memiliki Isu", "Sudah Memiliki Isu"],
dataUnit: 'Data',
legend: false,
datasets: [{
borderColor: "#fff",
background: ["#FE4F2D", "#3572EF"],
data: ["{{ $mediaMonitoringWithoutIssueCount }}", "{{ $mediaMonitoringWithIssueCount }}"]
}]
};
@elseif(is_role(['5']))
var cooperationCompletionsStatistics = {
labels: ["Menunggu", "Diterima", "Ditolak"],
dataUnit: 'Data',
legend: false,
datasets: [{
borderColor: "#fff",
background: ["#FFB200", "#5CB338", "#E50046"],
data: ["{{$cooperationCompletionWaiting}}", "{{$cooperationCompletionAccepted}}", "{{$cooperationCompletionRejected}}"]
}]
};
@endif
function ecommerceDoughnutS1(selector, set_data) {
var $selector = selector ? $(selector) : $('.ecommerce-doughnut-s1');
$selector.each(function () {
var $self = $(this),
_self_id = $self.attr('id'),
_get_data = typeof set_data === 'undefined' ? eval(_self_id) : set_data;
var selectCanvas = document.getElementById(_self_id).getContext("2d");
var chart_data = [];
for (var i = 0; i < _get_data.datasets.length; i++) {
chart_data.push({
backgroundColor: _get_data.datasets[i].background,
borderWidth: 2,
borderColor: _get_data.datasets[i].borderColor,
hoverBorderColor: _get_data.datasets[i].borderColor,
data: _get_data.datasets[i].data
});
}
var chart = new Chart(selectCanvas, {
type: 'doughnut',
data: {
labels: _get_data.labels,
datasets: chart_data
},
options: {
legend: {
display: _get_data.legend ? _get_data.legend : false,
rtl: NioApp.State.isRTL,
labels: {
boxWidth: 12,
padding: 20,
fontColor: '#6783b8'
}
},
rotation: -1.5,
cutoutPercentage: 70,
maintainAspectRatio: false,
tooltips: {
enabled: true,
rtl: NioApp.State.isRTL,
callbacks: {
title: function title(tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function label(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex]['data'][tooltipItem['index']] + ' ' + _get_data.dataUnit;
}
},
backgroundColor: '#1c2b46',
titleFontSize: 13,
titleFontColor: '#fff',
titleMarginBottom: 6,
bodyFontColor: '#fff',
bodyFontSize: 12,
bodySpacing: 4,
yPadding: 10,
xPadding: 10,
footerMarginTop: 0,
displayColors: false
}
}
});
});
} // init chart
NioApp.coms.docReady.push(function () {
ecommerceDoughnutS1();
});
}(NioApp, jQuery);
</script>

View File

@ -0,0 +1,44 @@
@include('partials.dashboard.head')
@include('partials.dashboard.sidebar', ['page' => 'statistics'])
@include('partials.dashboard.header')
<!-- content @s -->
<div class="nk-content ">
<div class="container-fluid">
<div class="nk-content-inner">
<div class="nk-content-body">
<div class="components-preview wide-md mx-auto">
<div class="nk-block-head nk-block-head-lg wide-sm">
<div class="nk-block-head-content">
<h2 class="nk-block-title fw-normal">{{$title}}</h2>
<div class="nk-block-des">
<p class="lead">Temukan informasi dan ringkasan data penting yang disajikan secara terstruktur untuk kemudahan pemantauan dan analisis.</p>
</div>
</div>
</div><!-- .nk-block-head -->
<div class="nk-block nk-block-lg">
<div class="row g-gs">
@foreach ($statistics as $statistic)
<div class="col-lg-6">
<a href="{{route('dashboard.statistics.show', ['category' => $statistic['category']])}}" class="card text-soft">
<div class="card-inner">
<div class="align-center justify-between">
<div class="g">
<h6 class="title {{$statistic['is_available'] ? '' : 'not-available-text'}}">{{$statistic['name']}}</h6>
</div>
<div class="g">
<span class="btn btn-icon btn-trigger me-n1"><em class="icon ni ni-chevron-right"></em></span>
</div>
</div>
</div>
</a>
</div><!-- .col -->
@endforeach
</div><!-- .row -->
</div><!-- .nk-block -->
</div><!-- .components-preview -->
</div>
</div>
</div>
</div>
<!-- content @e -->
@include('partials.dashboard.footer', ['rich_editor' => false])

View File

@ -0,0 +1,252 @@
@include('partials.dashboard.head')
@include('partials.dashboard.sidebar', ['page' => 'statistics'])
@include('partials.dashboard.header')
<!-- content @s -->
<div class="nk-content ">
<div class="container-fluid">
<div class="nk-content-inner">
<div class="nk-content-body">
<div class="nk-block-head nk-block-head-sm">
<div class="nk-block-between">
<div class="nk-block-head-content">
<h3 class="nk-block-title page-title">{{$title}}</h3>
</div><!-- .nk-block-head-content -->
{{-- {{dd($cooperationRequests)}} --}}
<div class="nk-block-head-content">
<div class="toggle-wrap nk-block-tools-toggle">
<a href="#" class="btn btn-icon btn-trigger toggle-expand me-n1" data-target="pageMenu"><em class="icon ni ni-more-v"></em></a>
<div class="toggle-expand-content" data-content="pageMenu">
<ul class="nk-block-tools g-3">
<li>
<div>
<a href="{{route('dashboard.statistics.index')}}" class="btn btn-white btn-dim btn-outline-light"><em class="icon ni ni-arrow-left"></em><span class="d-none d-md-inline">Kembali</a>
</div>
</li>
<li>
@if (isset($year) && filled($year))
<span class="mx-1">
<a href="{{route('dashboard.statistics.show', ['category' => $category])}}" class="text-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-xbox-x"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 2c5.523 0 10 4.477 10 10s-4.477 10 -10 10s-10 -4.477 -10 -10s4.477 -10 10 -10m3.6 5.2a1 1 0 0 0 -1.4 .2l-2.2 2.933l-2.2 -2.933a1 1 0 1 0 -1.6 1.2l2.55 3.4l-2.55 3.4a1 1 0 1 0 1.6 1.2l2.2 -2.933l2.2 2.933a1 1 0 0 0 1.6 -1.2l-2.55 -3.4l2.55 -3.4a1 1 0 0 0 -.2 -1.4" /></svg>
</a>
</span>
@endif
<div>
<a href="javascript: void(0);" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalFilter"><em class="d-none d-sm-inline icon ni ni-filter"></em><span><span class="d-none d-md-inline">Filter</a>
</div>
</li>
</ul>
</div>
</div>
</div><!-- .nk-block-head-content -->
</div><!-- .nk-block-between -->
</div><!-- .nk-block-head -->
<div class="nk-block">
<div class="row g-gs">
@if (is_role(['1']))
<div class="col-xxl-3 col-md-6">
<div class="card card-full overflow-hidden">
<div class="nk-ecwg nk-ecwg7 h-100">
<div class="card-inner flex-grow-1">
<div class="card-title-group mb-4">
<div class="card-title">
<h6 class="title">Kanal Monitoring Media</h6>
</div>
</div>
<div class="nk-ecwg7-ck">
<canvas class="ecommerce-doughnut-s1" id="mediaMonitoringStatistics"></canvas>
</div>
<ul class="nk-ecwg7-legends">
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#1877F2"></span>
<span>Facebook {{ '('.$facebookMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#1DA1F2"></span>
<span>Twitter {{ '('.$twitterMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#28A745"></span>
<span>Website {{ '('.$websiteMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#FF0000"></span>
<span>YouTube {{ '('.$youtubeMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#E4405F"></span>
<span>Instagram {{ '('.$instagramMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#00F2EA"></span>
<span>TikTok {{ '('.$tiktokMediaMonitoring.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#333333"></span>
<span>Cetak {{ '('.$cetakMediaMonitoring.')' }}</span>
</div>
</li>
</ul>
</div><!-- .card-inner -->
</div>
</div><!-- .card -->
</div>
<div class="col-xxl-3 col-md-6">
<div class="card card-full overflow-hidden">
<div class="nk-ecwg nk-ecwg7 h-100">
<div class="card-inner flex-grow-1">
<div class="card-title-group mb-4">
<div class="card-title">
<h6 class="title">Isu</h6>
</div>
</div>
<div class="nk-ecwg7-ck">
<canvas class="ecommerce-doughnut-s1" id="issueStatistics"></canvas>
</div>
<ul class="nk-ecwg7-legends">
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#FE4F2D"></span>
<span>Krisis {{ '('.$crisisIssue.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#E50046"></span>
<span>Negatif {{ '('.$negativeIssue.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#5CB338"></span>
<span>Netral {{ '('.$neutralIssue.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#3572EF"></span>
<span>Positif {{ '('.$positiveIssue.')' }}</span>
</div>
</li>
</ul>
</div><!-- .card-inner -->
</div>
</div><!-- .card -->
</div><!-- .col -->
<div class="col-xxl-3 col-md-6">
<div class="card card-full overflow-hidden">
<div class="nk-ecwg nk-ecwg7 h-100">
<div class="card-inner flex-grow-1">
<div class="card-title-group mb-4">
<div class="card-title">
<h6 class="title">Status Monitoring Media</h6>
</div>
</div>
<div class="nk-ecwg7-ck">
<canvas class="ecommerce-doughnut-s1" id="mediaMonitoringIssuesStatus"></canvas>
</div>
<ul class="nk-ecwg7-legends">
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#FE4F2D"></span>
<span>Belum Memiliki Isu {{ '('.$mediaMonitoringWithoutIssueCount.')' }}</span>
</div>
</li>
<li>
<div class="title">
<span class="dot dot-lg sq" data-bg="#3572EF"></span>
<span>Sudah Memiliki Isu {{ '('.$mediaMonitoringWithIssueCount.')' }}</span>
</div>
</li>
</ul>
</div><!-- .card-inner -->
</div>
</div><!-- .card -->
</div><!-- .col -->
@endif
<div class="col-xxl-3 col-md-12">
<div class="card card-full overflow-hidden">
<div class="nk-ecwg nk-ecwg7 h-100">
<div class="card-inner flex-grow-1">
<div class="card-title-group mb-4">
<div class="card-title">
<h6 class="title">Statistik Monitoring Media dan Manajemen Isu</h6>
</div>
</div>
<div class="nk-ck">
<canvas class="bar-chart" id="barChartMultiple"></canvas>
</div>
</div><!-- .card-inner -->
</div>
</div><!-- .card -->
</div><!-- .col -->
<div class="modal fade" id="modalFilter">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Filter</h5>
<a href="javascript:void(0);" class="close" data-bs-dismiss="modal" aria-label="Close">
<em class="icon ni ni-cross"></em>
</a>
</div>
<form action="{{route('dashboard.statistics.show', ['category' => $category])}}" class="form-validate is-alter" method="get">
<div class="modal-body">
<div class="form-group">
<label class="form-label" for="year">Tahun</label>
<div class="form-control-wrap">
<input type="number" class="form-control" id="year" placeholder="Contoh: 2025" name="year" value="{{ old('year', $year ?? '') }}">
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label class="form-label" for="from_month">Dari Bulan</label>
<div class="form-control-wrap">
<input type="month" class="form-control" id="from_month" placeholder="Data berita pada bulan dan tahun" name="from_month" value="{{ old('from_month', $from_month ?? '') }}">
</div>
</div>
<div class="form-group col-md-6">
<label class="form-label" for="to_month">Sampai Bulan</label>
<div class="form-control-wrap">
<input type="month" class="form-control" id="to_month" placeholder="Data berita pada bulan dan tahun" name="to_month" value="{{ old('to_month', $to_month ?? '') }}">
</div>
</div>
</div>
</div>
<div class="modal-footer bg-light">
<span class="sub-text">
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
</span>
</div>
</form>
</div>
</div>
</div>
{{-- <div class="col-xxl-3 col-md-12">
<div class="card card-bordered card-preview">
<div class="card-inner">
<div class="nk-ck">
<canvas class="bar-chart" id="barChartMultiple"></canvas>
</div>
</div>
</div><!-- .card-preview -->
</div><!-- .col --> --}}
</div><!-- .row -->
</div><!-- .nk-block -->
</div>
</div>
</div>
</div>
<!-- content @e -->
@include('partials.dashboard.footer', ['statistic_chart' => 'media-monitoring'])

View File

@ -265,6 +265,17 @@ function statusAction(url, message, confirmButtonAction) {
</script>
@endif
@if (session('waiting-status'))
<script>
Swal.fire({
icon: 'info',
title: 'Informasi',
text: 'Fitur belum tersedia.',
confirmButtonText: 'OK'
});
</script>
@endif
<script>
$('#submitButton').click(function(e) {
e.preventDefault();

View File

@ -93,11 +93,11 @@
@include('partials.app.overview-statistics')
@include('dashboard.media-monitorings.statistics.media-monitoring-statistics')
@if(is_role(['1']))
@include('partials.app.calendars.admin')
@elseif (is_role(['3']))
@include('partials.app.calendars.media')
@endif
@if(is_role(['1']))
@include('partials.app.calendars.admin')
@elseif (is_role(['3']))
@include('partials.app.calendars.media')
@endif
@endif
@if (isset($rich_editor))
@ -106,6 +106,20 @@
<script src="{{asset('assets/dashboard/js/editors.js?ver=3.0.3')}}"></script>
@endif
@if (isset($statistic_chart))
@switch($statistic_chart)
@case('media-monitoring')
@include('dashboard.statistics.chart.media-monitoring-issue-management')
@include('dashboard.media-monitorings.statistics.media-monitoring-statistics')
@break
@case(2)
@break
@default
@endswitch
@endif
<script>
$(document).ready(function() {

View File

@ -65,6 +65,12 @@
<span class="nk-menu-text">Pengumuman</span>
</a>
</li><!-- .nk-menu-item -->
<li class="nk-menu-item">
<a href="{{route('dashboard.statistics.index')}}" class="nk-menu-link {{$page === 'statistics' ? 'active-page' : ''}}">
<span class="nk-menu-icon"><em class="icon ni ni-pie-alt"></em></span>
<span class="nk-menu-text">Statistik</span>
</a>
</li><!-- .nk-menu-item -->
@endif
@if (is_role('1'))
<li class="nk-menu-heading">

View File

@ -26,6 +26,7 @@
use App\Http\Controllers\Dashboard\ReportController;
use App\Http\Controllers\Dashboard\RoleController;
use App\Http\Controllers\Dashboard\SettingController;
use App\Http\Controllers\Dashboard\StatisticController;
use App\Http\Controllers\Dashboard\SubClassificationController;
use App\Http\Controllers\Dashboard\SubLocationController;
use App\Http\Controllers\Dashboard\UserController;
@ -222,6 +223,16 @@
});
});
Route::middleware('role:1')->group(function(){
Route::prefix('statistics')->name('statistics.')->group(function(){
Route::controller(StatisticController::class)->group(function(){
Route::get('/', 'index')->name('index');
Route::get('/{category}', 'show')->name('show');
});
});
});
Route::middleware('role:1')->group(function(){
Route::prefix('settings')->name('settings.')->group(function(){