What would be best approach to work with two hashes of arrays in this scenario? - perl-data-structures

What would be the best approach to process these two hashes of arrays? The 1st data set contains xml data and 2nd is from csv file, the idea is to check if the filename from 2nd dataset is in the first one and if so, calculate the delay in file delivery. Im not sure how to best produce the workable hash that i can work with (or change existing ones to have filenames as their keys or maybe somehow merge these together), any feedback would be greatly appreciated
dataset 1 (xml data):
$VAR1 = [
{
'StartTimestamp' => 1478146371,
'EndTimestamp' => 1478149167,
'FileName' => 'a3_file_20161024.req',
'Stage' => 'SentUserResponse'
},
{
'StartTimestamp' => 1478146375,
'EndTimestamp' => 1478149907,
'FileName' => 'a2_file_20161024.req',
'Stage' => 'SentUserResponse'
},
{
'StartTimestamp' => 1478161030,
'EndTimestamp' => 1478161234,
'FileName' => 'file_DEX_0.req',
'Stage' => 'SentUserResponse'
},
Data Set 2 from csv file:
$VAR1 = [
{
'FileName' => 'a3_file_20161024.req',
'ExpectedTime' => '20:04:07'
},
{
'FileName' => 'a2_file_20161024.req',
'ExpectedTime' => '20:14:39'
},
{
'FileName' => 'file_DEX_0.req',
'ExpectedTime' => '20:48:40'
},
code used:
sub Demo {
my $api_ref = GetData($apicall);
my $csvdata = ReadDataFile();
print Dumper($api_ref);
print "-------------------------*********--------------************------------------\n";
print Dumper ($csvdata);
print "#####################\n";
}
sub ReadDataFile {
my $parser = Text::CSV::Simple->new;
$parser->field_map(qw/FileName ExpectedTime/);
my #csv_data = $parser->read_file($datafile);
return \#csv_data;
}
sub GetData {
my ($xml) = #_;
my #api_data;
my %request;
my $t = XML::Twig->new(
twig_handlers => {
'//UserRequest' => sub {
push #api_data, {%request} if %request;
%request = ();
$_->purge; # free memory
},
'//UserRequest/HomeFileName' => sub {
$request{FileName} = $_->trimmed_text;
},
'//UserRequest/Stage' => sub {
$request{Stage} = $_->trimmed_text;
},
'//UserRequest/StartTimestamp' => sub {
$request{StartTimestamp} = str2time(substr($_->trimmed_text, -8));
},
'//UserRequest/EndTimestamp' => sub {
$request{EndTimestamp} = str2time(substr($_->trimmed_text, -8));
},
},
);
$t->xparse($xml);
$t->purge;
return \#api_data;
}

I am assuming, that you can map the elements of the first array to the elements of the second array by comparing by the filename and that relation is an 1:1 relation, I would perform the following steps:
Sort the lists by filename or generate a index hash
Combine both sets into a single array of hashs or use the index to process through your data set
Do whatever you need to do with the data sets
Just a litte example:
#!/usr/bin/env perl
use strict;
use warnings;
my $api_ref = [
{
'StartTimestamp' => 1478146371,
'EndTimestamp' => 1478149167,
'FileName' => 'a3_file_20161024.req',
'Stage' => 'SentUserResponse'
},
{
'StartTimestamp' => 1478146375,
'EndTimestamp' => 1478149907,
'FileName' => 'a2_file_20161024.req',
'Stage' => 'SentUserResponse'
},
{
'StartTimestamp' => 1478161030,
'EndTimestamp' => 1478161234,
'FileName' => 'file_DEX_0.req',
'Stage' => 'SentUserResponse'
}
];
my $csvdata = [
{
'FileName' => 'a3_file_20161024.req',
'ExpectedTime' => '20:04:07'
},
{
'FileName' => 'a2_file_20161024.req',
'ExpectedTime' => '20:14:39'
},
{
'FileName' => 'file_DEX_0.req',
'ExpectedTime' => '20:48:40'
}
];
# generate the index
my %index = ();
for ( my $i = 0 ; $i < #{$api_ref} ; $i++ ) {
$index{ $api_ref->[$i]{FileName} }{api_idx} = $i;
}
for ( my $i = 0 ; $i < #{$csvdata} ; $i++ ) {
$index{ $csvdata->[$i]{FileName} }{csv_idx} = $i;
}
# filter for elements not present in both data sets
my #filename_intersection =
grep { exists $index{$_}{api_idx} && exists $index{$_}{csv_idx} }
( keys %index );
foreach my $filename (#filename_intersection) {
# do something with
my $api_entry = $api_ref->[ $index{$filename}{api_idx} ];
my $csv_entry = $csvdata->[ $index{$filename}{csv_idx} ];
# example convert ExpectedTime into seconds and compare it to Start/End time difference
$csv_entry->{ExpectedTime} =~ /^(\d{2}):(\d{2}):(\d{2})$/;
my $exp_sec = ( $1 * 60 + $2 ) * 60 + $3;
my $real_sec = $api_entry->{EndTimestamp} - $api_entry->{StartTimestamp};
my $msg = "";
if ( $exp_sec >= $real_sec ) {
$msg = "in time:";
}
else {
$msg = "late:";
}
printf
"Filename %s was %s; expected time: %d seconds, real time: %d seconds\n",
$filename, $msg, $exp_sec, $real_sec;
}
Best,
Frank

Related

Error when I try to create index in elastic search from logstash

Hi Im getting the following error when I try to create index in ElasticSearch from logstash:
[Converge PipelineAction::Create] agent - Failed to execute action
{:action=>LogStash::PipelineAction::Create/pipeline_id:main,
:exception=>"LogStash::ConfigurationError", :message=>"Expected one of #, input, filter, output at
line 1, column 1 (byte 1)"
Can you tell me if I got something wrong in my .conf file
iput {
file {
path => "/opt/sis-host/process/uptime_test*"
# start_position => "beginning"
ignore_older => 0
}
}*emphasized text*
filter {
grok {
match => { "message" => "%{DATA:hora} %{DATA:fecha} %{DATA:status} %{DATA:server} %
{INT:segundos}" }
}
date {
match => ["horayfecha", "HH:mm:ss MM/dd/YYYY" ]
target => "#timestamp"
}
}
output {
elasticsearch {
hosts => ["host:9200"]
index => "uptime_test-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
The configuration file should start with input and not "iput"
input { # not iput
file {
path => "/opt/sis-host/process/uptime_test*"
# start_position => "beginning"
ignore_older => 0
}
}
filter {
grok {
match => { "message" => "%{DATA:hora} %{DATA:fecha} %{DATA:status} %{DATA:server} %
{INT:segundos}" }
}
date {
match => ["horayfecha", "HH:mm:ss MM/dd/YYYY" ]
target => "#timestamp"
}
}
output {
elasticsearch {
hosts => ["host:9200"]
index => "uptime_test-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}

Yii2 : Upload Image using Kartik/FileInput Plugin

I want to upload an image via Kartik widget. After submitting the form, the $_FILE['Product'] has the data about the image but getInstance($model, 'images') returns null. Tried with images[], also null.
This is what I'm trying to var_dump in the controller:
public function actionCreate()
{
$model = new Product();
if ($model->load(Yii::$app->request->post())) {
var_dump(UploadedFile::getInstance($model, 'images[]'));die;
And this is my model Product:
<?php
namespace app\models;
use backend\models\CActiveRecord;
use Yii;
use omgdef\multilingual\MultilingualQuery;
use omgdef\multilingual\MultilingualBehavior;
use yii\web\UploadedFile;
/**
* This is the model class for table "product".
*
* #property int $id
* #property int $category_id
* #property int $quantity
* #property double $price
* #property int $sort
*
* #property Productlang[] $productlangs
*/
class Product extends CActiveRecord
{
public $images;
public static function find()
{
return new MultilingualQuery(get_called_class());
}
public function behaviors()
{
$allLanguages = [];
foreach (Yii::$app->params['languages'] as $title => $language) {
$allLanguages[$title] = $language;
}
return [
'ml' => [
'class' => MultilingualBehavior::className(),
'languages' => $allLanguages,
//'languageField' => 'language',
//'localizedPrefix' => '',
//'requireTranslations' => false',
//'dynamicLangClass' => true',
//'langClassName' => PostLang::className(), // or namespace/for/a/class/PostLang
'defaultLanguage' => Yii::$app->params['languageDefault'],
'langForeignKey' => 'product_id',
'tableName' => "{{%productLang}}",
'attributes' => [
'title',
'description',
'meta_title',
'meta_desc',
'url'
]
],
];
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'product';
}
/**
* #inheritdoc
*/
public function rules()
{
$string = $this->multilingualFields(['description', 'url']);
$string_59 = $this->multilingualFields(['meta_title']);
$string_255 = $this->multilingualFields(['meta_desc', 'title']);
$string[] = 'description';
$string[] = 'url';
$string_59[] = 'meta_title';
$string_255[] = 'meta_desc';
$string_255[] = 'title';
return [
[['quantity', 'price', 'title', 'meta_title', 'meta_desc'], 'required'],
[['category_id', 'quantity', 'sort'], 'integer'],
[$string, 'string'],
[$string_59, 'string', 'max' => 59],
[$string_255, 'string', 'max' => 255],
[['price'], 'number'],
['images', 'file']
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'category_id' => 'Category ID',
'quantity' => 'Quantity',
'price' => 'Price',
'sort' => 'Sort',
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->image as $file) {
$file->saveAs(\Yii::getAlias("#images") . "/products/" . $this->id . "_" . $this->image->baseName . '.' . $this->image->extension);
}
return true;
} else {
return false;
}
}
}
Tried with rules ['images', 'safe'] also ['images', 'file'] ( think the second one is not right because the attribute is an array, right ? ). The form is <?php $form = ActiveForm::begin(['options' => ['multipart/form-data']]); ?>.
Finally my input:
<?= $form->field($model, 'images[]')->widget(FileInput::class, [
'showMessage' => true,
]) ?>
Full controller action:
public function actionCreate()
{
$model = new Product();
if ($model->load(Yii::$app->request->post())) {
foreach (Yii::$app->params['languages'] as $language){
if(Yii::$app->params['languageDefault'] != $language){
$title_lang = "title_$language";
$model->$title_lang = Yii::$app->request->post('Product')["title_$language"];
$description_lang = "description_$language";
$model->$description_lang = Yii::$app->request->post('Product')["description_$language"];
$meta_title_lang = "meta_title_$language";
$model->$meta_title_lang = Yii::$app->request->post('Product')["meta_title_$language"];
$meta_desc_lang = "meta_desc_$language";
$model->$meta_desc_lang = Yii::$app->request->post('Product')["meta_desc_$language"];
}
}
if($model->save()){
$model = $this->findModel($model->id, true);
//Make urls
foreach (Yii::$app->params['languages'] as $language) {
if (Yii::$app->params['languageDefault'] != $language) {
$url_lang = "url_$language";
$title_lang = "title_$language";
$model->$url_lang = $model->constructURL(
$model->$title_lang,
$model->id
);
}else{
$model->url = $model->constructURL(
$model->title,
$model->id
);
}
}
//Upload Images
$model->images = UploadedFile::getInstance($model, 'images');
if (!($model->upload())) {
Yii::$app->session->setFlash('error', Yii::t('app', 'Some problem with the image uploading occure!'));
return $this->redirect(['create']);
}
if($model->update() !== false){
return $this->redirect(['view', 'id' => $model->id]);
}else{
Yii::$app->session->setFlash('error', Yii::t('app', 'Something went wrong. Please, try again later!'));
return $this->redirect(['create']);
}
}
}
return $this->render('create', [
'model' => $model,
]);
}
What looks like you are trying to upload a single image you should remove the [] from the input field name from the ActiveForm field declaration, and from models rules.
Single File
<?= $form->field($model, 'images')->widget(FileInput::class, [
'showMessage' => true,
'pluginOptions' => [
'showCaption' => false ,
'showRemove' => false ,
'showUpload' => false ,
'showPreview' => false ,
'browseClass' => 'btn btn-success btn-block' ,
'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
'browseLabel' => 'Select Profile Image'
] ,
'options' => ['accept' => 'image/*' ] ,
]) ?>
and from the following line
UploadedFile::getInstance($model, 'images');
Multiple Files
For multiple files you need to add 'options' => ['multiple' => true] for the field and change the attribute name to images[]
<?= $form->field($model, 'images[]')->widget(FileInput::class, [
'showMessage' => true,
'pluginOptions' => [
'showCaption' => false ,
'showRemove' => false ,
'showUpload' => false ,
'showPreview' => false ,
'browseClass' => 'btn btn-success btn-block' ,
'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
'browseLabel' => 'Select Profile Image'
] ,
'options' => ['accept' => 'image/*' ,'multiple'=>true] ,
]) ?>
and for receiving the uploaded files you should not specify the attribute as an array just change getInstance to getInstances and then try printing, it will show you all the images use foreach() to save all of them.
UploadedFile::getInstances($model, 'images');
I personally prefer to use a separate model for file uploading rather than using the ActiveRecord model.
Note: When using multiple files upload, you can also specify the 'maxFiles'=>1000 inside you model rules to limit the number of files to be uploaded
EDIT
For troubleshooting your code you should comment out the actionCreate from the controller and replace with the one i added below
public function actionCreate() {
$model = new Product();
if ( $model->load ( Yii::$app->request->post () ) ) {
foreach ( Yii::$app->params['languages'] as $language ) {
if ( Yii::$app->params['languageDefault'] != $language ) {
$title_lang = "title_$language";
$model->$title_lang = Yii::$app->request->post ( 'Product' )["title_$language"];
$description_lang = "description_$language";
$model->$description_lang = Yii::$app->request->post ( 'Product' )["description_$language"];
$meta_title_lang = "meta_title_$language";
$model->$meta_title_lang = Yii::$app->request->post ( 'Product' )["meta_title_$language"];
$meta_desc_lang = "meta_desc_$language";
$model->$meta_desc_lang = Yii::$app->request->post ( 'Product' )["meta_desc_$language"];
}
}
$transaction = Yii::$app->db->beginTransaction ();
try {
if ( !$model->save () ) {
throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $model->errors , 0 , false ) ) );
}
//Make urls
foreach ( Yii::$app->params['languages'] as $language ) {
if ( Yii::$app->params['languageDefault'] != $language ) {
$url_lang = "url_$language";
$title_lang = "title_$language";
$model->$url_lang = $model->constructURL (
$model->$title_lang , $model->id
);
} else {
$model->url = $model->constructURL (
$model->title , $model->id
);
}
}
//save the new urls
if ( !$model->save () ) {
throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $model->errors , 0 , false ) ) );
}
//Upload Images
$model->images = UploadedFile::getInstances ( $model , 'images' );
$model->upload ();
//commit the transatction to save the record in the table
$transaction->commit ();
Yii::$app->session->setFlash ( 'success' , 'The model saved successfully.' );
return $this->redirect ( [ 'view' , 'id' => $model->id ] );
} catch ( \Exception $ex ) {
$transaction->rollBack ();
Yii::$app->session->setFlash ( 'error' , Yii::t ( 'app' , $ex->getMessage () ) );
}
}
return $this->render ( 'create' , [
'model' => $model ,
] );
}
And comment out the upload() function of your model and add below function
public function upload() {
$skipped = [];
foreach ( $this->images as $file ) {
if ( !$file->saveAs ( \Yii::getAlias ( "#images" ) . "/products/" . $this->id . "_" . $this->image->baseName . '.' . $this->image->extension ) ) {
$skipped[] = "File " . $file->baseName . " was not saved.";
}
}
if ( !empty ( $skipped ) ) {
Yii::$app->session->setFlash ( 'error' , implode ( "<br>" , $skipped ) );
}
}
And for the ActiveForm make sure your input matches the following
$form->field($model, 'images[]')->widget(FileInput::class, [
'showMessage' => true,
'pluginOptions' => [
'showCaption' => false ,
'showRemove' => false ,
'showUpload' => false ,
'showPreview' => false ,
'browseClass' => 'btn btn-success btn-block' ,
'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
'browseLabel' => 'Select Profile Image'
] ,
'options' => ['accept' => 'image/*','multiple'=>true ] ,
]) ;

Variables in logstash config not substituted

None of the variables in prefix are substituted - why?
It was working with on old version of logstash (1.5.4) but doesn't anymore with 2.3.
Part of the output filter in logstash.cfg (dumps to s3):
output {
if [bucket] == "bucket1" {
s3 {
bucket => "bucket1"
access_key_id => "****"
secret_access_key => "****"
region => "ap-southeast-2"
prefix => "%{env}/%{year}/%{month}/%{day}/"
size_file => 50000000 #50mb
time_file => 1
codec => json_lines # save log as json line (no newlines)
temporary_directory => "/var/log/temp-logstash"
tags => ["bucket1"]
}
}
..
}
Example dataset (taken from stdout):
{
"random_person" => "Kenneth Cumming 2016-04-14 00:53:59.777647",
"#timestamp" => "2016-04-14T00:53:59.917Z",
"host" => "192.168.99.1",
"year" => "2016",
"month" => "04",
"day" => "14",
"env" => "dev",
"bucket" => "bucket1"
}
Just in case, here is the filter:
filter {
mutate {
add_field => {
"request_uri" => "%{[headers][request_path]}"
}
}
grok {
break_on_match => false # default behaviour is to stop matching after first match, we don't want that
match => { "#timestamp" => "%{NOTSPACE:date}T%{NOTSPACE:time}Z"} # break timestamp field into date and time
match => { "date" => "%{INT:year}-%{INT:month}-%{INT:day}"} # break date into year month and day fields
match => { "request_uri" => "/%{WORD:env}/%{NOTSPACE:bucket}"} # break request uri into environment and bucket fields
}
mutate {
remove_field => ["request_uri", "headers", "#version", "date", "time"]
}
}
It's a known issue that field variables aren't allowed in 'prefix'.

How to implement kartik yii2 FileInput in form Update while using different models

I have followed this solution in working with multiple models to upload using files using kartik fileinput during actionCreate.
My problem is achieving the same during actionUpdate, I keep on receiving the error below:
Either 'name', or 'model' and 'attribute' properties must be specified.
My form view is as follows:
echo $form->field($document,'document[]')->widget(FileInput::classname(), [
'options' => ['multiple' => true],
'pluginOptions' => [
// 'previewFileType' => 'any',
'showPreview' => false,
'showUpload' => false
], ]);
Whereas my controller actionUpdate is as follows
public function actionUpdate($id)
{
//$document = new EmployeeDocuments();
$model = $this->findModel($id);
$document = EmployeeDocuments::find()->indexBy('employee_id')->all();
$empavatar=$model->avatar;
$oldavatar=Yii::$app->session['oldavatar'] = $empavatar;
if ($model->load(Yii::$app->request->post()) ) {
// print_r($model); exit;
// $attachments = UploadedFile::getInstances($document, 'document');
// print_r($attachments); exit;
if($model->avatar==""){
$model->avatar=$oldavatar;
}
if ($model->save()){
if(!empty($attachments)){
foreach($attachments as $attachment):
$ext = end((explode(".", $attachment)));
$filename=end((explode(">", $attachment)));
$filename = ucwords(substr($filename, 0, strpos($filename, '.')));
// generate a unique file name
$file2save = Yii::$app->security->generateRandomString().".{$ext}";
$path=Yii::getAlias('#loc').'/uploads/employees/docs/'; //set directory path to save image
$attachment->saveAs($path.$model->id."_".$file2save); //saving img in folder
$attachment = $model->id."_".$file2save; //appending id to image name
\Yii::$app->db->createCommand()
->insert('lcm_hrm_employee_documents', ['document' => $attachment, 'name'=>$filename,'employee_id'=>$model->id])
->execute(); //manually update image name to db /* */
endforeach;
}
return $this->redirect(['view', 'id' => $model->id]);
}
else {
return $this->render('update', [
'model' => $model, 'document'=>$document
]);
}
} else {
return $this->render('update', [
'model' => $model, 'document'=>$document
]);
}
}
Change your form view to
echo $form->field($document,'document[]')->widget(FileInput::classname(), [
'options' => ['multiple' => true],
'attribute' =>'document[]',
'pluginOptions' => [
// 'previewFileType' => 'any',
'showPreview' => false,
'showUpload' => false
], ]);

How to specify Schema for Lists while mapping Nhibernate by code

I want my "tag_post" table to be created in "article" schema but it's created in "public" schema.
List(x => x.Tags, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});
I have never used mapping by code, but i assume this is the solution:
List(x => x.Students, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
l.Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});