How to check UUID on PHP
Hi there!
So, if you need to check the UUID string you just need to use the next regular expression:
preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/', $string);
That’s it!
Hi there!
So, if you need to check the UUID string you just need to use the next regular expression:
preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/', $string);
That’s it!
Hello,
Recently, I had a problem with making some structure for storing a drag’n’drop state of an element. The best way that came to my mind was making a mixtype structure of arrays and objects. For example, I had an array with the following structure:
{ "docs": [ { "minimize": false, "docs": [ { "minimize": true } ] }, { "minimize": false, "docs": [ { "minimize": true } ] } ] }
So, I needed to get the last nested element of that object by the path like — docs_0_docs_0 . And also, after getting the nested element, I needed to set the value back to the element. The function with the implementation of setting data is below:
function set_data_to_object(object, path, data, type = 'object') { const isNumeric = (string) => /^[+-]?\d+(\.\d+)?$/.test(string) if (typeof (path) == 'string') { path = path.split('_'); } if (typeof (object) !== 'object' || Object.keys(object).length == 0) { object = type === 'object' ? {} : []; } const element = path[0]; if (path.length == 1) { object[element] = data; } else { if (isNumeric(element)) { object[element] = set_data_to_object(object[element], path.slice(1), data, 'object'); } else { object[element] = set_data_to_object(object[element], path.slice(1), data, 'array'); } } return object; }
The first argument of the function is an object. The object can be empty empty like — {}; in this case the parent elements will be made corresponding to the path.
The second argument is the path, as I mentioned above it should be like — docs_0_docs_0 . Where the underscore symbol is delimiter symbol.
The third argument is the data that you want to the object.
And finally, the function will return the changed object with the set data.
For getting data from the object, I wrote another function:
function get_data_from_object(object, path) { if (typeof (path) == 'string') { path = path.split('_'); } const element = path[0]; if (path.length == 1) { return object[element]; } else { return get_data_from_object(object[element], path.slice(1)); } }
The first argument of the function is the object that contains the structure like I described above.
The second argument is the path like — docs_0_docs_0.
I hope, it can be helpful for somebody.
If you have problem with cutting decimal point from input with type number, you can just define KeyDown event on the input element:
var input_element = document.getElementById('number-input'); input_element.addEventListener('keydown',function(event) { if(event.keyCode == '190') { event.preventDefault(); } });
That’s it!
Hello
I have run into a problem when I tried to add submodule into my project that is controlled by GIT. I got an error:
% git submodule add /submodule /project/submodule fatal: transport 'file' not allowed fatal: clone of '/submodule' into submodule path '/project/submodule' failed
The solution of this error is setting the global value always for file protocol in GIT like this:
git config --global protocol.file.allow always
That’s it!
The most important thing in programming languages is data types. Each language has many types of data like boolean, integer, float, character, string, array, records, lists, tuples, unions, etc. Some of them are primitive data types, and others are complex. The primitive types play a central role in all languages; on the contrary, the complex data types don’t have a realization in some languages. A data type also means predefined operations that can be performed for it. For example, for the integer type, you can use the simple arithmetical operations like addition, subtraction, multiplication, and division; for the string data type available operations are like concatenation, union, subtraction, etc.; for the complex data type include objects, arrays, etc. Thus, many specific operations that can be different from one to another which depending on a language.
The program may be written by using any data type, but the relevant type is determined by the ease with which the results of the program can be performed. It other words, the data type must be bounded to the objects that in the real-world problem being addressed. The right chosen data type facilitates further support and modifies a program. In the modern world, when all around us changes frequently, it is especially important to have the ability to change a program in the appropriate way. Also, a computer program it is only the paradigm of a data manipulation, so in this meaning, the data is a structure that can be manipulated by the operations with data types. Thus, by matching the real problem with the right tool, the result may bring profit and solve the problem. On the contrary, an inappropriate data type may be the cause that freezes or slows down the program. In a negative scenario, using the wrong data type can lead to losing the data.
Lost data and errors are the most common problems in programming. On the design stage sometimes mistakes are allowed, so when the real users try to use a program, they can run into a problem. For instance, imagine some application where users need to fill numeric data into a field, and they can write a decimal number into the field, but the handler of that field accepts only a real or an integer data type, then the error is very expected. The way the program will behave, in this case, depends on the type of typing in the programming language. There are two typing classifications: the first is strong, and the second is weak. Based on the example above, if the application had used the strong typing, then the program would have been interrupted by an error like a segmentation fault. But, if the weak typing had been used, then the program would have lasted, but the user was perplexed and confused when his entered number like – 1.4 transformed into something like 1. It means the entered number was converted implicitly, or it may be named type coercion. However, an error wouldn’t have occurred, if a programming language had strong typing, and the type casting was used in the application.
In that case, the decimal number – 1.4 would be explicitly converted into 1 without any errors. The reason why in a programming language that has strong typing is needed to make the type casting to prevent the errors is the static typing. Overall, there are another two types of classification of the languages: static and dynamic. In the static type, each variable has its own type of data. It means that a certain range or a certain size of memory is allocated for this variable. So, when the program is running, and the variable is assigned with a value with a different data type that requires more memory, then the error of segmentation data occurs. In other words, the CPU tries to write the data to the address that lies outrange of the allocated memory and may corrupt another programs data in the nearby memory blocks. To prevent the corruption of the data, the error occurs. But if the type casting is used, the “oversized” value will be cast to the variable type. And the situation is the same as it would be implicit conversion. In the languages with the dynamic types, the conversation happens implicitly, but the variable can change its own type to the type of the value. The dynamically typed languages also may not have explicit typing; thus, in the source code, there are no variables with data types, and the code execution program converts them in the appropriate way based on the values types they are assigned to.
Honestly, this is only my point of view. There are many people with the different views who can disagree with me, because there are no clear rules to determining what the terms above are meant. They don’t exist because each language is used every day by a sheer number of people in different conditions to solve various tasks or problems, and most importantly, they are evolving every day.
Hello there
Recently, I have run into the problem that I couldn’t swipe the slides with YouTube embedded clips in the Slick gallery. Instead of swiping, nothing was happening. In other words, when I tried to touch and swipe the slide to the left or the right on a mobile device, the slide and the slider didn’t react in any way. Nevertheless, when I just touched the YouTube embedded clip, it just started playing normaly. I tried to play with the settings of the Slick slider, and then I concluded that it was impossible to fix it that way.
I searched for the solution, and I didn’t find anything that could help me. So, I thought that it would be a very interesting task to solve.
First of all, as I understood, the problem was in the embedded objects that caught the focus of the main window. When a user tried to swipe and touch the slide, the touch event didn’t pass to the window context, and the Slick slider handler couldn’t receive the data of the event. An empty div tag, stretched above the embedded object, could resolve this problem, but in that case the user would not be able to start a Youtube clip. When the user would have tried to touch the play button, he would touch the empty div tag, not the Youtube embedded object.
After a couple of hours of googling, I found the solution. YouTube provides the API for their embedded clips, and you can control almost everything in the embedded object. You can programmatically change the volume, the timecode, the state – play/stop, etc. By the link, you can find the description of this API.
Secondly, I joint the idea of an empty div tag and the ability to control an embedded object programmatically with JavaScript. It means when the user touches the empty div tag, you can programmatically handle the event, and based on the state of the YouTube embedded clip you can start to play or stop playing the clip. So, I have made a simple example with the solution.
1. You need to make a simple markup, like this:
<div class="video-review-slick-slider"> <div class="slide"> <div class="gap" data-action-type="play" data-target-id="video1"></div> <div class="player-init" id="video1" data-yt-id="f9O3yURTBCM"></div> </div> <div class="slide"> <div class="gap" data-action-type="play" data-target-id="video2"></div> <div class="player-init" id="video2" data-yt-id="nhm8aal5F1c"></div> </div> <div class="slide"> <div class="gap" data-action-type="play" data-target-id="video3"></div> <div class="player-init" id="video3" data-yt-id="JkI2wJQ5YcM"></div> </div> <div class="slide"> <div class="gap" data-action-type="play" data-target-id="video4"></div> <div class="player-init" id="video4" data-yt-id="ZA4lISqqUXU"></div> </div> <div class="slide"> <div class="gap" data-action-type="play" data-target-id="video5"></div> <div class="player-init" id="video5" data-yt-id="NIjMeUDurrk"></div> </div> </div>
The div tag with class video-review-slick-slider is a root container for the slider. It contains the slides with divs. The first of these divs is a gap or an empty div tag. This div has attributes – data-action-type that has the state of the embedded YouTube object. Also, this div has data-target-id that holds the id of the second div that used to make a YouTube embedded object. The second div has attributes like id and data-yt-id, which means the id for data-target-id of the previous div and the id of the YouTube video clip.
2. Next step, you need to initialize the YouTube API as it specified in the documentation:
var tag = document.createElement('script'); tag.id = 'iframe-demo'; tag.src = 'https://www.youtube.com/iframe_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
3. After that, you need to write a simple function that contains logic with the initialization of the YouTube embedded clips and attaches the handle for the empty div tag with that class gap. The function is below.
var players = {}; function init_players() { $('.player-init').each(function() { if(!$(this).data('initialized')) { let player_cont_id = $(this).attr('id'); let yt_video_id = $(this).data('yt-id'); if(player_cont_id && yt_video_id) { players[player_cont_id] = new YT.Player(player_cont_id, { videoId: yt_video_id, height: '380', width: '100%' }); } else { if(player_cont_id == '') { player_cont_id = 'video_'+Math.random(999,9999); $(this).attr('id',player_cont_id); $(this).prev().data('target-id',player_cont_id); players[player_cont_id] = new YT.Player(player_cont_id, { videoId: yt_video_id, height: '380', width: '100%' }); } } $(this).data('initialized',true); } }); $('.video-review-slick-slider .slide .gap').off('click.video'); $('.video-review-slick-slider .slide .gap').on('click.video',function() { var target_id = $(this).data('target-id'); var action_type = $(this).data('action-type'); if(typeof(players[target_id]) == 'object') { if(action_type == 'play') { players[target_id].playVideo(); $(this).data('action-type','pause'); } if(action_type == 'pause') { players[target_id].pauseVideo(); $(this).data('action-type','play'); } } }); }
In this function:
4. Having defined the main function for the YouTube objects, it’s time to define the function that will be called when the YouTube API is loaded on the page. The function name is onYouTubeIframeAPIReady, and it is described in the documentation to the API.
function onYouTubeIframeAPIReady() { init_players(); }
5. The final step is writing the definition for the Slick slider initialization.
$('.video-review-slick-slider').slick({ slidesToShow: 1, slidesToScroll: 1, dots: false, arrows:true, centerMode: false, swipe: true, focusOnSelect: true, centerPadding: '0px', adaptiveHeight: false, responsive: [{ breakpoint: 768, settings: { arrows: false, centerMode: true, centerPadding: '40px', slidesToShow: 1, dots: true } }, { breakpoint: 480, settings: { arrows: false, centerMode: true, centerPadding: '40px', slidesToShow: 1, dots: true } } ] });
6. But in one row with the scripts, it is needed to add css styles for the slides and the gap elements. They are below:
.video-review-slick-slider .slide { position: relative; } .video-review-slick-slider .slide iframe { position: relative; z-index: 2; padding: 0 10px; margin: 0 10px; max-width: 95%; } .video-review-slick-slider .slide .gap { position: absolute; top: 50px; left: 0px; width: 100%; height: 65%; z-index: 10; }
In the style definition for the gap element there are important properties like height and top. In this case, they allow the user to use the control elements of the YouTube embedded objects like – play button, pause button, settings button, volume bar, timecode bar, etc.; because the gap element provides only the play or stop functionality.
7. But when you run this code on your page, you will notice that the YouTube videos do not stop playing after a swiping gesture. It means there will be a lot of YouTube clips playing simultaneously. To prevent this behaviour, you can just add a simple handler to the swipe event of the Slick slider before its initialization; the function handler is below:
$('.video-review-slick-slider').on('swipe', function(event, slick, direction) { $('.video-review-slick-slider .gap').data('action-type','play'); for(object in players) { let player = players[object]; player.pauseVideo(); } });
In this handler, after a swiping gesture all the YouTube clips are stopped.
The working example of this solution is available by the link.
Since the Gutenberg editor has been added to WordPress and started using as the default content editor, many developers and ordinary users still prefer the old editor.
In order to turn off the new editor and get the old one, you will need to add a few rows of code into your function.php:
add_filter('use_block_editor_for_post', '__return_false', 10); add_filter('use_block_editor_for_post_type', '__return_false', 10);
Also, in the newer versions of WordPress, the Gutenberg editor is turned on for the widget dashboard. As the editor for the content, the Gutenberg widget editor is not habitual for the regular users. Fortunately, you can turn off it in the same way, so you need merely add a few lines of code to your function.php:
add_filter( 'gutenberg_use_widgets_block_editor', '__return_false', 10); add_filter( 'use_widgets_block_editor', '__return_false', 10);
After these changes in your function.php, you will get the old interface of the content editor for posts and the old interface to manage widgets.
Hello everyone!
Many nowadays developers are using different ways of communication between front end (client web browser) and back end (server).
One of these ways is GraphQL schema language. Using GraphQL, a developer can easily transfer data between the front end and the back end. Also you can quickly change rules or create a new one to modify structure of data. In GraphQL the rules are called – Schema. Schema consists of: Objects, Fields, Data types, etc. Also there are three types of communication with the server: Query, Mutation, Subscribe. These types describes schema of fields and types and each schema provides its principle to transfer data.
Along with this GraphQL has a different implementation in different programming languages with the same abilities. In other words, GraphQL is a schema language that is implemented in a programming language as a service. Each programming language, for instance: PHP, JavaScript, Java, Python, Ruby, etc., has a side-developed library to work with GraphQL schema. It isn’t builtin a module/library and it isn’t a part of any programming language.
That being said, GraphQL has many different implementations and below I am describing an implementation for PHP language and the library is called: webonyx/graphql-php by creating a simple Query schema. It is a quick way to create simple schema and use it to receive data from the server and then use it in your client scripts.
Being written on PHP language this library can be installed into your scripts with the Composer package manager. As described on the GitHub page of the library, you can just run the next command:
composer require webonyx/graphql-php
Also, to parse input requests to the scripts you need to install the laminas-diactoros library by the next command:
composer require laminas/laminas-diactoros
After finishing these commands the library will be able to use it in your project by including the file autoload.php in your script like this:
require_once('vendor/autoload.php');
To begin using the libary and creating a simple Query scheme, it is required to define the classes of the library that will be used to process the Query Scheme:
use GraphQL\GraphQL; use GraphQL\Type\Schema; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; use GraphQL\Server\StandardServer; use GraphQL\Upload\UploadMiddleware; use Laminas\Diactoros\ServerRequestFactory; use GraphQL\Server\ServerConfig;
Recently I ran into a problem implementing a filter for flats for one of my clients, on his real estate website, and below I will try to describe a simple way to quickly create an elementary schema for a filter like that. So, after defining the classes used for creating a schema, let’s start describing a simple object for the flats Query:
$flats_item = new ObjectType([ 'name' => 'FlatItem', 'fields' => [ 'id' => Type::int(), 'floor' => Type::int(), 'num' => Type::int(), 'price' => Type::int(), 'area_total' => Type::int(), 'complex' => Type::string() ] ]); $flats_items = new ObjectType([ 'name' => 'FlatsItems', 'fields' => [ 'items' => Type::listof($flats_item) ] ]); $flats = [ 'type' => $flats_items, 'args' => [ 'price_min' => Type::int(), 'price_max' => Type::int(), ], 'resolve' => function($rootValue, $args) { // some code to make query answer } ];
The code above describes the structure of flats. Each flat has a few parameters such as id, floor (floor number), num (flat number), price, etc. The next variables($flats_items) contains a list of the flat items. Finally in the $flats variable the type of the query is defined, which is assigned by $flats_items variable and arguments that the schema can receive in the resolve function.
After defining the flats schema, you need to add into Schema Query:
$query = new ObjectType([ 'name' => 'Query', 'fields' => [ 'flats' => $flats, ] ]); $schema = new Schema([ 'query' => $query, ]);
The assinging of the flats schema to the Schema Query is above, which means you need to create a new ObjectType in $query variable and then assign this variable to the Schema object.
Having done these several actions let’s move on to writing a code for using the Schema defined above.
$server_config = ServerConfig::create() ->setSchema($schema); $request = ServerRequestFactory::fromGlobals(); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $request = $request->withParsedBody($input); $server = new StandardServer($server_config); $result = $server->executePsrRequest($request); $server->getHelper()->sendResponse($result);
In the lines above you need to create an instance of ServerConfig class and assign the Query Schema. Then, you will need to create a request instance using the class ServerRequestFactory from the laminas-diactoros library. After that, you need to pass the data from the input to the request, the data sent from the client to the server. Finally,
you will need to create a server instance, which will be using the ServerConfig instance, and a request instance to output the request’s response using method – sendResponse.
At the same time the response to your request may contain errors. But not all errors will appear in the response, only the errors about the Query Schema will. Other errors don’t add to the response. You need to do additional actions to get these errors, so if your purpose is to debug your code you need to add these lines after the server response code:
$debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE; $output = $result->toArray($debug); file_put_contents('/path/to/file',json_encode($output));
This code is converting all debug data to an array and saving it into the file in the JSON format.
In the code above, in the schema definition, there is a resolve function as an associated element of the array. Now to test our script that provides the response with the data of the flats on the filter request, you need to define the test data inside this function. The input arguments for the schema were price_min and price_max; these arguments also are called the fields in the request that you can send to the server. For example, let’s define a four flats in an array with the fields corresponding to our defined schema.
<?php $flats = [ [ 'id' => 1, 'floor' => 2, 'num' => 3, 'price' => 100, 'area_total' => 10, 'complex' => 'Complex 1' ], [ 'id' => 2, 'floor' => 2, 'num' => 3, 'price' => 200, 'area_total' => 10, 'complex' => 'Complex 2' ], [ 'id' => 3, 'floor' => 2, 'num' => 3, 'price' => 300, 'area_total' => 10, 'complex' => 'Complex 3' ], [ 'id' => 3, 'floor' => 2, 'num' => 3, 'price' => 400, 'area_total' => 10, 'complex' => 'Complex 1' ], ];
All in all, by writing the array of data for the flats, you need to write a simple function of filtering this data based on filter arguments – price_min or price_max. This code can be written like this:
return ['items' => array_filter($flats,function($flat) use ($args) { if($flat['price']>$args['price_min']) return true; else return false; })];
The code uses the anonymous function in the context of PHP builtin function array_filter. The anonymous function gets each element of the flats array and the request data in the $args variable. Inside the function there is a check that is comparing the price field of each element with the filter argument – price_min and then if the price is greater than the filter argument, the flat passes to the finall array of the items for the response.
To illustrate, the query may be like this:
query flats { flats(price_min: 200) { items { id floor price } } }
and the response will be like this:
{ "data": { "flats": { "items": [ { "id": 3, "floor": 2, "price": 300 }, { "id": 3, "floor": 2, "price": 400 } ] } } }
It means when you pass the variable/field in the request – price_min with the value – 200, you will receive the response only with two flats of the four because they are correspond to the filter argument and the others don’t.
Also, in the request I use only three fields – id, floor and price, but in the Query Schema there are a few more. You can easily add them into the query and receive new information in the response. For example:
query flats { flats(price_min: 200) { items { id floor price complex } } }
After that, all flats will have a new field – complex with the information from the server that you have defined earlier.
{ "data": { "flats": { "items": [ { "id": 3, "floor": 2, "price": 300, "complex": "Complex 3" }, { "id": 3, "floor": 2, "price": 400, "complex": "Complex 1" } ] } } }
The code of this script you can get on the Gist.
Full review about GraphQL type system you can read on this page.
Almost all web developers run into the problem of implementation of a disclosure widget. In the HTML5 standard implementation that is supported by all modern browsers there is a special HTML tag that allows you to create a disclosure widget. The tag is:
<details>
Using this tag you can create disclosure widget without writing any code on JavaScript. Below is an HTML markup:
<details> <summary>Widget title</summary> <p>Widget content</p> </details>
The result of this code is rendered below:
Widget content
On clicking the label – the Widget title or the black triangle, the widget expands and collapses. When the widget is expanded the widget content becomes visible. On clicking the label again, the content becomes hidden. It means you can toggle the state of the widget.
The detail tag has a special attribute of its state called – open. When the widget is open the details tag is having the attribute open which can have a boolean value – true or empty value.
Otherwise when the widget is closed the open attribute can have a boolean value – false or the attribute may be removed.
But on the object level the attribute – open always exists and has a boolean value. In a markup the attribute may be ommited.
This simple widget will work in every modern browser excluding Internet Explorer and Edge.
Also the widget appearance can be changed by CSS styles. For example the black triangle can be replaced with plus and minus signs depending on the state of the widget. The widget title can be decorated with a grey gradient background. CSS styles are below:
details.style1 { margin-bottom: 10px; } details.style1 > summary::-webkit-details-marker { display:none; } details.style1 > summary { position: relative; cursor: pointer; background: linear-gradient(#dbdbdb,#898989); display: inline-block; padding: 5px; padding-left: 25px; border-radius: 5px; outline: none; width: 100%; text-align: center; } details.style1 > summary:hover { background: linear-gradient(#bbbbbb,#737373); } details.style1 > summary::after { display: block; position:absolute; content: '+'; font-size: 20px; font-weight: bold; top: 0px; left: 5px; } details.style1[open] > summary::after { content: '-'; }
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
First widget has the open attribute and the widget is rendered in the expanded state. All these widgets have been created totally without JavaScript.
Nevertheless sometimes you need to check the state of the widget and do some actions depending on its state. For example when a user attempts to change the state of the widget by clicking on it, the others widgets must collapse. It can be implemented only with JavaScript, the code is below:
window.onload = function() { var details = document.getElementsByClassName('collapsed'); for (var i = 0; i < details.length; i++) { var element = details[i]; element.addEventListener("toggle", function(event) { if (this.open) { for (let i = 0; i < details.length; i++) { let element = details[i]; if (element !== this) { element.open = false; } } } }); } }
The JavaScript code above begins working when a page is fully loaded. Then all the detail tags with collapsed class are chosen and we start the loop with these elements. Inside the loop for each element we set up a function that will be called whenever the specified event is fired. In our case the event will be fired when a user is clicking on the widget title and the event has name toggle. In the function we are checking the current object with each object from the details variable inside a loop too. If current object isn’t equal to the object from the details variable then we set the open attribute of this object to a boolean value – false.
Thus the all the widgets that exclude a clicked widget will be collapsed and the clicked widget will be expanded. The examples are below:
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
In conclusion, I think it is a fast and a simple way to create disclosure widgets without coding and loading third party libraries like jQuery, etc. But you should keep in mind that this solution isn’t working in Internet Explorer and Edge.
Hello everyone!
If you are trying to install new MySQL instance and want to connect to this instance through SSH tunnel with GUI software like Sequel Pro or MySQL Workbench then you can’t help meeting with the error: MySQL said: Access denied for user ‘root’@’localhost’ . Especially if you are installing a Percona MySQL Server.
It occurs because MySQL resolves address localhost as 127.0.0.1 and by default in mysql.user table exits a record for localhost users only. But in case if you create a new user for 127.0.0.1 and try to connect through SSH you can get the same error. You can solve these errors with simple action, just put this single line in your my.cnf in [mysqld] section:
[mysqld] skip-name-resolve = 1